diff --git a/pkg/sql/logictest/testdata/logic_test/fk b/pkg/sql/logictest/testdata/logic_test/fk index e8f8ab88cab8..14af5df12d3d 100644 --- a/pkg/sql/logictest/testdata/logic_test/fk +++ b/pkg/sql/logictest/testdata/logic_test/fk @@ -2742,3 +2742,18 @@ ALTER TABLE table1_42498 ADD FOREIGN KEY (col2, col1) REFERENCES table2_42498 (c statement ok DROP TABLE table1_42498, table2_42498 CASCADE + +# Regression test for #42680: The unique index used for the referenced columns +# must index only those columns and no others, in order to enforce uniqueness +# for the FK constraint. +subtest 42680_unique_index_must_exactly_match_columns + +# The table has a unique index on (a, b) but not (a). +statement ok +CREATE TABLE target (a INT, b INT, UNIQUE INDEX (a, b)); + +statement ok +CREATE TABLE source (a INT, INDEX (a)); + +statement error there is no unique constraint matching given keys for referenced table target +ALTER TABLE source ADD FOREIGN KEY (a) REFERENCES target (a); diff --git a/pkg/sql/sqlbase/structured.go b/pkg/sql/sqlbase/structured.go index 487fe0fa16f2..e66ace8ab320 100644 --- a/pkg/sql/sqlbase/structured.go +++ b/pkg/sql/sqlbase/structured.go @@ -86,6 +86,19 @@ func (c ColumnIDs) HasPrefix(input ColumnIDs) bool { return true } +// Equals returns true if the input list is equal to this list. +func (c ColumnIDs) Equals(input ColumnIDs) bool { + if len(input) != len(c) { + return false + } + for i := range input { + if input[i] != c[i] { + return false + } + } + return true +} + // FamilyID is a custom type for ColumnFamilyDescriptor IDs. type FamilyID uint32 diff --git a/pkg/sql/sqlbase/table.go b/pkg/sql/sqlbase/table.go index 6d416a32fa1c..9175bc708e17 100644 --- a/pkg/sql/sqlbase/table.go +++ b/pkg/sql/sqlbase/table.go @@ -423,12 +423,12 @@ func FindFKReferencedIndex( ) (*IndexDescriptor, error) { // Search for a unique index on the referenced table that matches our foreign // key columns. - if ColumnIDs(referencedTable.PrimaryIndex.ColumnIDs).HasPrefix(referencedColIDs) { + if ColumnIDs(referencedTable.PrimaryIndex.ColumnIDs).Equals(referencedColIDs) { return &referencedTable.PrimaryIndex, nil } // If the PK doesn't match, find the index corresponding to the referenced column. for _, idx := range referencedTable.Indexes { - if idx.Unique && ColumnIDs(idx.ColumnIDs).HasPrefix(referencedColIDs) { + if idx.Unique && ColumnIDs(idx.ColumnIDs).Equals(referencedColIDs) { return &idx, nil } }