Skip to content

Commit

Permalink
Merge branch 'master' into close_more_recordset
Browse files Browse the repository at this point in the history
  • Loading branch information
hawkingrei authored Dec 9, 2022
2 parents f23a664 + c19adff commit 960c5bc
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 17 deletions.
18 changes: 18 additions & 0 deletions executor/fktest/foreign_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2521,3 +2521,21 @@ func TestTableLockInForeignKeyCascade(t *testing.T) {
tk.MustQuery("select * from t1 order by id").Check(testkit.Rows("2", "3"))
tk.MustQuery("select * from t2 order by id").Check(testkit.Rows("2", "3"))
}

func TestForeignKeyIssue39732(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("set @@global.tidb_enable_stmt_summary=1")
tk.MustExec("set @@foreign_key_checks=1")
tk.MustExec("use test")
tk.MustExec("create user 'u1'@'%' identified by '';")
tk.MustExec("GRANT ALL PRIVILEGES ON *.* TO 'u1'@'%'")
err := tk.Session().Auth(&auth.UserIdentity{Username: "u1", Hostname: "localhost", CurrentUser: true, AuthUsername: "u1", AuthHostname: "%"}, nil, []byte("012345678901234567890"))
require.NoError(t, err)
tk.MustExec("create table t1 (id int key, leader int, index(leader), foreign key (leader) references t1(id) ON DELETE CASCADE);")
tk.MustExec("insert into t1 values (1, null), (10, 1), (11, 1), (20, 10)")
tk.MustExec(`prepare stmt1 from 'delete from t1 where id = ?';`)
tk.MustExec(`set @a = 1;`)
tk.MustExec("execute stmt1 using @a;")
tk.MustQuery("select * from t1 order by id").Check(testkit.Rows())
}
13 changes: 3 additions & 10 deletions planner/core/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func EncodeFlatPlan(flat *FlatPhysicalPlan) string {
return ""
}
failpoint.Inject("mockPlanRowCount", func(val failpoint.Value) {
selectPlan := flat.Main.GetSelectPlan()
selectPlan, _ := flat.Main.GetSelectPlan()
for _, op := range selectPlan {
op.Origin.statsInfo().RowCount = float64(val.(int))
}
Expand Down Expand Up @@ -262,7 +262,7 @@ type planDigester struct {

// NormalizeFlatPlan normalizes a FlatPhysicalPlan and generates plan digest.
func NormalizeFlatPlan(flat *FlatPhysicalPlan) (normalized string, digest *parser.Digest) {
selectPlan := flat.Main.GetSelectPlan()
selectPlan, selectPlanOffset := flat.Main.GetSelectPlan()
if len(selectPlan) == 0 || !selectPlan[0].IsPhysicalPlan {
return "", parser.NewDigest(nil)
}
Expand All @@ -274,18 +274,11 @@ func NormalizeFlatPlan(flat *FlatPhysicalPlan) (normalized string, digest *parse
}()
// assume an operator costs around 30 bytes, preallocate space for them
d.buf.Grow(30 * len(selectPlan))
depthOffset := len(flat.Main) - len(selectPlan)
loop1:
for _, op := range selectPlan {
switch op.Origin.(type) {
case *FKCheck, *FKCascade:
// Generate plan digest doesn't need to contain the foreign key check/cascade plan, so just break the loop.
break loop1
}
taskTypeInfo := plancodec.EncodeTaskTypeForNormalize(op.IsRoot, op.StoreType)
p := op.Origin.(PhysicalPlan)
plancodec.NormalizePlanNode(
int(op.Depth-uint32(depthOffset)),
int(op.Depth-uint32(selectPlanOffset)),
op.Origin.TP(),
taskTypeInfo,
p.ExplainNormalizedInfo(),
Expand Down
23 changes: 17 additions & 6 deletions planner/core/flat_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,34 @@ type FlatPhysicalPlan struct {
// depth-first traversal plus some special rule for some operators.
type FlatPlanTree []*FlatOperator

// GetSelectPlan skips Insert, Delete and Update at the beginning of the FlatPlanTree.
// GetSelectPlan skips Insert, Delete, and Update at the beginning of the FlatPlanTree and the foreign key check/cascade plan at the end of the FlatPlanTree.
// Note:
//
// It returns a reference to the original FlatPlanTree, please avoid modifying the returned value.
// Since you get a part of the original slice, you need to adjust the FlatOperator.Depth and FlatOperator.ChildrenIdx when using them.
func (e FlatPlanTree) GetSelectPlan() FlatPlanTree {
// The second return value is the offset. Because the returned FlatPlanTree is a part of the original slice, you need to minus them by the offset when using the returned FlatOperator.Depth and FlatOperator.ChildrenIdx.
func (e FlatPlanTree) GetSelectPlan() (FlatPlanTree, int) {
if len(e) == 0 {
return nil
return nil, 0
}
hasDML := false
for i, op := range e {
switch op.Origin.(type) {
case *Insert, *Delete, *Update:
hasDML = true
default:
return e[i:]
if hasDML {
for j := i; j < len(e); j++ {
switch e[j].Origin.(type) {
case *FKCheck, *FKCascade:
// The later plans are belong to foreign key check/cascade plans, doesn't belong to select plan, just skip it.
return e[i:j], i
}
}
}
return e[i:], i
}
}
return nil
return nil, 0
}

// FlatOperator is a simplified operator.
Expand Down
2 changes: 1 addition & 1 deletion planner/core/hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func GenHintsFromFlatPlan(flat *FlatPhysicalPlan) []*ast.TableOptimizerHint {
nodeTp = utilhint.TypeDelete
}
var hints []*ast.TableOptimizerHint
selectPlan := flat.Main.GetSelectPlan()
selectPlan, _ := flat.Main.GetSelectPlan()
if len(selectPlan) == 0 || !selectPlan[0].IsPhysicalPlan {
return nil
}
Expand Down
2 changes: 2 additions & 0 deletions planner/core/plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ func TestNormalizedPlan(t *testing.T) {
newNormalized, newDigest := core.NormalizeFlatPlan(flat)
require.Equal(t, normalized, newNormalized)
require.Equal(t, digest, newDigest)
// Test for GenHintsFromFlatPlan won't panic.
core.GenHintsFromFlatPlan(flat)

normalizedPlan, err := plancodec.DecodeNormalizedPlan(normalized)
normalizedPlanRows := getPlanRows(normalizedPlan)
Expand Down

0 comments on commit 960c5bc

Please sign in to comment.