diff --git a/planner/optimize.go b/planner/optimize.go index 299f93e4b29ab..83824af121199 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -99,6 +99,16 @@ func matchSQLBinding(sctx sessionctx.Context, stmtNode ast.StmtNode) (bindRecord func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema) (plannercore.Plan, types.NameSlice, error) { sessVars := sctx.GetSessionVars() + if !sctx.GetSessionVars().InRestrictedSQL && variable.RestrictedReadOnly.Load() || variable.VarTiDBSuperReadOnly.Load() { + allowed, err := allowInReadOnlyMode(sctx, node) + if err != nil { + return nil, nil, err + } + if !allowed { + return nil, nil, errors.Trace(core.ErrSQLInReadOnlyMode) + } + } + // Because for write stmt, TiFlash has a different results when lock the data in point get plan. We ban the TiFlash // engine in not read only stmt. if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(node, sessVars) { @@ -351,16 +361,6 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in return nil, nil, 0, err } - if !sctx.GetSessionVars().InRestrictedSQL && variable.RestrictedReadOnly.Load() || variable.VarTiDBSuperReadOnly.Load() { - allowed, err := allowInReadOnlyMode(sctx, node) - if err != nil { - return nil, nil, 0, err - } - if !allowed { - return nil, nil, 0, errors.Trace(core.ErrSQLInReadOnlyMode) - } - } - // Handle the execute statement. if execPlan, ok := p.(*plannercore.Execute); ok { err := execPlan.OptimizePreparedPlan(ctx, sctx, is) diff --git a/tests/readonlytest/readonly_test.go b/tests/readonlytest/readonly_test.go index bf76a8d91e593..bf2f267531788 100644 --- a/tests/readonlytest/readonly_test.go +++ b/tests/readonlytest/readonly_test.go @@ -28,8 +28,8 @@ import ( var ( tidbRootPassword = flag.String("passwd", "", "tidb root password") - tidbAPort = flag.Int("tidb_a_port", 4000, "first tidb server listening port") - tidbBPort = flag.Int("tidb_b_port", 4001, "second tidb server listening port") + tidbAPort = flag.Int("tidb_a_port", 4001, "first tidb server listening port") + tidbBPort = flag.Int("tidb_b_port", 4002, "second tidb server listening port") ReadOnlyErrMsg = "Error 1836: Running in read-only mode" ConflictErrMsg = "Error 1105: can't turn off tidb_super_read_only when tidb_restricted_read_only is on" PriviledgedErrMsg = "Error 1227: Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation" @@ -107,8 +107,18 @@ func createReadOnlySuite(t *testing.T) (s *ReadOnlySuite, clean func()) { func TestRestriction(t *testing.T) { s, clean := createReadOnlySuite(t) defer clean() - setVariable(t, s.db, TiDBRestrictedReadOnly, 1) + var err error + _, err = s.db.Exec("drop table if exists t") + require.NoError(t, err) + _, err = s.udb.Exec("create table t (a int primary key, b int)") + require.NoError(t, err) + _, err = s.udb.Exec("insert into t values (1, 1)") + require.NoError(t, err) + _, err = s.udb.Exec("update t set b = 2 where a = 1") + require.NoError(t, err) + + setVariable(t, s.db, TiDBRestrictedReadOnly, 1) time.Sleep(1) checkVariable(t, s.udb, TiDBRestrictedReadOnly, true) @@ -117,7 +127,18 @@ func TestRestriction(t *testing.T) { checkVariable(t, s.rdb, TiDBRestrictedReadOnly, true) checkVariable(t, s.rdb, TiDBSuperReadOnly, true) - _, err := s.udb.Exec("create table t(a int)") + // can't create table + _, err = s.udb.Exec("create table t(a int)") + require.Error(t, err) + require.Equal(t, err.Error(), ReadOnlyErrMsg) + + // can't do point update when tidb_restricted_read_only is on + _, err = s.udb.Exec("update t set b = 2 where a = 1") + require.Error(t, err) + require.Equal(t, err.Error(), ReadOnlyErrMsg) + + // can't insert + _, err = s.udb.Exec("insert into t values (2, 3)") require.Error(t, err) require.Equal(t, err.Error(), ReadOnlyErrMsg)