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

ttl,ddl: disable ttl for fk and temp table #39581

Merged
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
4 changes: 2 additions & 2 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2116,7 +2116,7 @@ func checkTableInfoValidWithStmt(ctx sessionctx.Context, tbInfo *model.TableInfo
}
}
if tbInfo.TTLInfo != nil {
if err := checkTTLInfoValid(ctx, tbInfo); err != nil {
if err := checkTTLInfoValid(ctx, s.Table.Schema, tbInfo); err != nil {
return errors.Trace(err)
}
}
Expand Down Expand Up @@ -5368,7 +5368,7 @@ func (d *ddl) AlterTableTTLInfoOrEnable(ctx sessionctx.Context, ident ast.Ident,
var job *model.Job
if ttlInfo != nil {
tblInfo.TTLInfo = ttlInfo
err = checkTTLInfoValid(ctx, tblInfo)
err = checkTTLInfoValid(ctx, ident.Schema, tblInfo)
if err != nil {
return err
}
Expand Down
3 changes: 3 additions & 0 deletions ddl/foreign_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ func checkTableForeignKey(referTblInfo, tblInfo *model.TableInfo, fkInfo *model.
if referTblInfo.TempTableType != model.TempTableNone || tblInfo.TempTableType != model.TempTableNone {
return infoschema.ErrCannotAddForeign
}
if referTblInfo.TTLInfo != nil {
return dbterror.ErrUnsupportedTTLReferencedByFK
}

// check refer columns in parent table.
for i := range fkInfo.RefCols {
Expand Down
23 changes: 22 additions & 1 deletion ddl/ttl.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/pingcap/tidb/parser/format"
"github.com/pingcap/tidb/parser/model"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessiontxn"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/dbterror"
)
Expand Down Expand Up @@ -83,11 +84,15 @@ func onTTLInfoChange(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, err er
return ver, nil
}

func checkTTLInfoValid(ctx sessionctx.Context, tblInfo *model.TableInfo) error {
func checkTTLInfoValid(ctx sessionctx.Context, schema model.CIStr, tblInfo *model.TableInfo) error {
if err := checkTTLIntervalExpr(ctx, tblInfo.TTLInfo); err != nil {
return err
}

if err := checkTTLTableSuitable(ctx, schema, tblInfo); err != nil {
return err
}

return checkTTLInfoColumnType(tblInfo)
}

Expand Down Expand Up @@ -119,6 +124,22 @@ func checkTTLInfoColumnType(tblInfo *model.TableInfo) error {
return nil
}

// checkTTLTableSuitable returns whether this table is suitable to be a TTL table
// A temporary table or a parent table referenced by a foreign key cannot be TTL table
func checkTTLTableSuitable(ctx sessionctx.Context, schema model.CIStr, tblInfo *model.TableInfo) error {
if tblInfo.TempTableType != model.TempTableNone {
return dbterror.ErrTempTableNotAllowedWithTTL
}

// checks even when the foreign key check is not enabled, to keep safe
is := sessiontxn.GetTxnManager(ctx).GetTxnInfoSchema()
if referredFK := checkTableHasForeignKeyReferred(is, schema.L, tblInfo.Name.L, nil, true); referredFK != nil {
return dbterror.ErrUnsupportedTTLReferencedByFK
}

return nil
}

func checkDropColumnWithTTLConfig(tblInfo *model.TableInfo, colName string) error {
if tblInfo.TTLInfo != nil {
if tblInfo.TTLInfo.ColumnName.L == colName {
Expand Down
2 changes: 2 additions & 0 deletions errno/errcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,8 @@ const (
ErrUnsupportedColumnInTTLConfig = 8148
ErrTTLColumnCannotDrop = 8149
ErrSetTTLEnableForNonTTLTable = 8150
ErrTempTableNotAllowedWithTTL = 8151
ErrUnsupportedTTLReferencedByFK = 8152

// Error codes used by TiDB ddl package
ErrUnsupportedDDLOperation = 8200
Expand Down
2 changes: 2 additions & 0 deletions errno/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,8 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{
ErrUnsupportedColumnInTTLConfig: mysql.Message("Field '%-.192s' is of a not supported type for TTL config, expect DATETIME, DATE or TIMESTAMP", nil),
ErrTTLColumnCannotDrop: mysql.Message("Cannot drop column '%-.192s': needed in TTL config", nil),
ErrSetTTLEnableForNonTTLTable: mysql.Message("Cannot set TTL_ENABLE on a table without TTL config", nil),
ErrTempTableNotAllowedWithTTL: mysql.Message("Set TTL for temporary table is not allowed", nil),
ErrUnsupportedTTLReferencedByFK: mysql.Message("Set TTL for a table referenced by foreign key is not allowed", nil),

ErrWarnOptimizerHintInvalidInteger: mysql.Message("integer value is out of range in '%s'", nil),
ErrWarnOptimizerHintUnsupportedHint: mysql.Message("Optimizer hint %s is not supported by TiDB and is ignored", nil),
Expand Down
10 changes: 10 additions & 0 deletions errors.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,16 @@ error = '''
Cannot set TTL_ENABLE on a table without TTL config
'''

["ddl:8151"]
error = '''
Set TTL for temporary table is not allowed
'''

["ddl:8152"]
error = '''
Set TTL for a table referenced by foreign key is not allowed
'''

["ddl:8200"]
error = '''
Unsupported shard_row_id_bits for table with primary key as row id
Expand Down
36 changes: 36 additions & 0 deletions executor/ddl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1582,3 +1582,39 @@ func TestAlterTTLInfo(t *testing.T) {

tk.MustGetErrMsg("ALTER TABLE t TTL_ENABLE = 'OFF'", "[ddl:8150]Cannot set TTL_ENABLE on a table without TTL config")
}

func TestDisableTTLForTempTable(t *testing.T) {
parser.TTLFeatureGate = true

store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")

tk.MustGetDBError("CREATE TEMPORARY TABLE t (created_at datetime) TTL = `created_at` + INTERVAL 5 DAY", dbterror.ErrTempTableNotAllowedWithTTL)
}

func TestDisableTTLForFKParentTable(t *testing.T) {
parser.TTLFeatureGate = true

store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")

// alter ttl for a FK parent table is not allowed
tk.MustExec("set global tidb_enable_foreign_key='ON'")
tk.MustExec("CREATE TABLE t (id int primary key, created_at datetime)")
tk.MustExec("CREATE TABLE t_1 (t_id int, foreign key fk_t_id(t_id) references t(id))")
tk.MustGetDBError("ALTER TABLE t TTL = created_at + INTERVAL 5 YEAR", dbterror.ErrUnsupportedTTLReferencedByFK)
tk.MustExec("drop table t,t_1")

// refuse to reference TTL key when create table
tk.MustExec("CREATE TABLE t (id int primary key, created_at datetime) TTL = created_at + INTERVAL 5 YEAR")
tk.MustGetDBError("CREATE TABLE t_1 (t_id int, foreign key fk_t_id(t_id) references t(id))", dbterror.ErrUnsupportedTTLReferencedByFK)
tk.MustExec("drop table t")

// refuse to add foreign key reference TTL table
tk.MustExec("CREATE TABLE t (id int primary key, created_at datetime) TTL = created_at + INTERVAL 5 YEAR")
tk.MustExec("CREATE TABLE t_1 (t_id int)")
tk.MustGetDBError("ALTER TABLE t_1 ADD FOREIGN KEY fk_t_id(t_id) references t(id)", dbterror.ErrUnsupportedTTLReferencedByFK)
tk.MustExec("drop table t,t_1")
}
4 changes: 4 additions & 0 deletions util/dbterror/ddl_terror.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,8 @@ var (
ErrTTLColumnCannotDrop = ClassDDL.NewStd(mysql.ErrTTLColumnCannotDrop)
// ErrSetTTLEnableForNonTTLTable returns when the `TTL_ENABLE` option is set on a non-TTL table
ErrSetTTLEnableForNonTTLTable = ClassDDL.NewStd(mysql.ErrSetTTLEnableForNonTTLTable)
// ErrTempTableNotAllowedWithTTL returns when setting TTL config for a temp table
ErrTempTableNotAllowedWithTTL = ClassDDL.NewStd(mysql.ErrTempTableNotAllowedWithTTL)
// ErrUnsupportedTTLReferencedByFK returns when the TTL config is set for a table referenced by foreign key
ErrUnsupportedTTLReferencedByFK = ClassDDL.NewStd(mysql.ErrUnsupportedTTLReferencedByFK)
)