Skip to content

Commit

Permalink
Merge branch 'master' into dayofweek_year
Browse files Browse the repository at this point in the history
  • Loading branch information
gengliqi authored Mar 16, 2022
2 parents e4a99b3 + 93d44e2 commit 64b8953
Show file tree
Hide file tree
Showing 12 changed files with 392 additions and 4 deletions.
7 changes: 7 additions & 0 deletions bindinfo/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,10 @@ func TestSPMHitInfo(t *testing.T) {
require.True(t, tk.HasPlan("SELECT * from t1,t2 where t1.id = t2.id", "MergeJoin"))
tk.MustExec("SELECT * from t1,t2 where t1.id = t2.id")
tk.MustQuery(`select @@last_plan_from_binding;`).Check(testkit.Rows("1"))
tk.MustExec("set binding disabled for SELECT * from t1,t2 where t1.id = t2.id")
tk.MustExec("SELECT * from t1,t2 where t1.id = t2.id")
tk.MustQuery(`select @@last_plan_from_binding;`).Check(testkit.Rows("0"))

tk.MustExec("drop global binding for SELECT * from t1,t2 where t1.id = t2.id")
}

Expand Down Expand Up @@ -1165,6 +1169,9 @@ func TestSPMWithoutUseDatabase(t *testing.T) {
require.True(t, tk1.MustUseIndex("select * from test.t", "a"))
tk1.MustExec("select * from test.t")
tk1.MustQuery(`select @@last_plan_from_binding;`).Check(testkit.Rows("1"))
tk1.MustExec("set binding disabled for select * from test.t")
tk1.MustExec("select * from test.t")
tk1.MustQuery(`select @@last_plan_from_binding;`).Check(testkit.Rows("0"))
}

func TestBindingWithoutCharset(t *testing.T) {
Expand Down
60 changes: 60 additions & 0 deletions bindinfo/capture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,66 @@ func TestCapturePlanBaseline(t *testing.T) {
require.Equal(t, "SELECT /*+ use_index(@`sel_1` `test`.`t` )*/ * FROM `test`.`t` WHERE `a` > 10", rows[0][1])
}

func TestCapturePlanBaseline4DisabledStatus(t *testing.T) {
store, dom, clean := testkit.CreateMockStoreAndDomain(t)
defer clean()

tk := testkit.NewTestKit(t, store)

utilCleanBindingEnv(tk, dom)
stmtsummary.StmtSummaryByDigestMap.Clear()
tk.MustExec("SET GLOBAL tidb_capture_plan_baselines = on")
defer func() {
tk.MustExec("SET GLOBAL tidb_capture_plan_baselines = off")
}()
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int, index idx_a(a))")
dom.BindHandle().CaptureBaselines()
tk.MustQuery("show global bindings").Check(testkit.Rows())
tk.MustExec("select /*+ USE_INDEX(t, idx_a) */ * from t where a > 10")
tk.MustExec("select /*+ USE_INDEX(t, idx_a) */ * from t where a > 10")
tk.MustExec("admin capture bindings")
rows := tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 0)

require.True(t, tk.Session().Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil))
tk.MustExec("select * from t where a > 10")
tk.MustExec("select * from t where a > 10")
tk.MustExec("admin capture bindings")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Enabled, rows[0][3])
require.Equal(t, bindinfo.Capture, rows[0][8])

tk.MustExec("select * from t where a > 10")
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("1"))

tk.MustExec("set binding disabled for select * from t where a > 10")

tk.MustExec("select * from t where a > 10")
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("0"))
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Disabled, rows[0][3])

tk.MustExec("select * from t where a > 10")
tk.MustExec("select * from t where a > 10")
tk.MustExec("admin capture bindings")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Disabled, rows[0][3])

tk.MustExec("select * from t where a > 10")
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("0"))

tk.MustExec("drop global binding for select * from t where a > 10")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 0)

utilCleanBindingEnv(tk, dom)
}

func TestCaptureDBCaseSensitivity(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
Expand Down
86 changes: 86 additions & 0 deletions bindinfo/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,92 @@ func (h *BindHandle) DropBindRecord(originalSQL, db string, binding *Binding) (e
return err
}

// SetBindRecordStatus set a BindRecord's status to the storage and bind cache.
func (h *BindHandle) SetBindRecordStatus(originalSQL string, binding *Binding, newStatus string) (ok bool, err error) {
h.bindInfo.Lock()
h.sctx.Lock()
defer func() {
h.sctx.Unlock()
h.bindInfo.Unlock()
}()
exec, _ := h.sctx.Context.(sqlexec.SQLExecutor)
_, err = exec.ExecuteInternal(context.TODO(), "BEGIN PESSIMISTIC")
if err != nil {
return
}
var (
updateTs types.Time
oldStatus0, oldStatus1 string
affectRows int
)
if newStatus == Disabled {
// For compatibility reasons, when we need to 'set binding disabled for <stmt>',
// we need to consider both the 'enabled' and 'using' status.
oldStatus0 = Using
oldStatus1 = Enabled
} else if newStatus == Enabled {
// In order to unify the code, two identical old statuses are set.
oldStatus0 = Disabled
oldStatus1 = Disabled
}
defer func() {
if err != nil {
_, err1 := exec.ExecuteInternal(context.TODO(), "ROLLBACK")
terror.Log(err1)
return
}

_, err = exec.ExecuteInternal(context.TODO(), "COMMIT")
if err != nil {
return
}
if affectRows == 0 {
return
}

// The set binding status operation is success.
ok = true
record := &BindRecord{OriginalSQL: originalSQL}
sqlDigest := parser.DigestNormalized(record.OriginalSQL)
oldRecord := h.GetBindRecord(sqlDigest.String(), originalSQL, "")
setBindingStatusInCacheSucc := false
if oldRecord != nil && len(oldRecord.Bindings) > 0 {
record.Bindings = make([]Binding, len(oldRecord.Bindings))
copy(record.Bindings, oldRecord.Bindings)
for ind, oldBinding := range record.Bindings {
if oldBinding.Status == oldStatus0 || oldBinding.Status == oldStatus1 {
if binding == nil || (binding != nil && oldBinding.isSame(binding)) {
setBindingStatusInCacheSucc = true
record.Bindings[ind].Status = newStatus
record.Bindings[ind].UpdateTime = updateTs
}
}
}
}
if setBindingStatusInCacheSucc {
h.setBindRecord(sqlDigest.String(), record)
}
}()

// Lock mysql.bind_info to synchronize with SetBindingStatus on other tidb instances.
if err = h.lockBindInfoTable(); err != nil {
return
}

updateTs = types.NewTime(types.FromGoTime(time.Now()), mysql.TypeTimestamp, 3)
updateTsStr := updateTs.String()

if binding == nil {
_, err = exec.ExecuteInternal(context.TODO(), `UPDATE mysql.bind_info SET status = %?, update_time = %? WHERE original_sql = %? AND update_time < %? AND status IN (%?, %?)`,
newStatus, updateTsStr, originalSQL, updateTsStr, oldStatus0, oldStatus1)
} else {
_, err = exec.ExecuteInternal(context.TODO(), `UPDATE mysql.bind_info SET status = %?, update_time = %? WHERE original_sql = %? AND update_time < %? AND bind_sql = %? AND status IN (%?, %?)`,
newStatus, updateTsStr, originalSQL, updateTsStr, binding.BindSQL, oldStatus0, oldStatus1)
}
affectRows = int(h.sctx.Context.GetSessionVars().StmtCtx.AffectedRows())
return
}

// GCBindRecord physically removes the deleted bind records in mysql.bind_info.
func (h *BindHandle) GCBindRecord() (err error) {
h.bindInfo.Lock()
Expand Down
105 changes: 105 additions & 0 deletions bindinfo/handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,111 @@ func TestEvolveInvalidBindings(t *testing.T) {
require.True(t, status == bindinfo.Enabled || status == bindinfo.Rejected)
}

func TestSetBindingStatus(t *testing.T) {
store, _, clean := testkit.CreateMockStoreAndDomain(t)
defer clean()

tk := testkit.NewTestKit(t, store)

tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int, index idx_a(a))")
tk.MustQuery("show global bindings").Check(testkit.Rows())
tk.MustExec("create global binding for select * from t where a > 10 using select /*+ USE_INDEX(t, idx_a) */ * from t where a > 10")
rows := tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Enabled, rows[0][3])
tk.MustExec("select * from t where a > 10")
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("1"))

tk.MustExec("set binding disabled for select * from t where a > 10 using select * from t where a > 10")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 There are no bindings can be set the status. Please check the SQL text"))
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Enabled, rows[0][3])
tk.MustExec("select * from t where a > 10")
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("1"))

tk.MustExec("set binding disabled for select * from t where a > 10")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Disabled, rows[0][3])
tk.MustExec("select * from t where a > 10")
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("0"))

tk.MustExec("set binding enabled for select * from t where a > 10")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Enabled, rows[0][3])

tk.MustExec("set binding disabled for select * from t where a > 10")
tk.MustExec("create global binding for select * from t where a > 10 using select * from t where a > 10")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Enabled, rows[0][3])
tk.MustExec("select * from t where a > 10")
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("1"))

tk.MustExec("set binding disabled for select * from t where a > 10 using select * from t where a > 10")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Disabled, rows[0][3])
tk.MustExec("select * from t where a > 10")
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("0"))

tk.MustExec("set binding enabled for select * from t where a > 10 using select * from t where a > 10")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Enabled, rows[0][3])

tk.MustExec("set binding disabled for select * from t where a > 10 using select * from t where a > 10")
tk.MustExec("drop global binding for select * from t where a > 10 using select * from t where a > 10")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 0)
}

func TestSetBindingStatusWithoutBindingInCache(t *testing.T) {
store, dom, clean := testkit.CreateMockStoreAndDomain(t)
defer clean()

tk := testkit.NewTestKit(t, store)

tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int, index idx_a(a))")
utilCleanBindingEnv(tk, dom)
tk.MustQuery("show global bindings").Check(testkit.Rows())

// Simulate creating bindings on other machines
tk.MustExec("insert into mysql.bind_info values('select * from `test` . `t` where `a` > ?', 'SELECT /*+ USE_INDEX(`t` `idx_a`)*/ * FROM `test`.`t` WHERE `a` > 10', 'test', 'deleted', '2000-01-01 09:00:00', '2000-01-01 09:00:00', '', '','" +
bindinfo.Manual + "')")
tk.MustExec("insert into mysql.bind_info values('select * from `test` . `t` where `a` > ?', 'SELECT /*+ USE_INDEX(`t` `idx_a`)*/ * FROM `test`.`t` WHERE `a` > 10', 'test', 'enabled', '2000-01-02 09:00:00', '2000-01-02 09:00:00', '', '','" +
bindinfo.Manual + "')")
dom.BindHandle().Clear()
tk.MustExec("set binding disabled for select * from t where a > 10")
tk.MustExec("admin reload bindings")
rows := tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Disabled, rows[0][3])

// clear the mysql.bind_info
utilCleanBindingEnv(tk, dom)

// Simulate creating bindings on other machines
tk.MustExec("insert into mysql.bind_info values('select * from `test` . `t` where `a` > ?', 'SELECT * FROM `test`.`t` WHERE `a` > 10', 'test', 'deleted', '2000-01-01 09:00:00', '2000-01-01 09:00:00', '', '','" +
bindinfo.Manual + "')")
tk.MustExec("insert into mysql.bind_info values('select * from `test` . `t` where `a` > ?', 'SELECT * FROM `test`.`t` WHERE `a` > 10', 'test', 'disabled', '2000-01-02 09:00:00', '2000-01-02 09:00:00', '', '','" +
bindinfo.Manual + "')")
dom.BindHandle().Clear()
tk.MustExec("set binding enabled for select * from t where a > 10")
tk.MustExec("admin reload bindings")
rows = tk.MustQuery("show global bindings").Rows()
require.Len(t, rows, 1)
require.Equal(t, bindinfo.Enabled, rows[0][3])

utilCleanBindingEnv(tk, dom)
}

var testSQLs = []struct {
createSQL string
overlaySQL string
Expand Down
20 changes: 20 additions & 0 deletions executor/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type SQLBindExec struct {
db string
isGlobal bool
bindAst ast.StmtNode
newStatus string
}

// Next implements the Executor Next interface.
Expand All @@ -55,6 +56,8 @@ func (e *SQLBindExec) Next(ctx context.Context, req *chunk.Chunk) error {
return e.evolveBindings()
case plannercore.OpReloadBindings:
return e.reloadBindings()
case plannercore.OpSetBindingStatus:
return e.setBindingStatus()
default:
return errors.Errorf("unsupported SQL bind operation: %v", e.sqlBindOp)
}
Expand All @@ -77,6 +80,23 @@ func (e *SQLBindExec) dropSQLBind() error {
return domain.GetDomain(e.ctx).BindHandle().DropBindRecord(e.normdOrigSQL, e.db, bindInfo)
}

func (e *SQLBindExec) setBindingStatus() error {
var bindInfo *bindinfo.Binding
if e.bindSQL != "" {
bindInfo = &bindinfo.Binding{
BindSQL: e.bindSQL,
Charset: e.charset,
Collation: e.collation,
}
}
ok, err := domain.GetDomain(e.ctx).BindHandle().SetBindRecordStatus(e.normdOrigSQL, bindInfo, e.newStatus)
if err == nil && !ok {
warningMess := errors.New("There are no bindings can be set the status. Please check the SQL text")
e.ctx.GetSessionVars().StmtCtx.AppendWarning(warningMess)
}
return err
}

func (e *SQLBindExec) createSQLBind() error {
// For audit log, SQLBindExec execute "explain" statement internally, save and recover stmtctx
// is necessary to avoid 'create binding' been recorded as 'explain'.
Expand Down
1 change: 1 addition & 0 deletions executor/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4501,6 +4501,7 @@ func (b *executorBuilder) buildSQLBindExec(v *plannercore.SQLBindPlan) Executor
db: v.Db,
isGlobal: v.IsGlobal,
bindAst: v.BindStmt,
newStatus: v.NewStatus,
}
return e
}
Expand Down
8 changes: 4 additions & 4 deletions expression/distsql_builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,10 +668,10 @@ func getSignatureByPB(ctx sessionctx.Context, sigCode tipb.ScalarFuncSig, tp *ti
f = &builtinUUIDSig{base}
case tipb.ScalarFuncSig_LikeSig:
f = &builtinLikeSig{base, nil, false, sync.Once{}}
// case tipb.ScalarFuncSig_RegexpSig:
// f = &builtinRegexpSig{base}
// case tipb.ScalarFuncSig_RegexpUTF8Sig:
// f = &builtinRegexpUTF8Sig{base}
case tipb.ScalarFuncSig_RegexpSig:
f = newBuiltinRegexpSig(base)
case tipb.ScalarFuncSig_RegexpUTF8Sig:
f = newBuiltinRegexpUTF8Sig(base)
case tipb.ScalarFuncSig_JsonExtractSig:
f = &builtinJSONExtractSig{base}
case tipb.ScalarFuncSig_JsonUnquoteSig:
Expand Down
22 changes: 22 additions & 0 deletions expression/distsql_builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,28 @@ func TestPBToExprWithNewCollation(t *testing.T) {
}
}

// Test convert various scalar functions.
func TestPBToScalarFuncExpr(t *testing.T) {
sc := new(stmtctx.StatementContext)
fieldTps := make([]*types.FieldType, 1)
exprs := []*tipb.Expr{
{
Tp: tipb.ExprType_ScalarFunc,
Sig: tipb.ScalarFuncSig_RegexpSig,
FieldType: ToPBFieldType(newStringFieldType()),
},
{
Tp: tipb.ExprType_ScalarFunc,
Sig: tipb.ScalarFuncSig_RegexpUTF8Sig,
FieldType: ToPBFieldType(newStringFieldType()),
},
}
for _, expr := range exprs {
_, err := PBToExpr(expr, fieldTps, sc)
require.NoError(t, err)
}
}

func datumExpr(t *testing.T, d types.Datum) *tipb.Expr {
expr := new(tipb.Expr)
switch d.Kind() {
Expand Down
6 changes: 6 additions & 0 deletions infoschema/cluster_tables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,12 @@ func TestSelectClusterTable(t *testing.T) {
re := tk.MustQuery("select * from `CLUSTER_statements_summary`")
require.NotNil(t, re)
require.Greater(t, len(re.Rows()), 0)
re = tk.MustQuery("select * from `CLUSTER_statements_summary` where table_names REGEXP '\\binformation_schema\\.'")
require.NotNil(t, re)
require.Equal(t, len(re.Rows()), 0)
re = tk.MustQuery("select * from `CLUSTER_statements_summary` where table_names REGEXP 'information_schema\\.'")
require.NotNil(t, re)
require.Greater(t, len(re.Rows()), 0)
// Test for TiDB issue 14915.
re = tk.MustQuery("select sum(exec_count*avg_mem) from cluster_statements_summary_history group by schema_name,digest,digest_text;")
require.NotNil(t, re)
Expand Down
Loading

0 comments on commit 64b8953

Please sign in to comment.