From 885742b9f88b9386368ee94df8c94d154677ffba Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Tue, 30 Apr 2024 11:54:42 +0300 Subject: Change the way ATExecMergePartitions() handles the name collision The name collision happens when the name of the new partition is the same as the name of one of the merging partitions. Currently, ATExecMergePartitions() first gives the new partition a temporary name and then renames it when old partitions are deleted. That negatively influences the naming of related objects like indexes and constrains, which could inherit a temporary name. This commit changes the implementation in the following way. A merging partition gets renamed first, then the new partition is created with the right name immediately. This resolves the issue of the naming of related objects. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/edfbd846-dcc1-42d1-ac26-715691b687d3%40postgrespro.ru Author: Dmitry Koval, Alexander Korotkov Reviewed-by: Robert Haas, Justin Pryzby, Pavel Borisov --- src/backend/commands/tablecmds.c | 63 +++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 33 deletions(-) (limited to 'src/backend/commands/tablecmds.c') diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f1725c9da8c..8fa09afdc59 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -21503,9 +21503,6 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, ListCell *listptr; List *mergingPartitionsList = NIL; Oid defaultPartOid; - char tmpRelName[NAMEDATALEN]; - RangeVar *mergePartName = cmd->name; - bool isSameName = false; /* * Lock all merged partitions, check them and create list with partitions @@ -21527,8 +21524,28 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, * function transformPartitionCmdForMerge(). */ if (equal(name, cmd->name)) + { /* One new partition can have the same name as merged partition. */ - isSameName = true; + char tmpRelName[NAMEDATALEN]; + + /* Generate temporary name. */ + sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid); + + /* + * Rename the existing partition with a temporary name, leaving it + * free for the new partition. We don't need to care about this + * in the future because we're going to eventually drop the + * existing partition anyway. + */ + RenameRelationInternal(RelationGetRelid(mergingPartition), + tmpRelName, false, false); + + /* + * We must bump the command counter to make the new partition + * tuple visible for rename. + */ + CommandCounterIncrement(); + } /* Store a next merging partition into the list. */ mergingPartitionsList = lappend(mergingPartitionsList, @@ -21548,15 +21565,7 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, DetachPartitionFinalize(rel, mergingPartition, false, defaultPartOid); } - /* Create table for new partition, use partitioned table as model. */ - if (isSameName) - { - /* Create partition table with generated temporary name. */ - sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid); - mergePartName = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)), - tmpRelName, -1); - } - createPartitionTable(mergePartName, + createPartitionTable(cmd->name, makeRangeVar(get_namespace_name(RelationGetNamespace(rel)), RelationGetRelationName(rel), -1), context); @@ -21567,18 +21576,12 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, * excessive, but this is the way we make sure nobody is planning queries * involving merging partitions. */ - newPartRel = table_openrv(mergePartName, AccessExclusiveLock); + newPartRel = table_openrv(cmd->name, AccessExclusiveLock); /* Copy data from merged partitions to new partition. */ moveMergedTablesRows(rel, mergingPartitionsList, newPartRel); - /* - * Attach a new partition to the partitioned table. wqueue = NULL: - * verification for each cloned constraint is not need. - */ - attachPartitionTable(NULL, rel, newPartRel, cmd->bound); - - /* Unlock and drop merged partitions. */ + /* Drop the current partitions before attaching the new one. */ foreach(listptr, mergingPartitionsList) { ObjectAddress object; @@ -21596,18 +21599,12 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, } list_free(mergingPartitionsList); - /* Rename new partition if it is needed. */ - if (isSameName) - { - /* - * We must bump the command counter to make the new partition tuple - * visible for rename. - */ - CommandCounterIncrement(); - /* Rename partition. */ - RenameRelationInternal(RelationGetRelid(newPartRel), - cmd->name->relname, false, false); - } + /* + * Attach a new partition to the partitioned table. wqueue = NULL: + * verification for each cloned constraint is not needed. + */ + attachPartitionTable(NULL, rel, newPartRel, cmd->bound); + /* Keep the lock until commit. */ table_close(newPartRel, NoLock); } -- cgit v1.2.3