From bd56e9d2a418f4b08b77bd0a9a9bca03a930f6e7 Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Mon, 19 Oct 2020 10:46:59 -0700 Subject: [PATCH] sql: disqualify partial unique indexes as foreign key reference indexes Release justification: This is a critical bug fix for a new feature, partial indexes. Release note (bug fix): Foreign keys can no longer reference columns that are only indexed by a partial unique index. A partial unique index does not guarantee uniqueness in the entire table, therefore the column indexed is not guaranteed to be a unique key. --- pkg/sql/catalog/descpb/index.go | 4 ++-- pkg/sql/logictest/testdata/logic_test/fk | 11 ++++++++++- pkg/sql/opt/testutils/testcat/create_table.go | 3 +++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pkg/sql/catalog/descpb/index.go b/pkg/sql/catalog/descpb/index.go index f67a2aceebd8..226fde0baf1d 100644 --- a/pkg/sql/catalog/descpb/index.go +++ b/pkg/sql/catalog/descpb/index.go @@ -156,13 +156,13 @@ func (desc *IndexDescriptor) ColNamesString() string { // IsValidOriginIndex returns whether the index can serve as an origin index for a foreign // key constraint with the provided set of originColIDs. func (desc *IndexDescriptor) IsValidOriginIndex(originColIDs ColumnIDs) bool { - return ColumnIDs(desc.ColumnIDs).HasPrefix(originColIDs) + return !desc.IsPartial() && ColumnIDs(desc.ColumnIDs).HasPrefix(originColIDs) } // IsValidReferencedIndex returns whether the index can serve as a referenced index for a foreign // key constraint with the provided set of referencedColumnIDs. func (desc *IndexDescriptor) IsValidReferencedIndex(referencedColIDs ColumnIDs) bool { - return desc.Unique && ColumnIDs(desc.ColumnIDs).Equals(referencedColIDs) + return desc.Unique && !desc.IsPartial() && ColumnIDs(desc.ColumnIDs).Equals(referencedColIDs) } // HasOldStoredColumns returns whether the index has stored columns in the old diff --git a/pkg/sql/logictest/testdata/logic_test/fk b/pkg/sql/logictest/testdata/logic_test/fk index e7793ff870ce..6a5019b822b2 100644 --- a/pkg/sql/logictest/testdata/logic_test/fk +++ b/pkg/sql/logictest/testdata/logic_test/fk @@ -3600,7 +3600,6 @@ USE db2 statement ok CREATE TABLE child2 (c INT PRIMARY KEY, p INT REFERENCES db1.public.parent(p)) - # Test that reversing a constraint addition after adding a self foreign key # works correctly. @@ -3626,3 +3625,13 @@ foreign key violation: "add_self_fk_fail" row b=3, k=1 has no match in "add_self statement ok DROP TABLE add_self_fk_fail + +# Test that foreign keys cannot reference columns that are indexed by a partial +# unique index. Partial unique indexes do not guarantee uniqueness in the entire +# table. + +statement ok +CREATE TABLE partial_parent (p INT, UNIQUE INDEX (p) WHERE p > 100) + +statement error there is no unique constraint matching given keys for referenced table partial_parent +CREATE TABLE partial_child (p INT REFERENCES partial_parent (p)) diff --git a/pkg/sql/opt/testutils/testcat/create_table.go b/pkg/sql/opt/testutils/testcat/create_table.go index 7ca248580561..7d9db3c1c804 100644 --- a/pkg/sql/opt/testutils/testcat/create_table.go +++ b/pkg/sql/opt/testutils/testcat/create_table.go @@ -365,6 +365,9 @@ func (tc *Catalog) resolveFK(tab *Table, d *tree.ForeignKeyConstraintTableDef) { return false } } + if _, isPartialIndex := idx.Predicate(); isPartialIndex { + return false + } return true }