From 6239fc48eeaa43b02614ebd96582254d36b5053f Mon Sep 17 00:00:00 2001 From: "tender.wang" 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