Skip to content

Commit d0ec2dd

Browse files
committed
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
1 parent e09d763 commit d0ec2dd

File tree

3 files changed

+41
-7
lines changed

3 files changed

+41
-7
lines changed

src/backend/commands/tablecmds.c

+19-7
Original file line numberDiff line numberDiff line change
@@ -15746,21 +15746,23 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
1574615746
attributeName)));
1574715747

1574815748
/*
15749-
* Check child doesn't discard NOT NULL property. (Other
15750-
* constraints are checked elsewhere.) However, if the constraint
15751-
* is NO INHERIT in the parent, this is allowed.
15749+
* If the parent has a not-null constraint that's not NO INHERIT,
15750+
* make sure the child has one too.
15751+
*
15752+
* Other constraints are checked elsewhere.
1575215753
*/
1575315754
if (attribute->attnotnull && !childatt->attnotnull)
1575415755
{
1575515756
HeapTuple contup;
1575615757

1575715758
contup = findNotNullConstraintAttnum(RelationGetRelid(parent_rel),
1575815759
attribute->attnum);
15759-
if (!((Form_pg_constraint) GETSTRUCT(contup))->connoinherit)
15760+
if (HeapTupleIsValid(contup) &&
15761+
!((Form_pg_constraint) GETSTRUCT(contup))->connoinherit)
1576015762
ereport(ERROR,
15761-
(errcode(ERRCODE_DATATYPE_MISMATCH),
15762-
errmsg("column \"%s\" in child table must be marked NOT NULL",
15763-
attributeName)));
15763+
errcode(ERRCODE_DATATYPE_MISMATCH),
15764+
errmsg("column \"%s\" in child table must be marked NOT NULL",
15765+
attributeName));
1576415766
}
1576515767

1576615768
/*
@@ -15981,10 +15983,20 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
1598115983
systable_endscan(child_scan);
1598215984

1598315985
if (!found)
15986+
{
15987+
if (parent_con->contype == CONSTRAINT_NOTNULL)
15988+
ereport(ERROR,
15989+
errcode(ERRCODE_DATATYPE_MISMATCH),
15990+
errmsg("column \"%s\" in child table must be marked NOT NULL",
15991+
get_attname(parent_relid,
15992+
extractNotNullColumn(parent_tuple),
15993+
false)));
15994+
1598415995
ereport(ERROR,
1598515996
(errcode(ERRCODE_DATATYPE_MISMATCH),
1598615997
errmsg("child table is missing constraint \"%s\"",
1598715998
NameStr(parent_con->conname))));
15999+
}
1598816000
}
1598916001

1599016002
systable_endscan(parent_scan);

src/test/regress/expected/constraints.out

+11
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,17 @@ Inherits: cnn_grandchild,
10061006
ALTER TABLE cnn_parent DROP CONSTRAINT cnn_parent_pkey;
10071007
ERROR: constraint "cnn_parent_pkey" of relation "cnn_parent" does not exist
10081008
-- keeps these tables around, for pg_upgrade testing
1009+
-- ensure columns in partitions are marked not-null
1010+
create table cnn2_parted(a int primary key) partition by list (a);
1011+
create table cnn2_part1(a int);
1012+
alter table cnn2_parted attach partition cnn2_part1 for values in (1);
1013+
ERROR: primary key column "a" is not marked NOT NULL
1014+
drop table cnn2_parted, cnn2_part1;
1015+
create table cnn2_parted(a int not null) partition by list (a);
1016+
create table cnn2_part1(a int primary key);
1017+
alter table cnn2_parted attach partition cnn2_part1 for values in (1);
1018+
ERROR: column "a" in child table must be marked NOT NULL
1019+
drop table cnn2_parted, cnn2_part1;
10091020
-- Comments
10101021
-- Setup a low-level role to enforce non-superuser checks.
10111022
CREATE ROLE regress_constraint_comments;

src/test/regress/sql/constraints.sql

+11
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,17 @@ ALTER TABLE cnn_parent ADD PRIMARY KEY USING INDEX b_uq;
657657
ALTER TABLE cnn_parent DROP CONSTRAINT cnn_parent_pkey;
658658
-- keeps these tables around, for pg_upgrade testing
659659

660+
-- ensure columns in partitions are marked not-null
661+
create table cnn2_parted(a int primary key) partition by list (a);
662+
create table cnn2_part1(a int);
663+
alter table cnn2_parted attach partition cnn2_part1 for values in (1);
664+
drop table cnn2_parted, cnn2_part1;
665+
666+
create table cnn2_parted(a int not null) partition by list (a);
667+
create table cnn2_part1(a int primary key);
668+
alter table cnn2_parted attach partition cnn2_part1 for values in (1);
669+
drop table cnn2_parted, cnn2_part1;
670+
660671

661672
-- Comments
662673
-- Setup a low-level role to enforce non-superuser checks.

0 commit comments

Comments
 (0)