From 58f881ec3d039b4e992db9d96880f5a8648e1952 Mon Sep 17 00:00:00 2001 From: Lynn Date: Mon, 5 Nov 2018 20:57:12 +0800 Subject: [PATCH] exec, sessionctx: add a variable to control whether we can write _tidb_rowid --- executor/insert_common.go | 3 +++ executor/rowid_test.go | 40 ++++++++++++++++++++++++++-- executor/update.go | 8 ++++-- sessionctx/variable/session.go | 6 +++++ sessionctx/variable/sysvar.go | 1 + sessionctx/variable/tidb_vars.go | 4 +++ sessionctx/variable/varsutil_test.go | 1 + 7 files changed, 59 insertions(+), 4 deletions(-) diff --git a/executor/insert_common.go b/executor/insert_common.go index fc935a1030f64..d04adf4c9a343 100644 --- a/executor/insert_common.go +++ b/executor/insert_common.go @@ -112,6 +112,9 @@ func (e *InsertValues) initInsertColumns() error { } for _, col := range cols { if col.Name.L == model.ExtraHandleName.L { + if !e.ctx.GetSessionVars().AllowWriteRowID { + return errors.Errorf("insert, update and replace statements for _tidb_rowid are not supported.") + } e.hasExtraHandle = true break } diff --git a/executor/rowid_test.go b/executor/rowid_test.go index 56a9ac155792f..0e7d8a3d101d8 100644 --- a/executor/rowid_test.go +++ b/executor/rowid_test.go @@ -19,8 +19,12 @@ import ( ) func (s *testSuite) TestExportRowID(c *C) { - tk := testkit.NewTestKit(c, s.store) - tk.MustExec("use test") + tk := testkit.NewTestKitWithInit(c, s.store) + tk.Se.GetSessionVars().AllowWriteRowID = true + defer func() { + tk.Se.GetSessionVars().AllowWriteRowID = false + }() + tk.MustExec("drop table if exists t") tk.MustExec("create table t (a int, b int)") tk.MustExec("insert t values (1, 7), (1, 8), (1, 9)") @@ -49,4 +53,36 @@ func (s *testSuite) TestExportRowID(c *C) { c.Assert(err, NotNil) _, err = tk.Exec("delete from s where _tidb_rowid = 1") c.Assert(err, NotNil) + + // Make sure "AllowWriteRowID" is a session variable. + tk1 := testkit.NewTestKit(c, s.store) + tk1.MustExec("use test") + _, err = tk1.Exec("insert into t (a, _tidb_rowid) values(10, 1);") + c.Assert(err.Error(), Equals, "insert, update and replace statements for _tidb_rowid are not supported.") +} + +func (s *testSuite) TestNotAllowWriteRowID(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("create table tt(id binary(10), c int, primary key(id));") + tk.MustExec("insert tt values (1, 10);") + // select statement + tk.MustQuery("select *, _tidb_rowid from tt"). + Check(testkit.Rows("1\x00\x00\x00\x00\x00\x00\x00\x00\x00 10 1")) + // insert statement + _, err := tk.Exec("insert into tt (id, c, _tidb_rowid) values(30000,10,1);") + c.Assert(err.Error(), Equals, "insert, update and replace statements for _tidb_rowid are not supported.") + // replace statement + _, err = tk.Exec("replace into tt (id, c, _tidb_rowid) values(30000,10,1);") + c.Assert(err.Error(), Equals, "insert, update and replace statements for _tidb_rowid are not supported.") + // update statement + _, err = tk.Exec("update tt set id = 2, _tidb_rowid = 1 where _tidb_rowid = 1") + c.Assert(err.Error(), Equals, "insert, update and replace statements for _tidb_rowid are not supported.") + tk.MustExec("update tt set id = 2 where _tidb_rowid = 1") + tk.MustExec("admin check table tt;") + tk.MustExec("drop table tt") + // There is currently no real support for inserting, updating, and replacing _tidb_rowid statements. + // After we support it, the following operations must be passed. + // tk.MustExec("insert into tt (id, c, _tidb_rowid) values(30000,10,1);") + // tk.MustExec("admin check table tt;") } diff --git a/executor/update.go b/executor/update.go index 0f1db7b120646..d589a05c00570 100644 --- a/executor/update.go +++ b/executor/update.go @@ -18,6 +18,7 @@ import ( "github.com/pingcap/parser/model" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/chunk" @@ -46,7 +47,7 @@ type UpdateExec struct { } func (e *UpdateExec) exec(schema *expression.Schema) ([]types.Datum, error) { - assignFlag, err := e.getUpdateColumns(schema.Len()) + assignFlag, err := e.getUpdateColumns(e.ctx, schema.Len()) if err != nil { return nil, errors.Trace(err) } @@ -230,9 +231,12 @@ func (e *UpdateExec) Open(ctx context.Context) error { return e.SelectExec.Open(ctx) } -func (e *UpdateExec) getUpdateColumns(schemaLen int) ([]bool, error) { +func (e *UpdateExec) getUpdateColumns(ctx sessionctx.Context, schemaLen int) ([]bool, error) { assignFlag := make([]bool, schemaLen) for _, v := range e.OrderedList { + if !ctx.GetSessionVars().AllowWriteRowID && v.Col.ColName.L == model.ExtraHandleName.L { + return nil, errors.Errorf("insert, update and replace statements for _tidb_rowid are not supported.") + } idx := v.Col.Index assignFlag[idx] = true } diff --git a/sessionctx/variable/session.go b/sessionctx/variable/session.go index 2582a375641de..4f983eb3c275f 100644 --- a/sessionctx/variable/session.go +++ b/sessionctx/variable/session.go @@ -254,6 +254,10 @@ type SessionVars struct { // AllowAggPushDown can be set to false to forbid aggregation push down. AllowAggPushDown bool + // AllowWriteRowID can be set to false to forbid write data to _tidb_rowid. + // This variable is currently not recommended to be turned on. + AllowWriteRowID bool + // AllowInSubqToJoinAndAgg can be set to false to forbid rewriting the semi join to inner join with agg. AllowInSubqToJoinAndAgg bool @@ -555,6 +559,8 @@ func (s *SessionVars) SetSystemVar(name string, val string) error { s.SkipUTF8Check = TiDBOptOn(val) case TiDBOptAggPushDown: s.AllowAggPushDown = TiDBOptOn(val) + case TiDBOptWriteRowID: + s.AllowWriteRowID = TiDBOptOn(val) case TiDBOptInSubqToJoinAndAgg: s.AllowInSubqToJoinAndAgg = TiDBOptOn(val) case TiDBIndexLookupConcurrency: diff --git a/sessionctx/variable/sysvar.go b/sessionctx/variable/sysvar.go index 872f9760e0feb..c7bef840ef21e 100644 --- a/sessionctx/variable/sysvar.go +++ b/sessionctx/variable/sysvar.go @@ -622,6 +622,7 @@ var defaultSysVars = []*SysVar{ /* TiDB specific variables */ {ScopeSession, TiDBSnapshot, ""}, {ScopeSession, TiDBOptAggPushDown, boolToIntStr(DefOptAggPushDown)}, + {ScopeSession, TiDBOptWriteRowID, boolToIntStr(DefOptWriteRowID)}, {ScopeGlobal | ScopeSession, TiDBBuildStatsConcurrency, strconv.Itoa(DefBuildStatsConcurrency)}, {ScopeGlobal, TiDBAutoAnalyzeRatio, strconv.FormatFloat(DefAutoAnalyzeRatio, 'f', -1, 64)}, {ScopeGlobal, TiDBAutoAnalyzeStartTime, DefAutoAnalyzeStartTime}, diff --git a/sessionctx/variable/tidb_vars.go b/sessionctx/variable/tidb_vars.go index bd281ab174be5..1010490c5f472 100644 --- a/sessionctx/variable/tidb_vars.go +++ b/sessionctx/variable/tidb_vars.go @@ -41,6 +41,9 @@ const ( // tidb_opt_agg_push_down is used to enable/disable the optimizer rule of aggregation push down. TiDBOptAggPushDown = "tidb_opt_agg_push_down" + // tidb_opt_write_row_id is used to enable/disable the operations of insert、replace and update to _tidb_rowid. + TiDBOptWriteRowID = "tidb_opt_write_row_id" + // Auto analyze will run if (table modify count)/(table row count) is greater than this value. TiDBAutoAnalyzeRatio = "tidb_auto_analyze_ratio" @@ -226,6 +229,7 @@ const ( DefChecksumTableConcurrency = 4 DefSkipUTF8Check = false DefOptAggPushDown = false + DefOptWriteRowID = false DefOptInSubqToJoinAndAgg = true DefBatchInsert = false DefBatchDelete = false diff --git a/sessionctx/variable/varsutil_test.go b/sessionctx/variable/varsutil_test.go index c93ac9911973c..dd0fc336e1c85 100644 --- a/sessionctx/variable/varsutil_test.go +++ b/sessionctx/variable/varsutil_test.go @@ -78,6 +78,7 @@ func (s *testVarsutilSuite) TestNewSessionVars(c *C) { c.Assert(vars.MemQuotaIndexLookupJoin, Equals, int64(DefTiDBMemQuotaIndexLookupJoin)) c.Assert(vars.MemQuotaNestedLoopApply, Equals, int64(DefTiDBMemQuotaNestedLoopApply)) c.Assert(vars.EnableRadixJoin, Equals, DefTiDBUseRadixJoin) + c.Assert(vars.AllowWriteRowID, Equals, DefOptWriteRowID) assertFieldsGreaterThanZero(c, reflect.ValueOf(vars.Concurrency)) assertFieldsGreaterThanZero(c, reflect.ValueOf(vars.MemQuota))