From 83bdda1151055d943cc6318d9b792f2203df23dd 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 04/14] Attached partition inherits identity column

Identity column of a partitioned table should use the same value space.
Hence column which is identity column in partitioned table must be
identity column in all the partitions and share the same value space. A
table being attached as a partition inherits identity column. This
should be fine since we expect that the partition table's column has the
same type as the partitioned table's corresponding column.

TODO:

However this commit doesn't address one problem. An Identity column in
the partitioned table is also marked as NOT NULL. If that column in the
partition is not marked as NOT NULL, it should automatically get marked
as such. But this commit does not do so. The test has an ALTER TABLE
statement to mark the column in partition table as NOT NULL.

Ashutosh Bapat
---
 src/backend/commands/tablecmds.c       | 24 +++++++++++++++++-------
 src/test/regress/expected/identity.out | 19 +++++++++++++++++++
 src/test/regress/sql/identity.sql      | 12 ++++++++++++
 3 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3e3cd2ed75..b298747e13 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,
@@ -15643,7 +15645,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
@@ -15669,7 +15671,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;
@@ -15714,7 +15716,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);
@@ -15792,7 +15794,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;
@@ -15861,6 +15864,13 @@ 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)));
 
+			/*
+			 * A partition inherits identity column from the parent but not a
+			 * regular inheritance child.
+			 */
+			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.)
@@ -18692,7 +18702,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 eff73add59..6b9edb22c1 100644
--- a/src/test/regress/expected/identity.out
+++ b/src/test/regress/expected/identity.out
@@ -552,6 +552,25 @@ SELECT tableoid::regclass, f1, f2, f3 FROM itest_parted;
  itest_p1 | 07-03-2016 | from itest_p1     |  2
 (2 rows)
 
+-- attached partition inherits identity and shares the sequence.
+-- existing values in the table should not be affected
+CREATE TABLE itest_p2 (f1 date NOT NULL, f2 text, f3 bigint);
+-- TODO: ideally setting an identity column should automatically spawn the NOT NULL constraint. But it doesn't do that right now.
+ALTER TABLE itest_p2 ALTER COLUMN f3 SET NOT NULL;
+INSERT INTO itest_p2 VALUES ('2016-08-2', 'before attaching', 100);
+ALTER TABLE itest_parted ATTACH PARTITION itest_p2 FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
+INSERT INTO itest_p2 (f1, f2) VALUES ('2016-08-3', 'from itest_p2');
+INSERT INTO itest_parted (f1, f2) VALUES ('2016-08-4', 'from itest_parted');
+SELECT tableoid::regclass, f1, f2, f3 FROM itest_parted;
+ tableoid |     f1     |        f2         | f3  
+----------+------------+-------------------+-----
+ itest_p1 | 07-02-2016 | from itest_parted |   1
+ itest_p1 | 07-03-2016 | from itest_p1     |   2
+ itest_p2 | 08-02-2016 | before attaching  | 100
+ itest_p2 | 08-03-2016 | from itest_p2     |   3
+ itest_p2 | 08-04-2016 | from itest_parted |   4
+(5 rows)
+
 DROP TABLE itest_parted;
 -- 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 ad2a4249b9..a9babd1baa 100644
--- a/src/test/regress/sql/identity.sql
+++ b/src/test/regress/sql/identity.sql
@@ -339,6 +339,18 @@ CREATE TABLE itest_p1 PARTITION OF itest_parted FOR VALUES FROM ('2016-07-01') T
 INSERT into itest_parted(f1, f2) VALUES ('2016-07-2', 'from itest_parted');
 INSERT into itest_p1 (f1, f2) VALUES ('2016-07-3', 'from itest_p1');
 SELECT tableoid::regclass, f1, f2, f3 FROM itest_parted;
+
+-- attached partition inherits identity and shares the sequence.
+-- existing values in the table should not be affected
+CREATE TABLE itest_p2 (f1 date NOT NULL, f2 text, f3 bigint);
+-- TODO: ideally setting an identity column should automatically spawn the NOT NULL constraint. But it doesn't do that right now.
+ALTER TABLE itest_p2 ALTER COLUMN f3 SET NOT NULL;
+INSERT INTO itest_p2 VALUES ('2016-08-2', 'before attaching', 100);
+ALTER TABLE itest_parted ATTACH PARTITION itest_p2 FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
+INSERT INTO itest_p2 (f1, f2) VALUES ('2016-08-3', 'from itest_p2');
+INSERT INTO itest_parted (f1, f2) VALUES ('2016-08-4', 'from itest_parted');
+SELECT tableoid::regclass, f1, f2, f3 FROM itest_parted;
+
 DROP TABLE itest_parted;
 
 -- partition with identity column of its own is not allowed
-- 
2.25.1

