From 60b2a8fb666d837f8b406724262efa21d926c5a7 Mon Sep 17 00:00:00 2001 From: Chengxiong Ruan Date: Sat, 18 Dec 2021 17:05:52 -0500 Subject: [PATCH] sql: ignore shard column during unique constraint searching Fixes #69192 Referencing table does not know about the shard column. So need to ignore it when looking for a valid unique constraint. Release note (bug fix): Foreign key referencing hash sharded key won't fail anymore. --- pkg/sql/catalog/descpb/index.go | 19 ++- .../testdata/logic_test/hash_sharded_index | 127 ++++++++++++++++++ 2 files changed, 143 insertions(+), 3 deletions(-) diff --git a/pkg/sql/catalog/descpb/index.go b/pkg/sql/catalog/descpb/index.go index f9ffae5bc784..7b1466815694 100644 --- a/pkg/sql/catalog/descpb/index.go +++ b/pkg/sql/catalog/descpb/index.go @@ -65,13 +65,26 @@ func (desc *IndexDescriptor) IsValidOriginIndex(originColIDs ColumnIDs) bool { return !desc.IsPartial() && ColumnIDs(desc.KeyColumnIDs).HasPrefix(originColIDs) } +// ExplicitColumnIDsWithoutShardColumn returns explicit column ids of the index +// excluding the shard column. +func (desc *IndexDescriptor) ExplicitColumnIDsWithoutShardColumn() []ColumnID { + explicitColIDs := desc.KeyColumnIDs[desc.ExplicitColumnStartIdx():] + explicitColNames := desc.KeyColumnNames[desc.ExplicitColumnStartIdx():] + colIDs := make([]ColumnID, 0, len(explicitColIDs)) + for i := range explicitColNames { + if !desc.IsSharded() || explicitColNames[i] != desc.Sharded.Name { + colIDs = append(colIDs, explicitColIDs[i]) + } + } + return colIDs +} + // IsValidReferencedUniqueConstraint is part of the UniqueConstraint interface. // It returns whether the index can serve as a referenced index for a foreign // key constraint with the provided set of referencedColumnIDs. func (desc *IndexDescriptor) IsValidReferencedUniqueConstraint(referencedColIDs ColumnIDs) bool { - return desc.Unique && - !desc.IsPartial() && - ColumnIDs(desc.KeyColumnIDs[desc.Partitioning.NumImplicitColumns:]).PermutationOf(referencedColIDs) + colIDs := desc.ExplicitColumnIDsWithoutShardColumn() + return desc.Unique && !desc.IsPartial() && ColumnIDs(colIDs).PermutationOf(referencedColIDs) } // GetName is part of the UniqueConstraint interface. diff --git a/pkg/sql/logictest/testdata/logic_test/hash_sharded_index b/pkg/sql/logictest/testdata/logic_test/hash_sharded_index index 13b01e29aaad..08a4009a08ce 100644 --- a/pkg/sql/logictest/testdata/logic_test/hash_sharded_index +++ b/pkg/sql/logictest/testdata/logic_test/hash_sharded_index @@ -680,3 +680,130 @@ descriptor_id descriptor_name index_id index_name index_type is_unique is statement ok DROP TABLE poor_t + +subtest fk_reference_shard_pk + +statement ok +DROP TABLE IF EXISTS child + +statement ok +DROP TABLE IF EXISTS parent + +statement ok +CREATE TABLE parent ( +id INT PRIMARY KEY USING HASH WITH BUCKET_COUNT = 8 +); + +statement ok +CREATE TABLE child ( +id INT PRIMARY KEY, +pid INT, +CONSTRAINT fk_child_pid FOREIGN KEY (pid) REFERENCES parent(id) ON DELETE CASCADE +); + +statement error pq: insert on table "child" violates foreign key constraint "fk_child_pid" +INSERT INTO child VALUES (1,1) + +statement ok +INSERT INTO parent VALUES (1) + +statement ok +INSERT INTO child VALUES (1,1) + +subtest fk_reference_shard_index + +statement ok +DROP TABLE IF EXISTS child + +statement ok +DROP TABLE IF EXISTS parent + +statement ok +CREATE TABLE parent ( +id INT PRIMARY KEY, +oid INT +); + +statement ok +CREATE UNIQUE INDEX t_idx_oid ON parent(oid) USING HASH WITH BUCKET_COUNT = 8 + +statement ok +CREATE TABLE child ( +id INT PRIMARY KEY, +poid INT, +CONSTRAINT fk_child_pid FOREIGN KEY (poid) REFERENCES parent(oid) ON DELETE CASCADE +); + +statement error pq: insert on table "child" violates foreign key constraint "fk_child_pid" +INSERT INTO child VALUES (1,11) + +statement ok +INSERT INTO parent VALUES (1,11) + +statement ok +INSERT INTO child VALUES (1,11) + +subtest fk_reference_shard_pk_multi_col + +statement ok +DROP TABLE IF EXISTS child + +statement ok +DROP TABLE IF EXISTS parent + +statement ok +CREATE TABLE parent ( +a INT NOT NULL, +b INT NOT NULL, +PRIMARY KEY (a, b) USING HASH WITH BUCKET_COUNT = 8 +); + +statement ok +CREATE TABLE child ( +ca INT PRIMARY KEY, +cb INT, +CONSTRAINT fk_child_ca_cb FOREIGN KEY (ca, cb) REFERENCES parent(a, b) ON DELETE CASCADE +); + +statement error pq: insert on table "child" violates foreign key constraint "fk_child_ca_cb" +INSERT INTO child VALUES (1,1) + +statement ok +INSERT INTO parent VALUES (1,1) + +statement ok +INSERT INTO child VALUES (1,1) + +subtest fk_reference_shard_index_multi_col + +statement ok +DROP TABLE IF EXISTS child + +statement ok +DROP TABLE IF EXISTS parent + +statement ok +CREATE TABLE parent ( +a INT, +b INT +); + +statement ok +CREATE UNIQUE INDEX t_idx_a_b ON parent(a, b) USING HASH WITH BUCKET_COUNT = 8 + + +statement ok +CREATE TABLE child ( +ca INT PRIMARY KEY, +cb INT, +CONSTRAINT fk_child_ca_cb FOREIGN KEY (ca, cb) REFERENCES parent(a, b) ON DELETE CASCADE +); + +statement error pq: insert on table "child" violates foreign key constraint "fk_child_ca_cb" +INSERT INTO child VALUES (1,1) + +statement ok +INSERT INTO parent VALUES (1,1) + +statement ok +INSERT INTO child VALUES (1,1)