Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 885742b

Browse files
committed
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
1 parent 5bcbe98 commit 885742b

File tree

3 files changed

+73
-33
lines changed

3 files changed

+73
-33
lines changed

src/backend/commands/tablecmds.c

+30-33
Original file line numberDiff line numberDiff line change
@@ -21503,9 +21503,6 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
2150321503
ListCell *listptr;
2150421504
List *mergingPartitionsList = NIL;
2150521505
Oid defaultPartOid;
21506-
char tmpRelName[NAMEDATALEN];
21507-
RangeVar *mergePartName = cmd->name;
21508-
bool isSameName = false;
2150921506

2151021507
/*
2151121508
* Lock all merged partitions, check them and create list with partitions
@@ -21527,8 +21524,28 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
2152721524
* function transformPartitionCmdForMerge().
2152821525
*/
2152921526
if (equal(name, cmd->name))
21527+
{
2153021528
/* One new partition can have the same name as merged partition. */
21531-
isSameName = true;
21529+
char tmpRelName[NAMEDATALEN];
21530+
21531+
/* Generate temporary name. */
21532+
sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid);
21533+
21534+
/*
21535+
* Rename the existing partition with a temporary name, leaving it
21536+
* free for the new partition. We don't need to care about this
21537+
* in the future because we're going to eventually drop the
21538+
* existing partition anyway.
21539+
*/
21540+
RenameRelationInternal(RelationGetRelid(mergingPartition),
21541+
tmpRelName, false, false);
21542+
21543+
/*
21544+
* We must bump the command counter to make the new partition
21545+
* tuple visible for rename.
21546+
*/
21547+
CommandCounterIncrement();
21548+
}
2153221549

2153321550
/* Store a next merging partition into the list. */
2153421551
mergingPartitionsList = lappend(mergingPartitionsList,
@@ -21548,15 +21565,7 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
2154821565
DetachPartitionFinalize(rel, mergingPartition, false, defaultPartOid);
2154921566
}
2155021567

21551-
/* Create table for new partition, use partitioned table as model. */
21552-
if (isSameName)
21553-
{
21554-
/* Create partition table with generated temporary name. */
21555-
sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid);
21556-
mergePartName = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
21557-
tmpRelName, -1);
21558-
}
21559-
createPartitionTable(mergePartName,
21568+
createPartitionTable(cmd->name,
2156021569
makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
2156121570
RelationGetRelationName(rel), -1),
2156221571
context);
@@ -21567,18 +21576,12 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
2156721576
* excessive, but this is the way we make sure nobody is planning queries
2156821577
* involving merging partitions.
2156921578
*/
21570-
newPartRel = table_openrv(mergePartName, AccessExclusiveLock);
21579+
newPartRel = table_openrv(cmd->name, AccessExclusiveLock);
2157121580

2157221581
/* Copy data from merged partitions to new partition. */
2157321582
moveMergedTablesRows(rel, mergingPartitionsList, newPartRel);
2157421583

21575-
/*
21576-
* Attach a new partition to the partitioned table. wqueue = NULL:
21577-
* verification for each cloned constraint is not need.
21578-
*/
21579-
attachPartitionTable(NULL, rel, newPartRel, cmd->bound);
21580-
21581-
/* Unlock and drop merged partitions. */
21584+
/* Drop the current partitions before attaching the new one. */
2158221585
foreach(listptr, mergingPartitionsList)
2158321586
{
2158421587
ObjectAddress object;
@@ -21596,18 +21599,12 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
2159621599
}
2159721600
list_free(mergingPartitionsList);
2159821601

21599-
/* Rename new partition if it is needed. */
21600-
if (isSameName)
21601-
{
21602-
/*
21603-
* We must bump the command counter to make the new partition tuple
21604-
* visible for rename.
21605-
*/
21606-
CommandCounterIncrement();
21607-
/* Rename partition. */
21608-
RenameRelationInternal(RelationGetRelid(newPartRel),
21609-
cmd->name->relname, false, false);
21610-
}
21602+
/*
21603+
* Attach a new partition to the partitioned table. wqueue = NULL:
21604+
* verification for each cloned constraint is not needed.
21605+
*/
21606+
attachPartitionTable(NULL, rel, newPartRel, cmd->bound);
21607+
2161121608
/* Keep the lock until commit. */
2161221609
table_close(newPartRel, NoLock);
2161321610
}

src/test/regress/expected/partition_merge.out

+25
Original file line numberDiff line numberDiff line change
@@ -746,4 +746,29 @@ DROP TABLE t3;
746746
DROP TABLE t2;
747747
DROP TABLE t1;
748748
--
749+
-- Check the partition index name if the partition name is the same as one
750+
-- of the merged partitions.
751+
--
752+
CREATE TABLE t (i int, PRIMARY KEY(i)) PARTITION BY RANGE (i);
753+
CREATE TABLE tp_0_1 PARTITION OF t FOR VALUES FROM (0) TO (1);
754+
CREATE TABLE tp_1_2 PARTITION OF t FOR VALUES FROM (1) TO (2);
755+
CREATE INDEX tidx ON t(i);
756+
ALTER TABLE t MERGE PARTITIONS (tp_1_2, tp_0_1) INTO tp_1_2;
757+
-- Indexname values should be 'tp_1_2_pkey' and 'tp_1_2_i_idx'.
758+
-- Not-null constraint name should be 'tp_1_2_i_not_null'.
759+
\d+ tp_1_2
760+
Table "partitions_merge_schema.tp_1_2"
761+
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
762+
--------+---------+-----------+----------+---------+---------+--------------+-------------
763+
i | integer | | not null | | plain | |
764+
Partition of: t FOR VALUES FROM (0) TO (2)
765+
Partition constraint: ((i IS NOT NULL) AND (i >= 0) AND (i < 2))
766+
Indexes:
767+
"tp_1_2_pkey" PRIMARY KEY, btree (i)
768+
"tp_1_2_i_idx" btree (i)
769+
Not-null constraints:
770+
"tp_1_2_i_not_null" NOT NULL "i"
771+
772+
DROP TABLE t;
773+
--
749774
DROP SCHEMA partitions_merge_schema;

src/test/regress/sql/partition_merge.sql

+18
Original file line numberDiff line numberDiff line change
@@ -444,5 +444,23 @@ DROP TABLE t3;
444444
DROP TABLE t2;
445445
DROP TABLE t1;
446446

447+
--
448+
-- Check the partition index name if the partition name is the same as one
449+
-- of the merged partitions.
450+
--
451+
CREATE TABLE t (i int, PRIMARY KEY(i)) PARTITION BY RANGE (i);
452+
453+
CREATE TABLE tp_0_1 PARTITION OF t FOR VALUES FROM (0) TO (1);
454+
CREATE TABLE tp_1_2 PARTITION OF t FOR VALUES FROM (1) TO (2);
455+
456+
CREATE INDEX tidx ON t(i);
457+
ALTER TABLE t MERGE PARTITIONS (tp_1_2, tp_0_1) INTO tp_1_2;
458+
459+
-- Indexname values should be 'tp_1_2_pkey' and 'tp_1_2_i_idx'.
460+
-- Not-null constraint name should be 'tp_1_2_i_not_null'.
461+
\d+ tp_1_2
462+
463+
DROP TABLE t;
464+
447465
--
448466
DROP SCHEMA partitions_merge_schema;

0 commit comments

Comments
 (0)