Skip to content

Commit

Permalink
sql: disallow virtual columns in FK references
Browse files Browse the repository at this point in the history
Disallow FK references to or from virtual columns. Note that there is
no big reason why we couldn't support them other than some extra work
and testing surface; this is tracked by cockroachdb#59671.

Informs cockroachdb#57608.

Release note: None
  • Loading branch information
RaduBerinde committed Feb 1, 2021
1 parent a0bc3d9 commit 0ef3fa4
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 20 deletions.
10 changes: 0 additions & 10 deletions pkg/sql/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 22 additions & 3 deletions pkg/sql/catalog/descpb/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
}
Expand Down
8 changes: 7 additions & 1 deletion pkg/sql/create_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)",
Expand Down
12 changes: 6 additions & 6 deletions pkg/sql/logictest/testdata/logic_test/computed
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand Down
42 changes: 42 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/virtual_columns
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 0ef3fa4

Please sign in to comment.