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: block FKs to/from TTL tables #76409

Merged
merged 1 commit into from
Feb 15, 2022
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
14 changes: 10 additions & 4 deletions docs/RFCS/20220120_row_level_ttl.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,16 @@ Rows that have expired their TTL can be optionally removed from all SQL query
results. Work for this is required at the optimizer layer. However, this is not
planned to be implemented for the first iteration of TTL.

## Foreign Keys to a TTL Table
To avoid additional complexity in the initial implementation, foreign keys to
TTL tables will not be permitted. More thought has to be put on ON
DELETE/ON UPDATE CASCADEs before we can look at allowing this functionality.
## Foreign Keys to/from TTL Tables
To avoid additional complexity in the initial implementation, foreign keys (FK)
to and from TTL tables will not be permitted due to complexities with the
implementation which are complex to handle, for example:
* When having a non-TTL table with a FK dependent on a TTL table with an
`ON UPDATE/DELETE CASCADE`, the non-TTL table need to hide any rows which
are linked to an expired TTL row.
* When having a TTL table with an FK dependent on a non-TTL table,
`ON DELETE RESTRICT` should only block a delete on the non-TTL table
if the row has expired.

## Introspection
The TTL definition for the table will appear in `SHOW CREATE TABLE`. The options
Expand Down
2 changes: 2 additions & 0 deletions pkg/sql/catalog/descriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,8 @@ type TableDescriptor interface {
GetRegionalByRowTableRegionColumnName() (tree.Name, error)
// GetRowLevelTTL returns the row-level TTL config for the table.
GetRowLevelTTL() *descpb.TableDescriptor_RowLevelTTL
// HasRowLevelTTL returns where there is a row-level TTL config for the table.
HasRowLevelTTL() bool
// GetExcludeDataFromBackup returns true if the table's row data is configured
// to be excluded during backup.
GetExcludeDataFromBackup() bool
Expand Down
5 changes: 5 additions & 0 deletions pkg/sql/catalog/tabledesc/structured.go
Original file line number Diff line number Diff line change
Expand Up @@ -2440,6 +2440,11 @@ func (desc *wrapper) GetRowLevelTTL() *descpb.TableDescriptor_RowLevelTTL {
return desc.RowLevelTTL
}

// HasRowLevelTTL implements the TableDescriptor interface.
func (desc *wrapper) HasRowLevelTTL() bool {
return desc.RowLevelTTL != nil
}

// GetExcludeDataFromBackup implements the TableDescriptor interface.
func (desc *wrapper) GetExcludeDataFromBackup() bool {
return desc.ExcludeDataFromBackup
Expand Down
7 changes: 7 additions & 0 deletions pkg/sql/catalog/tabledesc/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ func (desc *wrapper) ValidateCrossReferences(
}

// Check foreign keys.
if desc.HasRowLevelTTL() && (len(desc.OutboundFKs) > 0 || len(desc.InboundFKs) > 0) {
vea.Report(unimplemented.NewWithIssuef(
76407,
`foreign keys to/from table with TTL "%s" are not permitted`,
desc.Name,
))
}
for i := range desc.OutboundFKs {
vea.Report(desc.validateOutboundFK(&desc.OutboundFKs[i], vdg))
}
Expand Down
25 changes: 25 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/row_level_ttl
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,28 @@ CREATE TABLE public.tbl (
CONSTRAINT tbl_pkey PRIMARY KEY (id ASC),
FAMILY fam_0_id_text_crdb_internal_expiration (id, text, crdb_internal_expiration)
) WITH (ttl = 'on', ttl_automatic_column = 'on', ttl_expire_after = '00:10:00':::INTERVAL)

# Test we cannot add FKs to a TTL table.
statement ok
CREATE TABLE ref_table (id INT PRIMARY KEY, ref INT)

statement error foreign keys to/from table with TTL "ttl_table" are not permitted
CREATE TABLE ttl_table (id INT PRIMARY KEY, ref INT REFERENCES ref_table(id)) WITH (ttl_expire_after = '10 mins')

statement ok
CREATE TABLE ttl_table (id INT PRIMARY KEY, ref INT) WITH (ttl_expire_after = '10 mins')

statement error foreign keys to/from table with TTL "ttl_table" are not permitted
CREATE TABLE new_ref_table (id INT PRIMARY KEY, ref INT REFERENCES ttl_table(id))

statement error foreign keys to/from table with TTL "ttl_table" are not permitted
ALTER TABLE ref_table ADD CONSTRAINT fk FOREIGN KEY (ref) REFERENCES ttl_table (id)

statement error foreign keys to/from table with TTL "ttl_table" are not permitted
ALTER TABLE ttl_table ADD CONSTRAINT fk FOREIGN KEY (ref) REFERENCES ttl_table (id)

statement ok
CREATE TABLE ttl_become_table (id INT PRIMARY KEY, ref INT REFERENCES ref_table (id))

statement error foreign keys to/from table with TTL "ttl_become_table" are not permitted
ALTER TABLE ttl_become_table SET (ttl_expire_after = '10 minutes')