From 954d1c239c7c0e20e5d4eda937860430d94e827e Mon Sep 17 00:00:00 2001
From: tanghy <tanghy.fnst@fujitsu.com>
Date: Wed, 24 Nov 2021 13:12:05 +0800
Subject: [PATCH] Disallow DROP NOT NULL on a column in the REPLICA IDENTITY
 index

Disallow DROP NOT NULL on a column if it's in a REPLICA IDENTITY index.

Author: Haiying Tang, Hou Zhijie
Reviewed-by: Hou Zhijie
---
 src/backend/commands/tablecmds.c               | 15 ++++++++++-----
 src/test/regress/expected/replica_identity.out |  6 ++++++
 src/test/regress/sql/replica_identity.sql      |  6 ++++++
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 785b282..4c24ff1 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7164,19 +7164,24 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
 			elog(ERROR, "cache lookup failed for index %u", indexoid);
 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 
-		/* If the index is not a primary key, skip the check */
-		if (indexStruct->indisprimary)
+		/*
+		 * If the index is not a primary key or REPLICA IDENTITY index, skip
+		 * the check
+		 */
+		if (indexStruct->indisprimary || indexStruct->indisreplident)
 		{
 			/*
-			 * Loop over each attribute in the primary key and see if it
-			 * matches the to-be-altered attribute
+			 * Loop over each attribute in the primary key or REPLICA IDENTITY
+			 * index and see if it matches the to-be-altered attribute
 			 */
 			for (i = 0; i < indexStruct->indnkeyatts; i++)
 			{
 				if (indexStruct->indkey.values[i] == attnum)
 					ereport(ERROR,
 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-							 errmsg("column \"%s\" is in a primary key",
+							 errmsg(ngettext("column \"%s\" is in a primary key",
+											 "column \"%s\" is in a REPLICA IDENTITY index",
+											 indexStruct->indisprimary),
 									colName)));
 			}
 		}
diff --git a/src/test/regress/expected/replica_identity.out b/src/test/regress/expected/replica_identity.out
index 7900219..8bbf52f 100644
--- a/src/test/regress/expected/replica_identity.out
+++ b/src/test/regress/expected/replica_identity.out
@@ -223,6 +223,12 @@ ALTER TABLE test_replica_identity3 ALTER COLUMN id TYPE bigint;
 Indexes:
     "test_replica_identity3_id_key" UNIQUE, btree (id) REPLICA IDENTITY
 
+---
+-- Test that ALTER TABLE DROP NOT NULL is not allowed for the columns in
+-- replica identity index
+---
+ALTER TABLE test_replica_identity3 ALTER COLUMN id DROP NOT NULL;
+ERROR:  column "id" is in a REPLICA IDENTITY index
 DROP TABLE test_replica_identity;
 DROP TABLE test_replica_identity2;
 DROP TABLE test_replica_identity3;
diff --git a/src/test/regress/sql/replica_identity.sql b/src/test/regress/sql/replica_identity.sql
index a5ac8f5..9684af2 100644
--- a/src/test/regress/sql/replica_identity.sql
+++ b/src/test/regress/sql/replica_identity.sql
@@ -94,6 +94,12 @@ ALTER TABLE test_replica_identity3 REPLICA IDENTITY USING INDEX test_replica_ide
 ALTER TABLE test_replica_identity3 ALTER COLUMN id TYPE bigint;
 \d test_replica_identity3
 
+---
+-- Test that ALTER TABLE DROP NOT NULL is not allowed for the columns in
+-- replica identity index
+---
+ALTER TABLE test_replica_identity3 ALTER COLUMN id DROP NOT NULL;
+
 DROP TABLE test_replica_identity;
 DROP TABLE test_replica_identity2;
 DROP TABLE test_replica_identity3;
-- 
2.7.2.windows.1

