Files
tidb/executor/prepared_test.go

226 lines
8.5 KiB
Go

// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package executor_test
import (
"crypto/tls"
"fmt"
"sync/atomic"
"testing"
"github.com/pingcap/tidb/parser/mysql"
plannercore "github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/session"
txninfo "github.com/pingcap/tidb/session/txninfo"
"github.com/pingcap/tidb/testkit"
"github.com/pingcap/tidb/util"
"github.com/stretchr/testify/require"
)
func TestPreparedNameResolver(t *testing.T) {
t.Parallel()
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (id int, KEY id (id))")
tk.MustExec("prepare stmt from 'select * from t limit ? offset ?'")
_, err := tk.Exec("prepare stmt from 'select b from t'")
require.EqualError(t, err, "[planner:1054]Unknown column 'b' in 'field list'")
_, err = tk.Exec("prepare stmt from '(select * FROM t) union all (select * FROM t) order by a limit ?'")
require.EqualError(t, err, "[planner:1054]Unknown column 'a' in 'order clause'")
}
// a 'create table' DDL statement should be accepted if it has no parameters.
func TestPreparedDDL(t *testing.T) {
t.Parallel()
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("prepare stmt from 'create table t (id int, KEY id (id))'")
}
// TestUnsupportedStmtForPrepare is related to https://github.com/pingcap/tidb/issues/17412
func TestUnsupportedStmtForPrepare(t *testing.T) {
t.Parallel()
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec(`prepare stmt0 from "create table t0(a int primary key)"`)
tk.MustGetErrCode(`prepare stmt1 from "execute stmt0"`, mysql.ErrUnsupportedPs)
tk.MustGetErrCode(`prepare stmt2 from "deallocate prepare stmt0"`, mysql.ErrUnsupportedPs)
tk.MustGetErrCode(`prepare stmt4 from "prepare stmt3 from 'create table t1(a int, b int)'"`, mysql.ErrUnsupportedPs)
}
func TestIgnorePlanCache(t *testing.T) {
t.Parallel()
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (id int primary key, num int)")
tk.MustExec("insert into t values (1, 1)")
tk.MustExec("insert into t values (2, 2)")
tk.MustExec("insert into t values (3, 3)")
tk.MustExec("prepare stmt from 'select /*+ IGNORE_PLAN_CACHE() */ * from t where id=?'")
tk.MustExec("set @ignore_plan_doma = 1")
tk.MustExec("execute stmt using @ignore_plan_doma")
require.False(t, tk.Session().GetSessionVars().StmtCtx.UseCache)
}
type mockSessionManager2 struct {
se session.Session
killed int32
}
func (sm *mockSessionManager2) ShowTxnList() []*txninfo.TxnInfo {
panic("unimplemented!")
}
func (sm *mockSessionManager2) ShowProcessList() map[uint64]*util.ProcessInfo {
pl := make(map[uint64]*util.ProcessInfo)
if pi, ok := sm.GetProcessInfo(0); ok {
pl[pi.ID] = pi
}
return pl
}
func (sm *mockSessionManager2) GetProcessInfo(id uint64) (pi *util.ProcessInfo, notNil bool) {
pi = sm.se.ShowProcess()
if pi != nil {
notNil = true
}
return
}
func (sm *mockSessionManager2) Kill(connectionID uint64, query bool) {
atomic.StoreInt32(&sm.killed, 1)
atomic.StoreUint32(&sm.se.GetSessionVars().Killed, 1)
}
func (sm *mockSessionManager2) KillAllConnections() {}
func (sm *mockSessionManager2) UpdateTLSConfig(cfg *tls.Config) {}
func (sm *mockSessionManager2) ServerID() uint64 {
return 1
}
func TestPreparedStmtWithHint(t *testing.T) {
t.Parallel()
// see https://github.com/pingcap/tidb/issues/18535
store, dom, err := newStoreWithBootstrap()
require.NoError(t, err)
defer func() {
require.NoError(t, store.Close())
dom.Close()
}()
se, err := session.CreateSession4Test(store)
require.NoError(t, err)
tk := testkit.NewTestKit(t, store)
tk.SetSession(se)
sm := &mockSessionManager2{
se: se,
}
se.SetSessionManager(sm)
go dom.ExpensiveQueryHandle().SetSessionManager(sm).Run()
tk.MustExec("prepare stmt from \"select /*+ max_execution_time(100) */ sleep(10)\"")
tk.MustQuery("execute stmt").Check(testkit.Rows("1"))
require.Equal(t, int32(1), atomic.LoadInt32(&sm.killed))
}
func TestIssue29850(t *testing.T) {
store, dom, err := newStoreWithBootstrap()
require.NoError(t, err)
defer func() {
require.NoError(t, store.Close())
dom.Close()
}()
orgEnable := plannercore.PreparedPlanCacheEnabled()
defer func() {
plannercore.SetPreparedPlanCache(orgEnable)
}()
plannercore.SetPreparedPlanCache(true)
tk := testkit.NewTestKit(t, store)
tk.MustExec(`set tidb_enable_clustered_index=on`)
tk.MustExec("set @@tidb_enable_collect_execution_info=0")
tk.MustExec(`use test`)
tk.MustExec(`CREATE TABLE customer (
c_id int(11) NOT NULL,
c_d_id int(11) NOT NULL,
c_first varchar(16) DEFAULT NULL,
c_w_id int(11) NOT NULL,
c_last varchar(16) DEFAULT NULL,
c_credit char(2) DEFAULT NULL,
c_discount decimal(4,4) DEFAULT NULL,
PRIMARY KEY (c_w_id,c_d_id,c_id),
KEY idx_customer (c_w_id,c_d_id,c_last,c_first))`)
tk.MustExec(`CREATE TABLE warehouse (
w_id int(11) NOT NULL,
w_tax decimal(4,4) DEFAULT NULL,
PRIMARY KEY (w_id))`)
tk.MustExec(`prepare stmt from 'SELECT c_discount, c_last, c_credit, w_tax
FROM customer, warehouse
WHERE w_id = ? AND c_w_id = w_id AND c_d_id = ? AND c_id = ?'`)
tk.MustExec(`set @w_id=1262`)
tk.MustExec(`set @c_d_id=7`)
tk.MustExec(`set @c_id=1549`)
tk.MustQuery(`execute stmt using @w_id, @c_d_id, @c_id`).Check(testkit.Rows())
tkProcess := tk.Session().ShowProcess()
ps := []*util.ProcessInfo{tkProcess}
tk.Session().SetSessionManager(&mockSessionManager1{PS: ps})
tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID)).Check(testkit.Rows( // can use PointGet
`Projection_7 0.00 root test.customer.c_discount, test.customer.c_last, test.customer.c_credit, test.warehouse.w_tax`,
`└─MergeJoin_8 0.00 root inner join, left key:test.customer.c_w_id, right key:test.warehouse.w_id`,
` ├─Point_Get_34(Build) 1.00 root table:warehouse handle:1262`,
` └─Point_Get_33(Probe) 1.00 root table:customer, clustered index:PRIMARY(c_w_id, c_d_id, c_id) `))
tk.MustQuery(`execute stmt using @w_id, @c_d_id, @c_id`).Check(testkit.Rows())
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) // can use the cached plan
tk.MustExec(`create table t (a int primary key)`)
tk.MustExec(`insert into t values (1), (2)`)
tk.MustExec(`prepare stmt from 'select * from t where a>=? and a<=?'`)
tk.MustExec(`set @a1=1, @a2=2`)
tk.MustQuery(`execute stmt using @a1, @a1`).Check(testkit.Rows("1"))
tkProcess = tk.Session().ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Session().SetSessionManager(&mockSessionManager1{PS: ps})
tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID)).Check(testkit.Rows( // cannot use PointGet since it contains a range condition
`Selection_7 1.00 root ge(test.t.a, 1), le(test.t.a, 1)`,
`└─TableReader_6 1.00 root data:TableRangeScan_5`,
` └─TableRangeScan_5 1.00 cop[tikv] table:t range:[1,1], keep order:false, stats:pseudo`))
tk.MustQuery(`execute stmt using @a1, @a2`).Check(testkit.Rows("1", "2"))
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
tk.MustExec(`prepare stmt from 'select * from t where a=? or a=?'`)
tk.MustQuery(`execute stmt using @a1, @a1`).Check(testkit.Rows("1"))
tkProcess = tk.Session().ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Session().SetSessionManager(&mockSessionManager1{PS: ps})
tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID)).Check(testkit.Rows( // cannot use PointGet since it contains a or condition
`Selection_7 1.00 root or(eq(test.t.a, 1), eq(test.t.a, 1))`,
`└─TableReader_6 1.00 root data:TableRangeScan_5`,
` └─TableRangeScan_5 1.00 cop[tikv] table:t range:[1,1], keep order:false, stats:pseudo`))
tk.MustQuery(`execute stmt using @a1, @a2`).Check(testkit.Rows("1", "2"))
}