Skip to content

Commit

Permalink
planner: fix the issue that bindings with query-level hint can not ta…
Browse files Browse the repository at this point in the history
…ke effect for replace statements (#54048)

close #53834
  • Loading branch information
qw4990 committed Jun 18, 2024
1 parent 2cea994 commit 01a4573
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 5 deletions.
20 changes: 20 additions & 0 deletions pkg/bindinfo/session_handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package bindinfo_test

import (
"context"
"fmt"
"strconv"
"testing"
"time"
Expand Down Expand Up @@ -381,6 +382,25 @@ func TestDropSingleBindings(t *testing.T) {
tk.MustExec("drop table t")
}

func TestIssue53834(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec(`use test`)
tk.MustExec(`create table t (a varchar(1024))`)
tk.MustExec(`insert into t values (space(1024))`)
for i := 0; i < 12; i++ {
tk.MustExec(`insert into t select * from t`)
}
oomAction := tk.MustQuery(`select @@tidb_mem_oom_action`).Rows()[0][0].(string)
defer func() {
tk.MustExec(fmt.Sprintf(`set global tidb_mem_oom_action='%v'`, oomAction))
}()
tk.MustExec(`set global tidb_mem_oom_action='cancel'`)
tk.MustExec(`create binding using replace into t select /*+ memory_quota(1 mb) */ * from t`)
err := tk.ExecToErr(`replace into t select * from t`)
require.ErrorContains(t, err, "cancelled due to exceeding the allowed memory limit")
}

func TestPreparedStmt(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
Expand Down
2 changes: 1 addition & 1 deletion pkg/planner/optimize.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in
core.DebugTraceTryBinding(pctx, binding.Hint)
}
hint.BindHint(stmtNode, binding.Hint)
curStmtHints, _, curWarns := hint.ParseStmtHints(binding.Hint.GetFirstTableHints(), setVarHintChecker, byte(kv.ReplicaReadFollower))
curStmtHints, _, curWarns := hint.ParseStmtHints(binding.Hint.GetStmtHints(), setVarHintChecker, byte(kv.ReplicaReadFollower))
sessVars.StmtCtx.StmtHints = curStmtHints
// update session var by hint /set_var/
for name, val := range sessVars.StmtCtx.StmtHints.SetVars {
Expand Down
10 changes: 10 additions & 0 deletions pkg/util/hint/hint.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,16 @@ func ParseStmtHints(hints []*ast.TableOptimizerHint,
return
}

// isStmtHint checks whether this hint is a statement-level hint.
func isStmtHint(h *ast.TableOptimizerHint) bool {
switch h.HintName.L {
case "max_execution_time", "memory_quota", "resource_group":
return true
default:
return false
}
}

// IndexJoinHints stores hint information about index nested loop join.
type IndexJoinHints struct {
INLJTables []HintedTable
Expand Down
16 changes: 12 additions & 4 deletions pkg/util/hint/hint_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,20 @@ type HintsSet struct {
indexHints [][]*ast.IndexHint // Slice offset is the traversal order of `TableName` in the ast.
}

// GetFirstTableHints gets the first table hints.
func (hs *HintsSet) GetFirstTableHints() []*ast.TableOptimizerHint {
// GetStmtHints gets all statement-level hints.
func (hs *HintsSet) GetStmtHints() []*ast.TableOptimizerHint {
var result []*ast.TableOptimizerHint
if len(hs.tableHints) > 0 {
return hs.tableHints[0]
result = append(result, hs.tableHints[0]...) // keep the same behavior with prior implementation
}
return nil
for _, tHints := range hs.tableHints[1:] {
for _, h := range tHints {
if isStmtHint(h) {
result = append(result, h)
}
}
}
return result
}

// ContainTableHint checks whether the table hint set contains a hint.
Expand Down

0 comments on commit 01a4573

Please sign in to comment.