ddl: forbid recover/flashback temporary tables (#24518)
This commit is contained in:
@ -26,12 +26,14 @@ import (
|
||||
"github.com/pingcap/tidb/config"
|
||||
"github.com/pingcap/tidb/ddl"
|
||||
"github.com/pingcap/tidb/domain"
|
||||
"github.com/pingcap/tidb/errno"
|
||||
"github.com/pingcap/tidb/infoschema"
|
||||
"github.com/pingcap/tidb/meta"
|
||||
"github.com/pingcap/tidb/planner/core"
|
||||
"github.com/pingcap/tidb/sessionctx/variable"
|
||||
"github.com/pingcap/tidb/util/admin"
|
||||
"github.com/pingcap/tidb/util/chunk"
|
||||
"github.com/pingcap/tidb/util/dbterror"
|
||||
"github.com/pingcap/tidb/util/gcutil"
|
||||
"github.com/pingcap/tidb/util/logutil"
|
||||
"github.com/pingcap/tidb/util/sqlexec"
|
||||
@ -563,6 +565,11 @@ func (e *DDLExec) getRecoverTableByTableName(tableName *ast.TableName) (*model.J
|
||||
if tableInfo == nil || jobInfo == nil {
|
||||
return nil, nil, errors.Errorf("Can't find dropped/truncated table: %v in DDL history jobs", tableName.Name)
|
||||
}
|
||||
// Dropping local temporary tables won't appear in DDL jobs.
|
||||
if tableInfo.TempTableType == model.TempTableGlobal {
|
||||
msg := mysql.Message("Recover/flashback table is not supported on temporary tables", nil)
|
||||
return nil, nil, dbterror.ClassDDL.NewStdErr(errno.ErrUnsupportedDDLOperation, msg)
|
||||
}
|
||||
return jobInfo, tableInfo, nil
|
||||
}
|
||||
|
||||
|
||||
@ -5697,24 +5697,15 @@ func (s *testRecoverTable) TearDownSuite(c *C) {
|
||||
s.dom.Close()
|
||||
}
|
||||
|
||||
func (s *testRecoverTable) TestRecoverTable(c *C) {
|
||||
c.Assert(failpoint.Enable("github.com/pingcap/tidb/meta/autoid/mockAutoIDChange", `return(true)`), IsNil)
|
||||
defer func() {
|
||||
err := failpoint.Disable("github.com/pingcap/tidb/meta/autoid/mockAutoIDChange")
|
||||
c.Assert(err, IsNil)
|
||||
}()
|
||||
tk := testkit.NewTestKit(c, s.store)
|
||||
tk.MustExec("create database if not exists test_recover")
|
||||
tk.MustExec("use test_recover")
|
||||
tk.MustExec("drop table if exists t_recover")
|
||||
tk.MustExec("create table t_recover (a int);")
|
||||
defer func(originGC bool) {
|
||||
func (s *testRecoverTable) mockGC(tk *testkit.TestKit) (string, string, string, func()) {
|
||||
originGC := ddl.IsEmulatorGCEnable()
|
||||
resetGC := func() {
|
||||
if originGC {
|
||||
ddl.EmulatorGCEnable()
|
||||
} else {
|
||||
ddl.EmulatorGCDisable()
|
||||
}
|
||||
}(ddl.IsEmulatorGCEnable())
|
||||
}
|
||||
|
||||
// disable emulator GC.
|
||||
// Otherwise emulator GC will delete table record as soon as possible after execute drop table ddl.
|
||||
@ -5727,6 +5718,23 @@ func (s *testRecoverTable) TestRecoverTable(c *C) {
|
||||
UPDATE variable_value = '%[1]s'`
|
||||
// clear GC variables first.
|
||||
tk.MustExec("delete from mysql.tidb where variable_name in ( 'tikv_gc_safe_point','tikv_gc_enable' )")
|
||||
return timeBeforeDrop, timeAfterDrop, safePointSQL, resetGC
|
||||
}
|
||||
|
||||
func (s *testRecoverTable) TestRecoverTable(c *C) {
|
||||
c.Assert(failpoint.Enable("github.com/pingcap/tidb/meta/autoid/mockAutoIDChange", `return(true)`), IsNil)
|
||||
defer func() {
|
||||
err := failpoint.Disable("github.com/pingcap/tidb/meta/autoid/mockAutoIDChange")
|
||||
c.Assert(err, IsNil)
|
||||
}()
|
||||
tk := testkit.NewTestKit(c, s.store)
|
||||
tk.MustExec("create database if not exists test_recover")
|
||||
tk.MustExec("use test_recover")
|
||||
tk.MustExec("drop table if exists t_recover")
|
||||
tk.MustExec("create table t_recover (a int);")
|
||||
|
||||
timeBeforeDrop, timeAfterDrop, safePointSQL, resetGC := s.mockGC(tk)
|
||||
defer resetGC()
|
||||
|
||||
tk.MustExec("insert into t_recover values (1),(2),(3)")
|
||||
tk.MustExec("drop table t_recover")
|
||||
@ -5819,24 +5827,10 @@ func (s *testRecoverTable) TestFlashbackTable(c *C) {
|
||||
tk.MustExec("use test_flashback")
|
||||
tk.MustExec("drop table if exists t_flashback")
|
||||
tk.MustExec("create table t_flashback (a int);")
|
||||
defer func(originGC bool) {
|
||||
if originGC {
|
||||
ddl.EmulatorGCEnable()
|
||||
} else {
|
||||
ddl.EmulatorGCDisable()
|
||||
}
|
||||
}(ddl.IsEmulatorGCEnable())
|
||||
|
||||
// Disable emulator GC.
|
||||
// Otherwise emulator GC will delete table record as soon as possible after execute drop table ddl.
|
||||
ddl.EmulatorGCDisable()
|
||||
gcTimeFormat := "20060102-15:04:05 -0700 MST"
|
||||
timeBeforeDrop := time.Now().Add(0 - 48*60*60*time.Second).Format(gcTimeFormat)
|
||||
safePointSQL := `INSERT HIGH_PRIORITY INTO mysql.tidb VALUES ('tikv_gc_safe_point', '%[1]s', '')
|
||||
ON DUPLICATE KEY
|
||||
UPDATE variable_value = '%[1]s'`
|
||||
// Clear GC variables first.
|
||||
tk.MustExec("delete from mysql.tidb where variable_name in ( 'tikv_gc_safe_point','tikv_gc_enable' )")
|
||||
timeBeforeDrop, _, safePointSQL, resetGC := s.mockGC(tk)
|
||||
defer resetGC()
|
||||
|
||||
// Set GC safe point
|
||||
tk.MustExec(fmt.Sprintf(safePointSQL, timeBeforeDrop))
|
||||
// Set GC enable.
|
||||
@ -5939,6 +5933,23 @@ func (s *testRecoverTable) TestFlashbackTable(c *C) {
|
||||
tk.MustQuery("select a from t order by a").Check(testkit.Rows("1", "2", "3"))
|
||||
}
|
||||
|
||||
func (s *testRecoverTable) TestRecoverTempTable(c *C) {
|
||||
tk := testkit.NewTestKit(c, s.store)
|
||||
tk.MustExec("create database if not exists test_recover")
|
||||
tk.MustExec("use test_recover")
|
||||
tk.MustExec("drop table if exists t_recover")
|
||||
tk.MustExec("create global temporary table t_recover (a int) on commit delete rows;")
|
||||
|
||||
timeBeforeDrop, _, safePointSQL, resetGC := s.mockGC(tk)
|
||||
defer resetGC()
|
||||
// Set GC safe point
|
||||
tk.MustExec(fmt.Sprintf(safePointSQL, timeBeforeDrop))
|
||||
|
||||
tk.MustExec("drop table t_recover")
|
||||
tk.MustGetErrCode("recover table t_recover;", errno.ErrUnsupportedDDLOperation)
|
||||
tk.MustGetErrCode("flashback table t_recover;", errno.ErrUnsupportedDDLOperation)
|
||||
}
|
||||
|
||||
func (s *testSuiteP2) TestPointGetPreparedPlan(c *C) {
|
||||
tk1 := testkit.NewTestKit(c, s.store)
|
||||
tk1.MustExec("drop database if exists ps_text")
|
||||
|
||||
Reference in New Issue
Block a user