Skip to content

Commit c7fde05

Browse files
authored
planner: add more test cases for plan cache (#56380)
ref #54057
1 parent 828b461 commit c7fde05

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed

pkg/planner/core/casetest/instanceplancache/BUILD.bazel

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ go_test(
99
"others_test.go",
1010
],
1111
flaky = True,
12-
shard_count = 9,
13-
deps = ["//pkg/testkit"],
12+
shard_count = 12,
13+
deps = [
14+
"//pkg/parser/auth",
15+
"//pkg/testkit",
16+
"@com_github_stretchr_testify//require",
17+
],
1418
)

pkg/planner/core/casetest/instanceplancache/others_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ import (
1919
"testing"
2020
"time"
2121

22+
"github.com/pingcap/tidb/pkg/parser/auth"
2223
"github.com/pingcap/tidb/pkg/testkit"
24+
"github.com/stretchr/testify/require"
2325
)
2426

2527
func TestInstancePlanCacheVars(t *testing.T) {
@@ -231,3 +233,100 @@ func TestInstancePlanCacheSchemaChange(t *testing.T) {
231233
tk.MustExec(`execute st`)
232234
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
233235
}
236+
237+
func TestInstancePlanCachePrivilegeChanges(t *testing.T) {
238+
store := testkit.CreateMockStore(t)
239+
tk := testkit.NewTestKit(t, store)
240+
tk.MustExec(`use test`)
241+
tk.MustExec(`set global tidb_enable_instance_plan_cache=1`)
242+
243+
tk.MustExec(`create table t (a int, primary key(a))`)
244+
tk.MustExec(`CREATE USER 'u1'`)
245+
tk.MustExec(`grant select on test.t to 'u1'`)
246+
247+
u1 := testkit.NewTestKit(t, store)
248+
require.NoError(t, u1.Session().Auth(&auth.UserIdentity{Username: "u1", Hostname: "%"}, nil, nil, nil))
249+
250+
u1.MustExec(`prepare st from 'select a from test.t where a<1'`)
251+
u1.MustExec(`execute st`)
252+
u1.MustExec(`execute st`)
253+
u1.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
254+
255+
tk.MustExec(`revoke select on test.t from 'u1'`)
256+
u1.MustExecToErr(`execute st`) // no privilege
257+
258+
tk.MustExec(`grant select on test.t to 'u1'`)
259+
u1.MustExec(`execute st`)
260+
u1.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) // hit the cache again
261+
}
262+
263+
func TestInstancePlanCacheDifferentUsers(t *testing.T) {
264+
store := testkit.CreateMockStore(t)
265+
tk := testkit.NewTestKit(t, store)
266+
tk.MustExec(`use test`)
267+
tk.MustExec(`set global tidb_enable_instance_plan_cache=1`)
268+
269+
tk.MustExec(`create table t (a int, primary key(a))`)
270+
tk.MustExec(`CREATE USER 'u1'`)
271+
tk.MustExec(`grant select on test.t to 'u1'`)
272+
tk.MustExec(`CREATE USER 'u1'@'localhost'`)
273+
tk.MustExec(`grant select on test.t to 'u1'@'localhost'`)
274+
tk.MustExec(`CREATE USER 'u2'`)
275+
tk.MustExec(`grant select on test.t to 'u2'`)
276+
277+
u1 := testkit.NewTestKit(t, store)
278+
require.NoError(t, u1.Session().Auth(&auth.UserIdentity{Username: "u1", Hostname: "%"}, nil, nil, nil))
279+
u1Local := testkit.NewTestKit(t, store)
280+
require.NoError(t, u1Local.Session().Auth(&auth.UserIdentity{Username: "u1", Hostname: "localhost"}, nil, nil, nil))
281+
u2 := testkit.NewTestKit(t, store)
282+
require.NoError(t, u2.Session().Auth(&auth.UserIdentity{Username: "u2", Hostname: "%"}, nil, nil, nil))
283+
u1Dup := testkit.NewTestKit(t, store)
284+
require.NoError(t, u1Dup.Session().Auth(&auth.UserIdentity{Username: "u1", Hostname: "%"}, nil, nil, nil))
285+
286+
u1.MustExec(`prepare st from 'select a from test.t where a=1'`)
287+
u1.MustExec(`execute st`)
288+
u1.MustExec(`execute st`)
289+
u1.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
290+
291+
u1Local.MustExec(`prepare st from 'select a from test.t where a=1'`)
292+
u1Local.MustExec(`execute st`)
293+
u1Local.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) // can't hit, different localhost
294+
u1Local.MustExec(`execute st`)
295+
u1Local.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
296+
297+
u2.MustExec(`prepare st from 'select a from test.t where a=1'`)
298+
u2.MustExec(`execute st`)
299+
u2.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) // can't hit, different user
300+
u2.MustExec(`execute st`)
301+
u2.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
302+
303+
u1Dup.MustExec(`prepare st from 'select a from test.t where a=1'`)
304+
u1Dup.MustExec(`execute st`)
305+
u1Dup.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) // can hit, same user and localhost
306+
u1Dup.MustExec(`execute st`)
307+
u1Dup.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
308+
}
309+
310+
func TestInstancePlanCachePartitioning(t *testing.T) {
311+
store := testkit.CreateMockStore(t)
312+
tk := testkit.NewTestKit(t, store)
313+
tk.MustExec("use test")
314+
tk.MustExec(`set global tidb_enable_instance_plan_cache=1`)
315+
tk.MustExec(`set @@tidb_partition_prune_mode='dynamic'`)
316+
317+
tk.MustExec(`create table t (a int, b varchar(255)) partition by hash(a) partitions 3`)
318+
tk.MustExec(`insert into t values (1,"a"),(2,"b"),(3,"c"),(4,"d"),(5,"e"),(6,"f")`)
319+
tk.MustExec(`prepare stmt from 'select a,b from t where a = ?;'`)
320+
tk.MustExec(`set @a=1`)
321+
tk.MustQuery(`execute stmt using @a`).Check(testkit.Rows("1 a"))
322+
// Same partition works, due to pruning is not affected
323+
tk.MustExec(`set @a=4`)
324+
tk.MustQuery(`execute stmt using @a`).Check(testkit.Rows("4 d"))
325+
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
326+
327+
tk.MustExec(`set @@tidb_partition_prune_mode='static'`)
328+
tk.MustQuery(`execute stmt using @a`).Check(testkit.Rows("4 d"))
329+
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))
330+
tk.MustQuery(`execute stmt using @a`).Check(testkit.Rows("4 d"))
331+
tk.MustQuery(`show warnings`).Check(testkit.Rows("Warning 1105 skip prepared plan-cache: Static partition pruning mode"))
332+
}

pkg/planner/core/plan_cache_utils.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,24 @@ func NewPlanCacheKey(sctx sessionctx.Context, stmt *PlanCacheStmt) (key, binding
294294
}
295295
_, connCollation := vars.GetCharsetInfo()
296296

297+
// not allow to share the same plan among different users for safety.
298+
var userName, hostName string
299+
if sctx.GetSessionVars().User != nil { // might be nil if in test
300+
userName = sctx.GetSessionVars().User.AuthUsername
301+
hostName = sctx.GetSessionVars().User.AuthHostname
302+
}
303+
304+
// the user might switch the prune mode dynamically
305+
pruneMode := sctx.GetSessionVars().PartitionPruneMode.Load()
306+
297307
hash := make([]byte, 0, len(stmt.StmtText)*2) // TODO: a Pool for this
308+
hash = append(hash, hack.Slice(userName)...)
309+
hash = append(hash, hack.Slice(hostName)...)
298310
hash = append(hash, hack.Slice(stmtDB)...)
299311
hash = append(hash, hack.Slice(stmt.StmtText)...)
300312
hash = codec.EncodeInt(hash, stmt.SchemaVersion)
301313
hash = hashInt64Uint64Map(hash, stmt.RelateVersion)
314+
hash = append(hash, pruneMode...)
302315
// Only be set in rc or for update read and leave it default otherwise.
303316
// In Rc or ForUpdateRead, we should check whether the information schema has been changed when using plan cache.
304317
// If it changed, we should rebuild the plan. lastUpdatedSchemaVersion help us to decide whether we should rebuild

0 commit comments

Comments
 (0)