postgres.git / summary / log / commit / refs

commit    d0ec2ddbe088f6da35444fad688a62eae4fbd840
Author:   Alvaro Herrera <alvherre@alvh.no-ip.org>
Date:     Fri Sep 01 17:49:20 2023 +0000
First released in: 17.0

    Fix not-null constraint test
    
    When a partitioned table has a primary key, trying to find the
    corresponding not-null constraint for that column would come up empty,
    causing code that's trying to check said not-null constraint to crash.
    Fix by only running the check when the not-null constraint exists.
    
    Reported-by: Alexander Lakhin <exclusion@gmail.com>
    Discussion: https://postgr.es/m/d57b4a69-7394-3146-5976-9a1ef27e7972@gmail.com


src/backend/commands/tablecmds.c | 26 +++++++++++++++++++------- src/test/regress/expected/constraints.out | 11 +++++++++++ src/test/regress/sql/constraints.sql | 11 +++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 03397746724..47c556669f3 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -15746,9 +15746,10 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel) attributeName))); /* - * Check child doesn't discard NOT NULL property. (Other - * constraints are checked elsewhere.) However, if the constraint - * is NO INHERIT in the parent, this is allowed. + * If the parent has a not-null constraint that's not NO INHERIT, + * make sure the child has one too. + * + * Other constraints are checked elsewhere. */ if (attribute->attnotnull && !childatt->attnotnull) { @@ -15756,11 +15757,12 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel) contup = findNotNullConstraintAttnum(RelationGetRelid(parent_rel), attribute->attnum); - if (!((Form_pg_constraint) GETSTRUCT(contup))->connoinherit) + if (HeapTupleIsValid(contup) && + !((Form_pg_constraint) GETSTRUCT(contup))->connoinherit) ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("column \"%s\" in child table must be marked NOT NULL", - attributeName))); + errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("column \"%s\" in child table must be marked NOT NULL", + attributeName)); } /* @@ -15981,10 +15983,20 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) systable_endscan(child_scan); if (!found) + { + if (parent_con->contype == CONSTRAINT_NOTNULL) + ereport(ERROR, + errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("column \"%s\" in child table must be marked NOT NULL", + get_attname(parent_relid, + extractNotNullColumn(parent_tuple), + false))); + ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("child table is missing constraint \"%s\"", NameStr(parent_con->conname)))); + } } systable_endscan(parent_scan); diff --git a/src/test/regress/expected/constraints.out b/src/test/regress/expected/constraints.out index b7de50ad6a6..5b068477bf8 100644 --- a/src/test/regress/expected/constraints.out +++ b/src/test/regress/expected/constraints.out @@ -1006,6 +1006,17 @@ Inherits: cnn_grandchild, ALTER TABLE cnn_parent DROP CONSTRAINT cnn_parent_pkey; ERROR: constraint "cnn_parent_pkey" of relation "cnn_parent" does not exist -- keeps these tables around, for pg_upgrade testing +-- ensure columns in partitions are marked not-null +create table cnn2_parted(a int primary key) partition by list (a); +create table cnn2_part1(a int); +alter table cnn2_parted attach partition cnn2_part1 for values in (1); +ERROR: primary key column "a" is not marked NOT NULL +drop table cnn2_parted, cnn2_part1; +create table cnn2_parted(a int not null) partition by list (a); +create table cnn2_part1(a int primary key); +alter table cnn2_parted attach partition cnn2_part1 for values in (1); +ERROR: column "a" in child table must be marked NOT NULL +drop table cnn2_parted, cnn2_part1; -- Comments -- Setup a low-level role to enforce non-superuser checks. CREATE ROLE regress_constraint_comments; diff --git a/src/test/regress/sql/constraints.sql b/src/test/regress/sql/constraints.sql index 782699a4377..a7d96e98f58 100644 --- a/src/test/regress/sql/constraints.sql +++ b/src/test/regress/sql/constraints.sql @@ -657,6 +657,17 @@ ALTER TABLE cnn_parent ADD PRIMARY KEY USING INDEX b_uq; ALTER TABLE cnn_parent DROP CONSTRAINT cnn_parent_pkey; -- keeps these tables around, for pg_upgrade testing +-- ensure columns in partitions are marked not-null +create table cnn2_parted(a int primary key) partition by list (a); +create table cnn2_part1(a int); +alter table cnn2_parted attach partition cnn2_part1 for values in (1); +drop table cnn2_parted, cnn2_part1; + +create table cnn2_parted(a int not null) partition by list (a); +create table cnn2_part1(a int primary key); +alter table cnn2_parted attach partition cnn2_part1 for values in (1); +drop table cnn2_parted, cnn2_part1; + -- Comments -- Setup a low-level role to enforce non-superuser checks. [parent: e09d763e25dc]