agora inbox for pgsql-hackers@postgresql.org  
help / color / mirror / Atom feed
[PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
323+ messages / 2 participants
[nested] [flat]

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27 Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
  0 siblings, 0 replies; 323+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
them to hit the default case and error out with "unsupported object class".

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread

* [PATCH] change get_tables_to_repack_partitioned
@ 2026-07-09 14:55 Álvaro Herrera <alvherre@kurilemu.de>
  0 siblings, 0 replies; 323+ messages in thread

From: Álvaro Herrera @ 2026-07-09 14:55 UTC (permalink / raw)

---
 src/backend/commands/repack.c | 127 +++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a4..b3589ceff51 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde
 							MultiXactId *pCutoffMulti);
 static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
 								  MemoryContext permcxt);
-static List *get_tables_to_repack_partitioned(RepackCommand cmd,
-											  Oid relid, bool rel_is_index,
+static List *get_tables_to_repack_partitioned(RepackStmt *stmt,
+											  Relation rel,
 											  MemoryContext permcxt);
 static bool repack_is_permitted_for_relation(RepackCommand cmd,
 											 Oid relid, Oid userid);
@@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 	}
 	else
 	{
-		Oid			relid;
-		bool		rel_is_index;
-
-		Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * If USING INDEX was specified, resolve the index name now and pass
-		 * it down.
-		 */
-		if (stmt->usingindex)
-		{
-			/*
-			 * If no index name was specified when repacking a partitioned
-			 * table, punt for now.  Maybe we can improve this later.
-			 */
-			if (!stmt->indexname)
-			{
-				if (stmt->command == REPACK_COMMAND_CLUSTER)
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-							errmsg("there is no previously clustered index for table \"%s\"",
-								   RelationGetRelationName(rel)));
-				else
-					ereport(ERROR,
-							errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-					/*- translator: first %s is name of a SQL command, eg. REPACK */
-							errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
-								   RepackCommandAsString(stmt->command),
-								   RelationGetRelationName(rel)));
-			}
-
-			relid = determine_clustered_index(rel, stmt->usingindex,
-											  stmt->indexname);
-			if (!OidIsValid(relid))
-				elog(ERROR, "unable to determine index to cluster on");
-			check_index_is_clusterable(rel, relid, AccessExclusiveLock);
-
-			rel_is_index = true;
-		}
-		else
-		{
-			relid = RelationGetRelid(rel);
-			rel_is_index = false;
-		}
-
-		rtcs = get_tables_to_repack_partitioned(stmt->command,
-												relid, rel_is_index,
-												repack_context);
-
-		/* close parent relation, releasing lock on it */
-		table_close(rel, AccessExclusiveLock);
-		rel = NULL;
+		rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context);
+		rel = NULL;			/* clobber no longer valid pointer */
 	}
 
 	/* Commit to get out of starting transaction */
@@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
 }
 
 /*
- * Given a partitioned table or its index, return a list of RelToCluster for
- * all the leaf child tables/indexes.
+ * Resolve a partitioned table named as target of REPACK to the list of
+ * its partitions, and return it as a list of RelToCluster.
  *
- * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the
- * owning relation.
+ * The partitioned table in question was already opened and locked by caller
+ * and is given as argument; it is closed and unlocked here before return.
  */
 static List *
-get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
-								 bool rel_is_index, MemoryContext permcxt)
+get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel,
+								 MemoryContext permcxt)
 {
+	Oid			relid;
+	bool		rel_is_index;
 	List	   *inhoids;
 	List	   *rtcs = NIL;
 
+	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
+	/*
+	 * We find the list of tables by looking for inheritors.  If USING INDEX
+	 * was given, look for inheritors of that index, whose name we resolve now.
+	 *
+	 * Otherwise we look for inheritors of the table itself.
+	 */
+	if (stmt->usingindex)
+	{
+		/*
+		 * If no index name was specified when repacking a partitioned
+		 * table, punt for now.  Maybe we can improve this later.
+		 */
+		if (!stmt->indexname)
+		{
+			if (stmt->command == REPACK_COMMAND_CLUSTER)
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						errmsg("there is no previously clustered index for table \"%s\"",
+							   RelationGetRelationName(rel)));
+			else
+				ereport(ERROR,
+						errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						/*- translator: first %s is name of a SQL command, eg. REPACK */
+						errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
+							   RepackCommandAsString(stmt->command),
+							   RelationGetRelationName(rel)));
+		}
+
+		relid = determine_clustered_index(rel, stmt->usingindex,
+										  stmt->indexname);
+		if (!OidIsValid(relid))
+			elog(ERROR, "unable to determine index to cluster on");
+		check_index_is_clusterable(rel, relid, AccessExclusiveLock);
+
+		rel_is_index = true;
+	}
+	else
+	{
+		relid = RelationGetRelid(rel);
+		rel_is_index = false;
+	}
+
 	/*
 	 * Do not lock the children until they're processed.  Note that we do hold
 	 * a lock on the parent partitioned table.
@@ -2286,7 +2283,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 			if (get_rel_relkind(child_oid) != RELKIND_INDEX)
 				continue;
 
-			table_oid = IndexGetRelation(child_oid, false);
+			table_oid = IndexGetRelation(child_oid, true);
+			if (!OidIsValid(table_oid))
+				continue;
 			index_oid = child_oid;
 		}
 		else
@@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		 * leaf partition despite having them on the partitioned table.  Skip
 		 * if so.
 		 */
-		if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId()))
+		if (!repack_is_permitted_for_relation(stmt->command, table_oid,
+											  GetUserId()))
 			continue;
 
 		/* Use a permanent memory context for the result list */
@@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
 		MemoryContextSwitchTo(oldcxt);
 	}
 
+	/* close parent relation, releasing lock on it */
+	table_close(rel, AccessExclusiveLock);
+
 	return rtcs;
 }
 
-- 
2.47.3


--f4uihmgjmvhgvze3--





^ permalink  raw  reply  [nested|flat] 323+ messages in thread


end of thread, other threads:[~2026-07-09 14:55 UTC | newest]

Thread overview: 323+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>
2026-07-09 14:55 [PATCH] change get_tables_to_repack_partitioned Álvaro Herrera <alvherre@kurilemu.de>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox