From 6239fc48eeaa43b02614ebd96582254d36b5053f Mon Sep 17 00:00:00 2001
From: "tender.wang" <tender.wang@openpie.com>
Date: Tue, 26 Mar 2024 19:33:53 +0800
Subject: [PATCH] Fix attnotnull not correct reset issue.

Since b0e96f3119, ALTER TABLE DROP NOT NULL will first check if
pg_constraint has related tuple. It will report error if the tuple
does not exist, but the pg_attribute attnotnull is true.

In some case, it will happend. So replacing report error, and just
update pg_attribute attnotnull to false.
---
 src/backend/commands/tablecmds.c          | 16 ++++++++++------
 src/test/regress/expected/constraints.out |  5 +++++
 src/test/regress/sql/constraints.sql      |  6 ++++++
 3 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 47c900445c..b2a4881373 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7524,9 +7524,7 @@ ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
 		Bitmapset  *pkcols;
 
 		/*
-		 * There's no not-null constraint, so throw an error.  If the column
-		 * is in a primary key, we can throw a specific error.  Otherwise,
-		 * this is unexpected.
+		 * If the column is in a primary key, we can throw a specific error.
 		 */
 		pkcols = RelationGetIndexAttrBitmap(rel, INDEX_ATTR_BITMAP_PRIMARY_KEY);
 		if (bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
@@ -7535,9 +7533,15 @@ ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
 					errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 					errmsg("column \"%s\" is in a primary key", colName));
 
-		/* this shouldn't happen */
-		elog(ERROR, "could not find not-null constraint on column \"%s\", relation \"%s\"",
-			 colName, RelationGetRelationName(rel));
+		/*
+		 * If a primary key includes two or more columns, one of the columns
+		 * was dropped, so the primary was dropped, too. But Others columns'
+		 * attnotnull is still true. So reset it here.
+		 */
+		attTup->attnotnull = false;
+		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
+		table_close(attr_rel, RowExclusiveLock);
+		return address;
 	}
 
 	readyRels = NIL;
diff --git a/src/test/regress/expected/constraints.out b/src/test/regress/expected/constraints.out
index b7de50ad6a..be6fe7cfbd 100644
--- a/src/test/regress/expected/constraints.out
+++ b/src/test/regress/expected/constraints.out
@@ -867,6 +867,11 @@ select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl
 (1 row)
 
 DROP TABLE notnull_tbl1;
+CREATE TABLE notnull_t1(c0 int, c1 int);
+ALTER TABLE  notnull_t1 ADD CONSTRAINT Q PRIMARY KEY(c0, c1);
+ALTER TABLE  notnull_t1 DROP c1;
+ALTER TABLE  notnull_t1  ALTER c0 DROP NOT NULL;
+DROP TABLE notnull_t1;
 -- nope
 CREATE TABLE notnull_tbl2 (a INTEGER CONSTRAINT blah NOT NULL, b INTEGER CONSTRAINT blah NOT NULL);
 ERROR:  constraint "blah" for relation "notnull_tbl2" already exists
diff --git a/src/test/regress/sql/constraints.sql b/src/test/regress/sql/constraints.sql
index 782699a437..2d4820152c 100644
--- a/src/test/regress/sql/constraints.sql
+++ b/src/test/regress/sql/constraints.sql
@@ -599,6 +599,12 @@ ALTER TABLE notnull_tbl1 ADD CONSTRAINT foobar NOT NULL a;
 select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
 DROP TABLE notnull_tbl1;
 
+CREATE TABLE notnull_t1(c0 int, c1 int);
+ALTER TABLE  notnull_t1 ADD CONSTRAINT Q PRIMARY KEY(c0, c1);
+ALTER TABLE  notnull_t1 DROP c1;
+ALTER TABLE  notnull_t1  ALTER c0 DROP NOT NULL;
+DROP TABLE notnull_t1;
+
 -- nope
 CREATE TABLE notnull_tbl2 (a INTEGER CONSTRAINT blah NOT NULL, b INTEGER CONSTRAINT blah NOT NULL);
 
-- 
2.25.1

