From 75df6d97a950859285cff2438fde882dfee43470 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Tue, 19 Dec 2023 11:38:48 +0530
Subject: [PATCH 13/14] Drop identity property when detaching partition

A partition's identity columns share the identity space and have same
identity property as the corresponding columns of the partitioned table.
If a partition is detached it can longer share the identity space as
before. Hence the identity columns of the partition being detached loose
their identity property. When identity of a column of a regular table is
dropped it retains the NOT NULL constarint that came with the identity
property. Similarly the columns of the partition being detached retain
the NOT NULL constraints that came with identity property, even though
the identity property itself is lost. Also note that the sequence
associated with the identity property is linked to the partitioned table
(and not the partition being detached). That sequence is not dropped as
part of detach operation.

Ashutosh Bapat
---
 src/backend/commands/tablecmds.c       | 13 ++++++++++++
 src/test/regress/expected/identity.out | 28 ++++++++++++++++++++++++++
 src/test/regress/sql/identity.sql      | 16 +++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 79af2f4e85..fc90db9c82 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -19442,6 +19442,7 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
 	HeapTuple	tuple,
 				newtuple;
 	Relation	trigrel = NULL;
+	int			attno;
 
 	if (concurrent)
 	{
@@ -19607,6 +19608,18 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
 	heap_freetuple(newtuple);
 	table_close(classRel, RowExclusiveLock);
 
+	/*
+	 * Drop identity property from all identity columns of partition.
+	 */
+	for (attno = 0; attno < RelationGetNumberOfAttributes(partRel); attno++)
+	{
+		Form_pg_attribute attr = TupleDescAttr(partRel->rd_att, attno);
+
+		if (!attr->attisdropped && attr->attidentity)
+			ATExecDropIdentity(partRel, NameStr(attr->attname), false,
+							   AccessExclusiveLock, true, true);
+	}
+
 	if (OidIsValid(defaultPartOid))
 	{
 		/*
diff --git a/src/test/regress/expected/identity.out b/src/test/regress/expected/identity.out
index cb783a3f6c..4f91af0ca0 100644
--- a/src/test/regress/expected/identity.out
+++ b/src/test/regress/expected/identity.out
@@ -647,6 +647,34 @@ SELECT tableoid::regclass, f1, f2, f3 FROM itest_parted;
 (4 rows)
 
 DROP TABLE itest_parted;
+-- detaching a partition removes identity property
+CREATE TABLE itest_parted (f1 date NOT NULL, f2 text, f3 int generated always as identity) PARTITION BY RANGE (f1);
+CREATE TABLE itest_p1 PARTITION OF itest_parted FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');
+CREATE TABLE itest_p2 PARTITION OF itest_parted FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
+INSERT into itest_parted VALUES ('2016-07-2', 'from itest_parted');
+INSERT into itest_parted VALUES ('2016-08-2', 'from itest_parted');
+ALTER TABLE itest_parted DETACH PARTITION itest_p1;
+INSERT into itest_parted(f1, f2) VALUES ('2016-08-4', 'from itest_parted');
+INSERT into itest_p1 (f1, f2) VALUES ('2016-07-5', 'from itest_p1'); -- error
+ERROR:  null value in column "f3" of relation "itest_p1" violates not-null constraint
+DETAIL:  Failing row contains (07-05-2016, from itest_p1, null).
+INSERT into itest_p1 (f1, f2, f3) VALUES ('2016-07-5', 'from itest_p1', 100);
+SELECT tableoid::regclass, f1, f2, f3 FROM itest_parted;
+ tableoid |     f1     |        f2         | f3 
+----------+------------+-------------------+----
+ itest_p2 | 08-02-2016 | from itest_parted |  2
+ itest_p2 | 08-04-2016 | from itest_parted |  3
+(2 rows)
+
+SELECT tableoid::regclass, f1, f2, f3 FROM itest_p1;
+ tableoid |     f1     |        f2         | f3  
+----------+------------+-------------------+-----
+ itest_p1 | 07-02-2016 | from itest_parted |   1
+ itest_p1 | 07-05-2016 | from itest_p1     | 100
+(2 rows)
+
+DROP TABLE itest_parted;
+DROP TABLE itest_p1;
 -- partition with identity column of its own is not allowed
 CREATE TABLE itest_parent (f1 date NOT NULL, f2 text, f3 bigint) PARTITION BY RANGE (f1);
 CREATE TABLE itest_child PARTITION OF itest_parent (
diff --git a/src/test/regress/sql/identity.sql b/src/test/regress/sql/identity.sql
index fa823c2a30..bcbba24032 100644
--- a/src/test/regress/sql/identity.sql
+++ b/src/test/regress/sql/identity.sql
@@ -401,6 +401,22 @@ SELECT tableoid::regclass, f1, f2, f3 FROM itest_parted;
 
 DROP TABLE itest_parted;
 
+-- detaching a partition removes identity property
+CREATE TABLE itest_parted (f1 date NOT NULL, f2 text, f3 int generated always as identity) PARTITION BY RANGE (f1);
+CREATE TABLE itest_p1 PARTITION OF itest_parted FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');
+CREATE TABLE itest_p2 PARTITION OF itest_parted FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
+INSERT into itest_parted VALUES ('2016-07-2', 'from itest_parted');
+INSERT into itest_parted VALUES ('2016-08-2', 'from itest_parted');
+ALTER TABLE itest_parted DETACH PARTITION itest_p1;
+INSERT into itest_parted(f1, f2) VALUES ('2016-08-4', 'from itest_parted');
+INSERT into itest_p1 (f1, f2) VALUES ('2016-07-5', 'from itest_p1'); -- error
+INSERT into itest_p1 (f1, f2, f3) VALUES ('2016-07-5', 'from itest_p1', 100);
+SELECT tableoid::regclass, f1, f2, f3 FROM itest_parted;
+SELECT tableoid::regclass, f1, f2, f3 FROM itest_p1;
+
+DROP TABLE itest_parted;
+DROP TABLE itest_p1;
+
 -- partition with identity column of its own is not allowed
 CREATE TABLE itest_parent (f1 date NOT NULL, f2 text, f3 bigint) PARTITION BY RANGE (f1);
 CREATE TABLE itest_child PARTITION OF itest_parent (
-- 
2.25.1

