diff --git a/pkg/sql/alter_table.go b/pkg/sql/alter_table.go index b3ef8655bced..7f9de345e3d1 100644 --- a/pkg/sql/alter_table.go +++ b/pkg/sql/alter_table.go @@ -300,16 +300,6 @@ func (n *alterTableNode) startExec(params runParams) error { } case *tree.ForeignKeyConstraintTableDef: - for _, colName := range d.FromCols { - col, err := n.tableDesc.FindActiveOrNewColumnByName(colName) - if err != nil { - return err - } - - if err := col.CheckCanBeFKRef(); err != nil { - return err - } - } affected := make(map[descpb.ID]*tabledesc.Mutable) // If there are any FKs, we will need to update the table descriptor of the diff --git a/pkg/sql/catalog/descpb/column.go b/pkg/sql/catalog/descpb/column.go index 39aa87b1c5ae..4ee56f25d276 100644 --- a/pkg/sql/catalog/descpb/column.go +++ b/pkg/sql/catalog/descpb/column.go @@ -45,11 +45,30 @@ func (desc *ColumnDescriptor) ColName() tree.Name { return tree.Name(desc.Name) } -// CheckCanBeFKRef returns whether the given column is computed. -func (desc *ColumnDescriptor) CheckCanBeFKRef() error { +// CheckCanBeOutboundFKRef returns whether the given column can be on the +// referencing (origin) side of a foreign key relation. +func (desc *ColumnDescriptor) CheckCanBeOutboundFKRef() error { + if desc.Virtual { + return unimplemented.NewWithIssuef( + 59671, "virtual column %q cannot reference a foreign key", + desc.Name, + ) + } if desc.IsComputed() { return unimplemented.NewWithIssuef( - 46672, "computed column %q cannot be a foreign key reference", + 46672, "computed column %q cannot reference a foreign key", + desc.Name, + ) + } + return nil +} + +// CheckCanBeInboundFKRef returns whether the given column can be on the +// referenced (target) side of a foreign key relation. +func (desc *ColumnDescriptor) CheckCanBeInboundFKRef() error { + if desc.Virtual { + return unimplemented.NewWithIssuef( + 59671, "virtual column %q cannot be referenced by a foreign key", desc.Name, ) } diff --git a/pkg/sql/create_table.go b/pkg/sql/create_table.go index 66ad567e800f..c450de77244e 100644 --- a/pkg/sql/create_table.go +++ b/pkg/sql/create_table.go @@ -809,7 +809,7 @@ func ResolveFK( if err != nil { return err } - if err := col.CheckCanBeFKRef(); err != nil { + if err := col.CheckCanBeOutboundFKRef(); err != nil { return err } // Ensure that the origin columns don't have duplicates. @@ -883,6 +883,12 @@ func ResolveFK( return err } + for i := range referencedCols { + if err := referencedCols[i].CheckCanBeInboundFKRef(); err != nil { + return err + } + } + if len(referencedCols) != len(originCols) { return pgerror.Newf(pgcode.Syntax, "%d columns must reference exactly %d columns in referenced table (found %d)", diff --git a/pkg/sql/logictest/testdata/logic_test/computed b/pkg/sql/logictest/testdata/logic_test/computed index 2694e7f976d7..01820cd308db 100644 --- a/pkg/sql/logictest/testdata/logic_test/computed +++ b/pkg/sql/logictest/testdata/logic_test/computed @@ -358,17 +358,17 @@ CREATE TABLE y ( r INT AS (q) STORED ) -statement error computed column "r" cannot be a foreign key reference +statement error computed column "r" cannot reference a foreign key CREATE TABLE y ( r INT AS (1) STORED REFERENCES x (a) ) -statement error computed column "r" cannot be a foreign key reference +statement error computed column "r" cannot reference a foreign key CREATE TABLE y ( r INT AS (1) STORED REFERENCES x ) -statement error computed column "r" cannot be a foreign key reference +statement error computed column "r" cannot reference a foreign key CREATE TABLE y ( a INT, r INT AS (1) STORED REFERENCES x @@ -393,14 +393,14 @@ CREATE TABLE xx ( UNIQUE (a, b) ) -statement error computed column "y" cannot be a foreign key reference +statement error computed column "y" cannot reference a foreign key CREATE TABLE yy ( x INT, y INT AS (3) STORED, FOREIGN KEY (x, y) REFERENCES xx (a, b) ) -statement error computed column "y" cannot be a foreign key reference +statement error computed column "y" cannot reference a foreign key CREATE TABLE yy ( x INT, y INT AS (3) STORED, @@ -416,7 +416,7 @@ CREATE TABLE y ( INDEX (r) ) -statement error computed column "r" cannot be a foreign key reference +statement error computed column "r" cannot reference a foreign key ALTER TABLE y ADD FOREIGN KEY (r) REFERENCES x (a) statement ok diff --git a/pkg/sql/logictest/testdata/logic_test/virtual_columns b/pkg/sql/logictest/testdata/logic_test/virtual_columns index e9d85699befd..f2160b52d8fe 100644 --- a/pkg/sql/logictest/testdata/logic_test/virtual_columns +++ b/pkg/sql/logictest/testdata/logic_test/virtual_columns @@ -500,3 +500,45 @@ a b v w1 w2 1 10 11 10 20 2 20 22 40 40 3 30 33 90 60 + +# Verify that FK relations on virtual columns are disallowed. +statement ok +CREATE TABLE fk ( + a INT PRIMARY KEY, + b INT, + c INT, + u INT UNIQUE AS (b+c) VIRTUAL +) + +statement error virtual column "u" cannot be referenced by a foreign key +CREATE TABLE fk2 ( + p INT PRIMARY KEY, + c INT REFERENCES fk(u) +) + +statement error virtual column "c" cannot reference a foreign key +CREATE TABLE fk2 ( + p INT PRIMARY KEY, + c INT AS (p+1) VIRTUAL REFERENCES fk(a) +) + +statement error virtual column "u" cannot be referenced by a foreign key +CREATE TABLE fk2 ( + p INT PRIMARY KEY, + q INT, + r INT, + CONSTRAINT fk FOREIGN KEY (q,r) REFERENCES fk(a,u) +) + +statement ok +CREATE TABLE fk2 ( + x INT PRIMARY KEY, + y INT, + v INT AS (x+y) VIRTUAL +) + +statement error virtual column "u" cannot be referenced by a foreign key +ALTER TABLE fk2 ADD CONSTRAINT foo FOREIGN KEY (x) REFERENCES fk(u) + +statement error virtual column "v" cannot reference a foreign key +ALTER TABLE fk2 ADD CONSTRAINT foo FOREIGN KEY (v) REFERENCES fk(a)