From c3e6c6a73ac697b85b3481c60554ef0382929a51 Mon Sep 17 00:00:00 2001 From: Lynn Date: Mon, 5 Nov 2018 22:45:32 +0800 Subject: [PATCH] cherry-pick]*: add a variable to control whether we can write _tidb_rowid (#8187) --- 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 2517420943feb..5680444463ed5 100644 --- a/executor/insert_common.go +++ b/executor/insert_common.go @@ -106,6 +106,9 @@ func (e *InsertValues) getColumns(tableCols []*table.Column) ([]*table.Column, e } for _, col := range cols { if col.Name.L == model.ExtraHandleName.L { + if !e.ctx.GetSessionVars().AllowWriteRowID { + return nil, 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 de60b92ab8a01..af50997a160ed 100644 --- a/executor/update.go +++ b/executor/update.go @@ -17,6 +17,7 @@ import ( "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/model" + "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/chunk" @@ -45,7 +46,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) } @@ -206,9 +207,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 40afea3b9a4d6..94614c1bbfef7 100644 --- a/sessionctx/variable/session.go +++ b/sessionctx/variable/session.go @@ -252,6 +252,10 @@ type SessionVars struct { // AllowInSubqueryUnFolding can be set to true to fold in subquery AllowInSubqueryUnFolding 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 + // CurrInsertValues is used to record current ValuesExpr's values. // See http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values CurrInsertValues chunk.Row @@ -512,6 +516,8 @@ func (s *SessionVars) SetSystemVar(name string, val string) error { s.AllowAggPushDown = TiDBOptOn(val) case TiDBOptInSubqUnFolding: s.AllowInSubqueryUnFolding = TiDBOptOn(val) + case TiDBOptWriteRowID: + s.AllowWriteRowID = TiDBOptOn(val) case TiDBIndexLookupConcurrency: s.IndexLookupConcurrency = tidbOptPositiveInt32(val, DefIndexLookupConcurrency) case TiDBIndexLookupJoinConcurrency: diff --git a/sessionctx/variable/sysvar.go b/sessionctx/variable/sysvar.go index f3a25e17db457..f38283afff949 100644 --- a/sessionctx/variable/sysvar.go +++ b/sessionctx/variable/sysvar.go @@ -621,6 +621,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 3cb5314d07273..9b249c041bd2d 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" @@ -209,6 +212,7 @@ const ( DefSkipUTF8Check = false DefOptAggPushDown = false DefOptInSubqUnfolding = false + DefOptWriteRowID = false DefBatchInsert = false DefBatchDelete = false DefCurretTS = 0 diff --git a/sessionctx/variable/varsutil_test.go b/sessionctx/variable/varsutil_test.go index 2c2a96a25ea4c..0b9e71d661a3d 100644 --- a/sessionctx/variable/varsutil_test.go +++ b/sessionctx/variable/varsutil_test.go @@ -77,6 +77,7 @@ func (s *testVarsutilSuite) TestNewSessionVars(c *C) { c.Assert(vars.MemQuotaIndexLookupReader, Equals, int64(DefTiDBMemQuotaIndexLookupReader)) c.Assert(vars.MemQuotaIndexLookupJoin, Equals, int64(DefTiDBMemQuotaIndexLookupJoin)) c.Assert(vars.MemQuotaNestedLoopApply, Equals, int64(DefTiDBMemQuotaNestedLoopApply)) + c.Assert(vars.AllowWriteRowID, Equals, DefOptWriteRowID) assertFieldsGreaterThanZero(c, reflect.ValueOf(vars.Concurrency)) assertFieldsGreaterThanZero(c, reflect.ValueOf(vars.MemQuota))