Skip to content

Commit

Permalink
add unique testcase
Browse files Browse the repository at this point in the history
  • Loading branch information
Yisaer committed Nov 29, 2022
1 parent 2453692 commit fcc9b0c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 31 deletions.
89 changes: 60 additions & 29 deletions planner/core/find_best_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -914,8 +914,10 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
}

// if the path is the point get range path with for update lock, we should forbid tiflash as it's store path.
if path.StoreType == kv.TiFlash && ds.isPointGetPath(path) && ds.isForUpdateRead {
continue
if path.StoreType == kv.TiFlash && ds.isForUpdateRead {
if ds.isPointGetConditions() {
continue
}
}

canConvertPointGet := len(path.Ranges) > 0 && path.StoreType == kv.TiKV && ds.isPointGetConvertableSchema()
Expand Down Expand Up @@ -1058,33 +1060,6 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
return
}

func (ds *DataSource) isPointGetPath(path *util.AccessPath) bool {
if len(path.Ranges) < 1 {
return false
}
for _, ran := range path.Ranges {
if !ran.IsPointNonNullable(ds.ctx) {
return false
}
}
if path.IsIntHandlePath {
return true
}
if path.Index == nil {
return false
}
if path.Index.HasPrefixIndex() || !path.Index.Unique {
return false
}
idxColsLen := len(path.Index.Columns)
for _, ran := range path.Ranges {
if len(ran.LowVal) != idxColsLen {
return false
}
}
return true
}

func (ds *DataSource) canConvertToPointGetForPlanCache(path *util.AccessPath) bool {
// PointGet might contain some over-optimized assumptions, like `a>=1 and a<=1` --> `a=1`, but
// these assumptions may be broken after parameters change.
Expand Down Expand Up @@ -1936,6 +1911,62 @@ func (s *LogicalIndexScan) GetPhysicalIndexScan(_ *expression.Schema, stats *pro
return is
}

func (ds *DataSource) isPointGetConditions() bool {
t, _ := ds.is.TableByID(ds.physicalTableID)
columns := map[string]struct{}{}
for _, cond := range ds.allConds {
s, ok := cond.(*expression.ScalarFunction)
if !ok {
return false
}
if s.FuncName.L != ast.EQ || (s.FuncName.L == ast.In && len(s.GetArgs()) != 2) {
return false
}
arg0 := s.GetArgs()[0]
arg1 := s.GetArgs()[1]
_, ok1 := arg0.(*expression.Constant)
col, ok2 := arg1.(*expression.Column)
if ok1 && ok2 {
columns[t.Meta().FindColumnNameByID(col.ID)] = struct{}{}
continue
}
col, ok1 = arg0.(*expression.Column)
_, ok2 = arg1.(*expression.Constant)
if ok1 && ok2 {
columns[t.Meta().FindColumnNameByID(col.ID)] = struct{}{}
continue
}
}
return ds.findPKOrUniqueIndexMatchColumns(columns)
}

func (ds *DataSource) findPKOrUniqueIndexMatchColumns(columns map[string]struct{}) bool {
for _, idx := range ds.tableInfo.Indices {
if !idx.Unique && !idx.Primary {
continue
}
if idx.HasPrefixIndex() {
continue
}
if len(idx.Columns) != len(columns) {
continue
}
flag := true
for _, idxCol := range idx.Columns {
_, ok := columns[idxCol.Name.String()]
if !ok {
flag = false
break
}
}
if !flag {
continue
}
return true
}
return false
}

// convertToTableScan converts the DataSource to table scan.
func (ds *DataSource) convertToTableScan(prop *property.PhysicalProperty, candidate *candidatePath, _ *physicalOptimizeOp) (task task, err error) {
// It will be handled in convertToIndexScan.
Expand Down
12 changes: 10 additions & 2 deletions planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7558,19 +7558,27 @@ func TestPointGetWithSelectLock(t *testing.T) {
store, dom := testkit.CreateMockStoreAndDomain(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table t(a int, b int, c int, primary key(a, b));")
tk.MustExec("insert into t values(1,2,3), (4,5,6);")
tk.MustExec("create table t(a int, b int, primary key(a, b));")
tk.MustExec("create table t1(c int unique, d int);")
tbl, err := dom.InfoSchema().TableByName(model.CIStr{O: "test", L: "test"}, model.CIStr{O: "t", L: "t"})
require.NoError(t, err)
// Set the hacked TiFlash replica for explain tests.
tbl.Meta().TiFlashReplica = &model.TiFlashReplicaInfo{Count: 1, Available: true}
tbl1, err := dom.InfoSchema().TableByName(model.CIStr{O: "test", L: "test"}, model.CIStr{O: "t1", L: "t1"})
require.NoError(t, err)
// Set the hacked TiFlash replica for explain tests.
tbl1.Meta().TiFlashReplica = &model.TiFlashReplicaInfo{Count: 1, Available: true}

tk.MustExec("set @@tidb_enable_tiflash_read_for_write_stmt = on;")
tk.MustExec("set @@tidb_isolation_read_engines='tidb,tiflash';")
tk.MustExec("begin;")
tk.MustGetErrMsg("explain select a, b from t where a = 1 and b = 2 for update;", "[planner:1815]Internal : Can't find a proper physical plan for this query")
tk.MustGetErrMsg("explain select c, d from t1 where c = 1 for update;", "[planner:1815]Internal : Can't find a proper physical plan for this query")
tk.MustQuery("explain select a, b from t where a = 1 for update;")
tk.MustQuery("explain select c, d from t1 where c = 1 and d = 1 for update;")
tk.MustExec("set tidb_isolation_read_engines='tidb,tikv,tiflash';")
tk.MustQuery("explain select a, b from t where a = 1 and b = 2 for update;")
tk.MustQuery("explain select c, d from t1 where c = 1 for update;")
tk.MustExec("commit")
}

Expand Down

0 comments on commit fcc9b0c

Please sign in to comment.