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

planner: fix tidb can point update data even if tidb_super_read_only is on (#32547) #32551

Merged
merged 7 commits into from
Feb 23, 2022
Merged
20 changes: 10 additions & 10 deletions planner/optimize.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ func GetExecuteForUpdateReadIS(node ast.Node, sctx sessionctx.Context) infoschem
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) {
Expand Down Expand Up @@ -355,16 +365,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)
Expand Down
29 changes: 25 additions & 4 deletions tests/readonlytest/readonly_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand All @@ -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)

Expand Down