Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql: disallow virtual columns in FK references #59675

Merged
merged 1 commit into from
Feb 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)