From 3ee3d650f7d038affb91910bc2629e308e130542 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 | 10 ++++++++++ pkg/sql/opt/testutils/testcat/create_table.go | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pkg/sql/catalog/descpb/index.go b/pkg/sql/catalog/descpb/index.go index cf8ef80a5f4b..5fa34315d685 100644 --- a/pkg/sql/catalog/descpb/index.go +++ b/pkg/sql/catalog/descpb/index.go @@ -160,13 +160,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 d59d9de6fa62..2e2fb9adbe3a 100644 --- a/pkg/sql/logictest/testdata/logic_test/fk +++ b/pkg/sql/logictest/testdata/logic_test/fk @@ -3626,3 +3626,13 @@ USE db2 statement ok CREATE TABLE child2 (c INT PRIMARY KEY, p INT REFERENCES db1.public.parent(p)) + +# 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 410088aad141..8d8576948ebf 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 }