From 4d2dbe95f3c5267d7ddf7144329c5a98d95842f9 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Wed, 6 Dec 2023 16:08:59 +0530
Subject: [PATCH 05/27] Attached partition inherits identity column

A table being attached as a partition inherits identity property from
the partitioned table. This should be fine since we expect that the
partition table's column has the same type as the partitioned table's
corresponding column. If the table being attached is a partitioned
table, the indentity properties are propagated down its partition
hierarchy.

An Identity column in the partitioned table is also marked as NOT NULL.
The corresponding column in the partition needs to be marked as NOT NULL
for the attach to succeed.

Ashutosh Bapat
---
 src/backend/commands/tablecmds.c       | 25 ++++++++++++++++++-------
 src/test/regress/expected/identity.out | 23 ++++++++++++++++++-----
 src/test/regress/sql/identity.sql      |  9 +++++++++
 3 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 06f6301a57..5719df2b76 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -354,7 +354,8 @@ static List *MergeAttributes(List *columns, const List *supers, char relpersiste
 							 bool is_partition, List **supconstr,
 							 List **supnotnulls);
 static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr);
-static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
+static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel,
+										bool ispartition);
 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
 static void StoreCatalogInheritance(Oid relationId, List *supers,
 									bool child_is_partition);
@@ -618,7 +619,8 @@ static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partsp
 static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
 								  List **partexprs, Oid *partopclass, Oid *partcollation,
 								  PartitionStrategy strategy);
-static void CreateInheritance(Relation child_rel, Relation parent_rel);
+static void CreateInheritance(Relation child_rel, Relation parent_rel,
+							  bool ispartition);
 static void RemoveInheritance(Relation child_rel, Relation parent_rel,
 							  bool expect_detached);
 static void ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel,
@@ -15647,7 +15649,7 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 				 errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
 
 	/* OK to create inheritance */
-	CreateInheritance(child_rel, parent_rel);
+	CreateInheritance(child_rel, parent_rel, false);
 
 	/*
 	 * If parent_rel has a primary key, then child_rel has not-null
@@ -15673,7 +15675,7 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
  * Common to ATExecAddInherit() and ATExecAttachPartition().
  */
 static void
-CreateInheritance(Relation child_rel, Relation parent_rel)
+CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
 {
 	Relation	catalogRelation;
 	SysScanDesc scan;
@@ -15718,7 +15720,7 @@ CreateInheritance(Relation child_rel, Relation parent_rel)
 	systable_endscan(scan);
 
 	/* Match up the columns and bump attinhcount as needed */
-	MergeAttributesIntoExisting(child_rel, parent_rel);
+	MergeAttributesIntoExisting(child_rel, parent_rel, ispartition);
 
 	/* Match up the constraints and bump coninhcount as needed */
 	MergeConstraintsIntoExisting(child_rel, parent_rel);
@@ -15796,7 +15798,8 @@ constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
  * the child must be as well. Defaults are not compared, however.
  */
 static void
-MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
+MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel,
+							bool ispartition)
 {
 	Relation	attrrel;
 	TupleDesc	parent_desc;
@@ -15865,6 +15868,14 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
 						(errcode(ERRCODE_DATATYPE_MISMATCH),
 						 errmsg("column \"%s\" in child table must not be a generated column", parent_attname)));
 
+			/*
+			 * Regular inheritance children are independent enough not to
+			 * inherit identity columns. But partitions are integral part of a
+			 * partitioned table and inherit identity column.
+			 */
+			if (ispartition)
+				child_att->attidentity = parent_att->attidentity;
+
 			/*
 			 * OK, bump the child column's inheritance count.  (If we fail
 			 * later on, this change will just roll back.)
@@ -18696,7 +18707,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd,
 							  cmd->bound, pstate);
 
 	/* OK to create inheritance.  Rest of the checks performed there */
-	CreateInheritance(attachrel, rel);
+	CreateInheritance(attachrel, rel, true);
 
 	/* Update the pg_class entry. */
 	StorePartitionBound(attachrel, rel, cmd->bound);
diff --git a/src/test/regress/expected/identity.out b/src/test/regress/expected/identity.out
index 20803a1d24..222b3684da 100644
--- a/src/test/regress/expected/identity.out
+++ b/src/test/regress/expected/identity.out
@@ -542,15 +542,28 @@ DROP TYPE itest_type CASCADE;
 -- table partitions
 -- partitions inherit identity column and share sequence
 CREATE TABLE pitest1 (f1 date NOT NULL, f2 text, f3 bigint generated always as identity) PARTITION BY RANGE (f1);
+-- new partition
 CREATE TABLE pitest1_p1 PARTITION OF pitest1 FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');
 INSERT into pitest1(f1, f2) VALUES ('2016-07-2', 'from pitest1');
 INSERT into pitest1_p1 (f1, f2) VALUES ('2016-07-3', 'from pitest1_p1');
+-- attached partition
+CREATE TABLE pitest1_p2 (f1 date NOT NULL, f2 text, f3 bigint);
+INSERT INTO pitest1_p2 VALUES ('2016-08-2', 'before attaching', 100);
+ALTER TABLE pitest1 ATTACH PARTITION pitest1_p2 FOR VALUES FROM ('2016-08-01') TO ('2016-09-01'); -- requires NOT NULL constraint
+ERROR:  column "f3" in child table must be marked NOT NULL
+ALTER TABLE pitest1_p2 ALTER COLUMN f3 SET NOT NULL;
+ALTER TABLE pitest1 ATTACH PARTITION pitest1_p2 FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
+INSERT INTO pitest1_p2 (f1, f2) VALUES ('2016-08-3', 'from pitest1_p2');
+INSERT INTO pitest1 (f1, f2) VALUES ('2016-08-4', 'from pitest1');
 SELECT tableoid::regclass, f1, f2, f3 FROM pitest1;
-  tableoid  |     f1     |       f2        | f3 
-------------+------------+-----------------+----
- pitest1_p1 | 07-02-2016 | from pitest1    |  1
- pitest1_p1 | 07-03-2016 | from pitest1_p1 |  2
-(2 rows)
+  tableoid  |     f1     |        f2        | f3  
+------------+------------+------------------+-----
+ pitest1_p1 | 07-02-2016 | from pitest1     |   1
+ pitest1_p1 | 07-03-2016 | from pitest1_p1  |   2
+ pitest1_p2 | 08-02-2016 | before attaching | 100
+ pitest1_p2 | 08-03-2016 | from pitest1_p2  |   3
+ pitest1_p2 | 08-04-2016 | from pitest1     |   4
+(5 rows)
 
 -- 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);
diff --git a/src/test/regress/sql/identity.sql b/src/test/regress/sql/identity.sql
index 3660fa6a28..be29cbf119 100644
--- a/src/test/regress/sql/identity.sql
+++ b/src/test/regress/sql/identity.sql
@@ -335,9 +335,18 @@ DROP TYPE itest_type CASCADE;
 
 -- partitions inherit identity column and share sequence
 CREATE TABLE pitest1 (f1 date NOT NULL, f2 text, f3 bigint generated always as identity) PARTITION BY RANGE (f1);
+-- new partition
 CREATE TABLE pitest1_p1 PARTITION OF pitest1 FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');
 INSERT into pitest1(f1, f2) VALUES ('2016-07-2', 'from pitest1');
 INSERT into pitest1_p1 (f1, f2) VALUES ('2016-07-3', 'from pitest1_p1');
+-- attached partition
+CREATE TABLE pitest1_p2 (f1 date NOT NULL, f2 text, f3 bigint);
+INSERT INTO pitest1_p2 VALUES ('2016-08-2', 'before attaching', 100);
+ALTER TABLE pitest1 ATTACH PARTITION pitest1_p2 FOR VALUES FROM ('2016-08-01') TO ('2016-09-01'); -- requires NOT NULL constraint
+ALTER TABLE pitest1_p2 ALTER COLUMN f3 SET NOT NULL;
+ALTER TABLE pitest1 ATTACH PARTITION pitest1_p2 FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
+INSERT INTO pitest1_p2 (f1, f2) VALUES ('2016-08-3', 'from pitest1_p2');
+INSERT INTO pitest1 (f1, f2) VALUES ('2016-08-4', 'from pitest1');
 SELECT tableoid::regclass, f1, f2, f3 FROM pitest1;
 
 -- partition with identity column of its own is not allowed
-- 
2.25.1

