Repository: pingcap/tidb (go)

Issue:
tidb_load_binding_timeout cannot rightly init the default value
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

As the log shows, The duration is ```4.8µs```. it is not expected. and the user doesn't update this value. 

```
{"level":"WARN","time":"2025/06/18 21:54:59.873 +00:00","caller":"binding_cache.go:164","message":"failed to load binding from storage","category":"sql-bind","sqlDigest":"ef7f1cf1ec0c2e0891e40d26dbe1b95d9c517683663b8d0e035ab160126c4c63","error":"load bindings from storage timeout","errorVerbose":"load bindings from storage timeout
github.com/pingcap/tidb/pkg/bindinfo.(*globalBindingHandle).LoadBindingsFromStorage
\t/mnt/tidb/sql/pkg/bindinfo/global_handle.go:713
github.com/pingcap/tidb/pkg/bindinfo.(*fuzzyBindingCache).loadFromStore
\t/mnt/tidb/sql/pkg/bindinfo/binding_cache.go:162
github.com/pingcap/tidb/pkg/bindinfo.(*fuzzyBindingCache).FuzzyMatchingBinding
\t/mnt/tidb/sql/pkg/bindinfo/binding_cache.go:106
github.com/pingcap/tidb/pkg/bindinfo.(*globalBindingHandle).MatchGlobalBinding
\t/mnt/tidb/sql/pkg/bindinfo/global_handle.go:473
github.com/pingcap/tidb/pkg/bindinfo.matchSQLBinding
\t/mnt/tidb/sql/pkg/bindinfo/binding_match.go:89
github.com/pingcap/tidb/pkg/bindinfo.MatchSQLBinding
\t/mnt/tidb/sql/pkg/bindinfo/binding_match.go:53
github.com/pingcap/tidb/pkg/planner.Optimize
\t/mnt/tidb/sql/pkg/planner/optimize.go:220
github.com/pingcap/tidb/pkg/executor.(*Compiler).Compile
\t/mnt/tidb/sql/pkg/executor/compiler.go:104
github.com/pingcap/tidb/pkg/session.(*session).ExecuteStmt
\t/mnt/tidb/sql/pkg/session/session.go:2086
github.com/pingcap/tidb/pkg/server.(*TiDBContext).ExecuteStmt
\t/mnt/tidb/sql/pkg/server/driver_tidb.go:294
github.com/pingcap/tidb/pkg/server.(*clientConn).handleStmt
\t/mnt/tidb/sql/pkg/server/conn.go:2030
github.com/pingcap/tidb/pkg/server.(*clientConn).handleQuery
\t/mnt/tidb/sql/pkg/server/conn.go:1783
github.com/pingcap/tidb/pkg/server.(*clientConn).dispatch
\t/mnt/tidb/sql/pkg/server/conn.go:1357
github.com/pingcap/tidb/pkg/server.(*clientConn).Run
\t/mnt/tidb/sql/pkg/server/conn.go:1127
github.com/pingcap/tidb/pkg/server.(*Server).onConn
\t/mnt/tidb/sql/pkg/server/server.go:740
runtime.goexit
\t/usr/local/go/src/runtime/asm_amd64.s:1650","duration":"4.8µs"}
```

so I add a assert into the problem place and CI report the panic at here. This indicates that there indeed is an issue here.

<img width="924" alt="Image" src="https://github.com/user-attachments/assets/cf06401f-46c9-4b27-98b3-c6254faf7888" />


<!-- a step by step guide for reproducing the bug. -->

### 2. What did you expect to see? (Required)

### 3. What did you see instead (Required)

### 4. What is your TiDB version? (Required)

<!-- Paste the output of SELECT tidb_version() -->



Pull request:
planner: fix uninit timeout for loading bindings
<!--

Thank you for contributing to TiDB!

PR Title Format:
1. pkg [, pkg2, pkg3]: what's changed
2. *: what's changed

-->

### What problem does this PR solve?
<!--

Please create an issue first to describe the problem.

There MUST be one line starting with "Issue Number:  " and
linking the relevant issues via the "close" or "ref".

For more info, check https://pingcap.github.io/tidb-dev-guide/contribute-to-tidb/contribute-code.html#referring-to-an-issue.

-->

Issue Number: close #61889

Problem Summary:

### What changed and how does it work?

as the code show, the old code cannot init the right value for ```tidb_load_binding_timeout```

Currently,this switch is actually ineffective on the master branch.However,to comply with the process standards,it will still be merged into master first.But please refer to [this PR](https://github.com/pingcap/tidb/pull/61881) for the tests.

### Check List

Tests <!-- At least one of them must be included. -->

- [x] Unit test
- [ ] Integration test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test
  > - [ ] I checked and no code files have been changed.
  > <!-- Or your custom  "No need to test" reasons -->

Side effects

- [ ] Performance regression: Consumes more CPU
- [ ] Performance regression: Consumes more Memory
- [ ] Breaking backward compatibility

Documentation

- [ ] Affects user behaviors
- [ ] Contains syntax changes
- [ ] Contains variable changes
- [ ] Contains experimental features
- [ ] Changes MySQL compatibility

### Release note

<!-- compatibility change, improvement, bugfix, and new feature need a release note -->

Please refer to [Release Notes Language Style Guide](https://pingcap.github.io/tidb-dev-guide/contribute-to-tidb/release-notes-style-guide.html) to write a quality release note.

```release-note
planner: fix uninit timeout for loading bindings

修复加载bindings 超时配置不正确的问题
```


Patch:
diff --git a/pkg/ddl/BUILD.bazel b/pkg/ddl/BUILD.bazel
index 15d5073669..febb5b596f 100644
--- a/pkg/ddl/BUILD.bazel
+++ b/pkg/ddl/BUILD.bazel
@@ -76,6 +76,7 @@ go_library(
     deps = [
         "//br/pkg/storage",
         "//pkg/config",
+        "//pkg/config/kerneltype",
         "//pkg/ddl/copr",
         "//pkg/ddl/ingest",
         "//pkg/ddl/label",
diff --git a/pkg/ddl/ddl_tiflash_api.go b/pkg/ddl/ddl_tiflash_api.go
index 970dc9eda1..d82000d4ad 100644
--- a/pkg/ddl/ddl_tiflash_api.go
+++ b/pkg/ddl/ddl_tiflash_api.go
@@ -30,12 +30,14 @@ import (
 
 	"github.com/pingcap/errors"
 	"github.com/pingcap/failpoint"
+	"github.com/pingcap/tidb/pkg/config/kerneltype"
 	"github.com/pingcap/tidb/pkg/ddl/logutil"
 	ddlutil "github.com/pingcap/tidb/pkg/ddl/util"
 	"github.com/pingcap/tidb/pkg/domain/infosync"
 	"github.com/pingcap/tidb/pkg/infoschema"
 	infoschemacontext "github.com/pingcap/tidb/pkg/infoschema/context"
 	"github.com/pingcap/tidb/pkg/meta/model"
+	"github.com/pingcap/tidb/pkg/parser/ast"
 	"github.com/pingcap/tidb/pkg/sessionctx"
 	"github.com/pingcap/tidb/pkg/table"
 	"github.com/pingcap/tidb/pkg/util"
@@ -221,6 +223,8 @@ var (
 	PullTiFlashPdTick = atomicutil.NewUint64(30 * 5)
 	// UpdateTiFlashStoreTick indicates the number of intervals before we fully update TiFlash stores.
 	UpdateTiFlashStoreTick = atomicutil.NewUint64(5)
+	// RefreshRulesTick indicates the number of intervals before we refresh TiFlash rules.
+	RefreshRulesTick = atomicutil.NewUint64(10)
 	// PollTiFlashBackoffMaxTick is the max tick before we try to update TiFlash replica availability for one table.
 	PollTiFlashBackoffMaxTick TiFlashTick = 10
 	// PollTiFlashBackoffMinTick is the min tick before we try to update TiFlash replica availability for one table.
@@ -548,6 +552,99 @@ func (d *ddl) refreshTiFlashTicker(ctx sessionctx.Context, pollTiFlashContext *T
 	return nil
 }
 
+type pending struct {
+	ID        int64
+	TableInfo *model.TableInfo
+	DBInfo    *model.DBInfo
+}
+
+// refreshTiFlashPlacementRules will refresh the placement rules of TiFlash replicas if on tick.
+// 1. It will scan all the meta and check if there is any TiFlash replica.
+// 2. If there is, it will check if the placement rules are missing.
+// 3. If the placement rules are missing, it will add by submit a ActionSetTiFlashReplica job to repair the entire table.
+func (d *ddl) refreshTiFlashPlacementRules(sctx sessionctx.Context, tick uint64) error {
+	if tick%RefreshRulesTick.Load() != 0 {
+		return nil
+	}
+	schema := d.infoCache.GetLatest()
+	if schema == nil {
+		return errors.New("schema is nil")
+	}
+
+	var pendings []pending
+
+	for _, dbResult := range schema.ListTablesWithSpecialAttribute(infoschemacontext.TiFlashAttribute) {
+		db, ok := schema.SchemaByName(dbResult.DBName)
+		if !ok {
+			return infoschema.ErrDatabaseNotExists.GenWithStackByArgs(dbResult.DBName.O)
+		}
+		for _, tblInfo := range dbResult.TableInfos {
+			if tblInfo.TiFlashReplica == nil {
+				continue
+			}
+
+			if ps := tblInfo.GetPartitionInfo(); ps != nil {
+				collectPendings := func(ps []model.PartitionDefinition) {
+					for _, p := range ps {
+						pendings = append(pendings, pending{
+							ID:        p.ID,
+							TableInfo: tblInfo,
+							DBInfo:    db,
+						})
+					}
+				}
+				collectPendings(ps.Definitions)
+				collectPendings(ps.AddingDefinitions)
+			} else {
+				pendings = append(pendings, pending{
+					ID:        tblInfo.ID,
+					TableInfo: tblInfo,
+					DBInfo:    db,
+				})
+			}
+		}
+	}
+
+	fixed := make(map[int64]struct{})
+	for _, replica := range pendings {
+		if _, ok := fixed[replica.TableInfo.ID]; ok {
+			continue
+		}
+		rule, err := infosync.GetPlacementRule(d.ctx, replica.ID)
+		if err != nil {
+			logutil.DDLLogger().Warn("get placement rule err", zap.Error(err))
+			continue
+		}
+		// pdhttp.GetPlacementRule returns the zero object instead of nil pointer when not found.
+		ruleIsMissing := rule == nil || len(rule.ID) == 0
+		if ruleIsMissing && replica.TableInfo.TiFlashReplica.Count > 0 {
+			job := &model.Job{
+				Version:        model.GetJobVerInUse(),
+				SchemaID:       replica.DBInfo.ID,
+				TableID:        replica.TableInfo.ID,
+				SchemaName:     replica.DBInfo.Name.L,
+				TableName:      replica.TableInfo.Name.L,
+				Type:           model.ActionSetTiFlashReplica,
+				BinlogInfo:     &model.HistoryInfo{},
+				CDCWriteSource: sctx.GetSessionVars().CDCWriteSource,
+				SQLMode:        sctx.GetSessionVars().SQLMode,
+			}
+			args := model.SetTiFlashReplicaArgs{TiflashReplica: ast.TiFlashReplicaSpec{
+				Count:  replica.TableInfo.TiFlashReplica.Count,
+				Labels: replica.TableInfo.TiFlashReplica.LocationLabels,
+			}}
+			err = d.executor.doDDLJob2(sctx, job, &args)
+			if err != nil {
+				logutil.DDLLogger().Warn("fix placement rule err", zap.Error(err))
+			} else {
+				logutil.DDLLogger().Info("fix placement rule success", zap.Int64("tableID", replica.TableInfo.ID))
+				fixed[replica.TableInfo.ID] = struct{}{}
+			}
+		}
+	}
+	return nil
+}
+
 func (d *ddl) PollTiFlashRoutine() {
 	pollTiflashContext, err := NewTiFlashManagementContext()
 	if err != nil {
@@ -594,6 +691,11 @@ func (d *ddl) PollTiFlashRoutine() {
 							logutil.DDLLogger().Warn("refreshTiFlashTicker returns error", zap.Error(err))
 						}
 					}
+					if kerneltype.IsNextGen() {
+						if err := d.refreshTiFlashPlacementRules(sctx, pollTiflashContext.PollCounter); err != nil {
+							logutil.DDLLogger().Warn("refreshTiFlashPlacementRules returns error", zap.Error(err))
+						}
+					}
 				} else {
 					infosync.CleanTiFlashProgressCache()
 				}
diff --git a/pkg/ddl/index.go b/pkg/ddl/index.go
index a3f229be98..34853793aa 100644
--- a/pkg/ddl/index.go
+++ b/pkg/ddl/index.go
@@ -33,6 +33,7 @@ import (
 	"github.com/pingcap/failpoint"
 	"github.com/pingcap/kvproto/pkg/kvrpcpb"
 	"github.com/pingcap/tidb/pkg/config"
+	"github.com/pingcap/tidb/pkg/config/kerneltype"
 	"github.com/pingcap/tidb/pkg/ddl/copr"
 	"github.com/pingcap/tidb/pkg/ddl/ingest"
 	"github.com/pingcap/tidb/pkg/ddl/logutil"
@@ -47,6 +48,7 @@ import (
 	"github.com/pingcap/tidb/pkg/domain/infosync"
 	"github.com/pingcap/tidb/pkg/errctx"
 	"github.com/pingcap/tidb/pkg/infoschema"
+	"github.com/pingcap/tidb/pkg/keyspace"
 	"github.com/pingcap/tidb/pkg/kv"
 	"github.com/pingcap/tidb/pkg/lightning/backend"
 	"github.com/pingcap/tidb/pkg/lightning/backend/local"
@@ -2614,6 +2616,15 @@ func checkDuplicateForUniqueIndex(ctx context.Context, t table.Table, reorgInfo
 	return nil
 }
 
+// TaskKey generates a task key for the backfill job.
+func TaskKey(jobID int64) string {
+	if kerneltype.IsNextGen() {
+		ks := keyspace.GetKeyspaceNameBySettings()
+		return fmt.Sprintf("%s/ddl/%s/%d", ks, proto.Backfill, jobID)
+	}
+	return fmt.Sprintf("ddl/%s/%d", proto.Backfill, jobID)
+}
+
 func (w *worker) executeDistTask(jobCtx *jobContext, t table.Table, reorgInfo *reorgInfo) error {
 	if reorgInfo.mergingTmpIdx {
 		return errors.New("do not support merge index")
@@ -2621,7 +2632,7 @@ func (w *worker) executeDistTask(jobCtx *jobContext, t table.Table, reorgInfo *r
 
 	stepCtx := jobCtx.stepCtx
 	taskType := proto.Backfill
-	taskKey := fmt.Sprintf("ddl/%s/%d", taskType, reorgInfo.Job.ID)
+	taskKey := TaskKey(reorgInfo.Job.ID)
 	g, ctx := errgroup.WithContext(w.workCtx)
 	ctx = kv.WithInternalSourceType(ctx, kv.InternalDistTask)
 
diff --git a/pkg/disttask/importinto/BUILD.bazel b/pkg/disttask/importinto/BUILD.bazel
index 4bb06e1778..5d0d6a9c27 100644
--- a/pkg/disttask/importinto/BUILD.bazel
+++ b/pkg/disttask/importinto/BUILD.bazel
@@ -21,6 +21,7 @@ go_library(
         "//br/pkg/storage",
         "//br/pkg/utils",
         "//pkg/config",
+        "//pkg/config/kerneltype",
         "//pkg/disttask/framework/handle",
         "//pkg/disttask/framework/planner",
         "//pkg/disttask/framework/proto",
@@ -33,6 +34,7 @@ go_library(
         "//pkg/errno",
         "//pkg/executor/importer",
         "//pkg/ingestor/engineapi",
+        "//pkg/keyspace",
         "//pkg/kv",
         "//pkg/lightning/backend",
         "//pkg/lightning/backend/external",
diff --git a/pkg/disttask/importinto/job.go b/pkg/disttask/importinto/job.go
index 1b126b97dd..573d529597 100644
--- a/pkg/disttask/importinto/job.go
+++ b/pkg/disttask/importinto/job.go
@@ -21,12 +21,14 @@ import (
 
 	"github.com/docker/go-units"
 	"github.com/pingcap/errors"
+	"github.com/pingcap/tidb/pkg/config/kerneltype"
 	"github.com/pingcap/tidb/pkg/disttask/framework/handle"
 	"github.com/pingcap/tidb/pkg/disttask/framework/planner"
 	"github.com/pingcap/tidb/pkg/disttask/framework/proto"
 	"github.com/pingcap/tidb/pkg/disttask/framework/storage"
 	"github.com/pingcap/tidb/pkg/domain/infosync"
 	"github.com/pingcap/tidb/pkg/executor/importer"
+	"github.com/pingcap/tidb/pkg/keyspace"
 	"github.com/pingcap/tidb/pkg/kv"
 	"github.com/pingcap/tidb/pkg/sessionctx"
 	"github.com/pingcap/tidb/pkg/util/logutil"
@@ -176,5 +178,9 @@ func GetRuntimeInfoForJob(ctx context.Context, jobID int64) (*RuntimeInfo, error
 
 // TaskKey returns the task key for a job.
 func TaskKey(jobID int64) string {
+	if kerneltype.IsNextGen() {
+		ks := keyspace.GetKeyspaceNameBySettings()
+		return fmt.Sprintf("%s/%s/%d", ks, proto.ImportInto, jobID)
+	}
 	return fmt.Sprintf("%s/%d", proto.ImportInto, jobID)
 }
diff --git a/pkg/domain/infosync/info.go b/pkg/domain/infosync/info.go
index 9d87decdcc..aabf7122dd 100644
--- a/pkg/domain/infosync/info.go
+++ b/pkg/domain/infosync/info.go
@@ -1305,6 +1305,16 @@ func GetTiFlashRegionCountFromPD(ctx context.Context, tableID int64, regionCount
 	return is.tiflashReplicaManager.GetRegionCountFromPD(ctx, tableID, regionCount)
 }
 
+// GetPlacementRule is a helper function to get placement rule by table id.
+func GetPlacementRule(ctx context.Context, tableID int64) (*pdhttp.Rule, error) {
+	is, err := getGlobalInfoSyncer()
+	if err != nil {
+		return nil, err
+	}
+
+	return is.tiflashReplicaManager.GetPlacementRule(ctx, tableID)
+}
+
 // GetTiFlashStoresStat gets the TiKV store information by accessing PD's api.
 func GetTiFlashStoresStat(ctx context.Context) (*pdhttp.StoresInfo, error) {
 	is, err := getGlobalInfoSyncer()
diff --git a/pkg/domain/infosync/tiflash_manager.go b/pkg/domain/infosync/tiflash_manager.go
index f108c048e7..8a1785e84c 100644
--- a/pkg/domain/infosync/tiflash_manager.go
+++ b/pkg/domain/infosync/tiflash_manager.go
@@ -55,6 +55,8 @@ type TiFlashReplicaManager interface {
 	SetPlacementRule(ctx context.Context, rule *pd.Rule) error
 	// SetPlacementRuleBatch is a helper function to set a batch of placement rules.
 	SetPlacementRuleBatch(ctx context.Context, rules []*pd.Rule) error
+	// GetPlacementRule is a helper function to get placement rule.
+	GetPlacementRule(ctx context.Context, tableID int64) (*pd.Rule, error)
 	// DeletePlacementRule is to delete placement rule for certain group.
 	DeletePlacementRule(ctx context.Context, group string, ruleID string) error
 	// GetGroupRules to get all placement rule in a certain group.
@@ -89,6 +91,13 @@ type TiFlashReplicaManagerCtx struct {
 	codec                tikv.Codec
 }
 
+// GetPlacementRule is a helper function to get placement rule by table id.
+func (m *TiFlashReplicaManagerCtx) GetPlacementRule(ctx context.Context, tableID int64) (*pd.Rule, error) {
+	ruleID := MakeRuleID(tableID)
+	ruleID = encodeRuleID(m.codec, ruleID)
+	return m.pdHTTPCli.GetPlacementRule(ctx, placement.TiFlashRuleGroupID, ruleID)
+}
+
 // Close is called to close TiFlashReplicaManagerCtx.
 func (*TiFlashReplicaManagerCtx) Close(context.Context) {}
 
@@ -349,6 +358,10 @@ func makeBaseRule() pd.Rule {
 	}
 }
 
+func (*mockTiFlashReplicaManagerCtx) GetPlacementRule(context.Context, int64) (*pd.Rule, error) {
+	return nil, errors.New("not implemented")
+}
+
 // MakeNewRule creates a pd rule for TiFlash.
 func MakeNewRule(id int64, count uint64, locationLabels []string) pd.Rule {
 	ruleID := MakeRuleID(id)
diff --git a/pkg/infoschema/tables.go b/pkg/infoschema/tables.go
index d262d0bafb..cb30619418 100644
--- a/pkg/infoschema/tables.go
+++ b/pkg/infoschema/tables.go
@@ -1405,7 +1405,7 @@ var tableStatementsSummaryCols = []columnInfo{
 	{name: stmtsummary.BinaryPlan, tp: mysql.TypeBlob, size: types.UnspecifiedLength, comment: "Sampled binary plan"},
 	{name: stmtsummary.Charset, tp: mysql.TypeVarchar, size: 64, comment: "Sampled charset"},
 	{name: stmtsummary.Collation, tp: mysql.TypeVarchar, size: 64, comment: "Sampled collation"},
-	{name: stmtsummary.PlanHint, tp: mysql.TypeVarchar, size: 64, comment: "Sampled plan hint"},
+	{name: stmtsummary.PlanHint, tp: mysql.TypeBlob, size: types.UnspecifiedLength, comment: "Sampled plan hint"},
 	{name: stmtsummary.MaxRequestUnitReadStr, tp: mysql.TypeDouble, flag: mysql.NotNullFlag | mysql.UnsignedFlag, size: 22, comment: "Max read request-unit cost of these statements"},
 	{name: stmtsummary.AvgRequestUnitReadStr, tp: mysql.TypeDouble, flag: mysql.NotNullFlag | mysql.UnsignedFlag, size: 22, comment: "Average read request-unit cost of these statements"},
 	{name: stmtsummary.MaxRequestUnitWriteStr, tp: mysql.TypeDouble, flag: mysql.NotNullFlag | mysql.UnsignedFlag, size: 22, comment: "Max write request-unit cost of these statements"},
diff --git a/pkg/planner/core/constraint/exprs.go b/pkg/planner/core/constraint/exprs.go
index cd4129e4a7..c222b26c88 100644
--- a/pkg/planner/core/constraint/exprs.go
+++ b/pkg/planner/core/constraint/exprs.go
@@ -15,6 +15,8 @@
 package constraint
 
 import (
+	"slices"
+
 	"github.com/pingcap/tidb/pkg/expression"
 	"github.com/pingcap/tidb/pkg/sessionctx/stmtctx"
 )
@@ -24,21 +26,15 @@ func DeleteTrueExprs(buildCtx expression.BuildContext, stmtCtx *stmtctx.Statemen
 	if len(conds) == 0 {
 		return conds
 	}
-	newConds := make([]expression.Expression, 0, len(conds))
-	for _, cond := range conds {
+	return slices.DeleteFunc(conds, func(cond expression.Expression) bool {
 		con, ok := cond.(*expression.Constant)
 		if !ok {
-			newConds = append(newConds, cond)
-			continue
+			return false
 		}
 		if expression.MaybeOverOptimized4PlanCache(buildCtx, con) {
-			newConds = append(newConds, cond)
-			continue
-		}
-		if isTrue, err := con.Value.ToBool(stmtCtx.TypeCtx()); err == nil && isTrue == 1 {
-			continue
+			return false
 		}
-		newConds = append(newConds, cond)
-	}
-	return newConds
+		isTrue, err := con.Value.ToBool(stmtCtx.TypeCtx())
+		return err == nil && isTrue == 1
+	})
 }
diff --git a/pkg/planner/core/planbuilder.go b/pkg/planner/core/planbuilder.go
index 7c503243c3..49c1981680 100644
--- a/pkg/planner/core/planbuilder.go
+++ b/pkg/planner/core/planbuilder.go
@@ -1857,6 +1857,9 @@ func (b *PlanBuilder) buildPhysicalIndexLookUpReaders(ctx context.Context, dbNam
 }
 
 func (b *PlanBuilder) buildAdminCheckTable(ctx context.Context, as *ast.AdminStmt) (*CheckTable, error) {
+	if len(as.Tables) > 1 {
+		return nil, errors.New("admin check only supports one table at a time")
+	}
 	tblName := as.Tables[0]
 	tnW := b.resolveCtx.GetTableName(tblName)
 	tableInfo := tnW.TableInfo
diff --git a/pkg/session/bootstrap.go b/pkg/session/bootstrap.go
index d8c8127170..7fc5197e9b 100644
--- a/pkg/session/bootstrap.go
+++ b/pkg/session/bootstrap.go
@@ -49,6 +49,7 @@ import (
 	"github.com/pingcap/tidb/pkg/util/intest"
 	"github.com/pingcap/tidb/pkg/util/logutil"
 	"github.com/pingcap/tidb/pkg/util/sqlescape"
+	"github.com/pingcap/tidb/pkg/util/sqlexec"
 	"go.uber.org/zap"
 )
 
@@ -1042,13 +1043,9 @@ func upgrade(s sessiontypes.Session) {
 // initGlobalVariableIfNotExists initialize a global variable with specific val if it does not exist.
 func initGlobalVariableIfNotExists(s sessiontypes.Session, name string, val any) {
 	ctx := kv.WithInternalSourceType(context.Background(), kv.InternalTxnBootstrap)
-	rs, err := s.ExecuteInternal(ctx, "SELECT VARIABLE_VALUE FROM %n.%n WHERE VARIABLE_NAME=%?;",
-		mysql.SystemDB, mysql.GlobalVariablesTable, name)
+	rows, err := sqlexec.ExecSQL(ctx, s, "SELECT VARIABLE_VALUE FROM %n.%n WHERE VARIABLE_NAME=%?;", mysql.SystemDB, mysql.GlobalVariablesTable, name)
 	terror.MustNil(err)
-	req := rs.NewChunk(nil)
-	err = rs.Next(ctx, req)
-	terror.MustNil(err)
-	if req.NumRows() != 0 {
+	if len(rows) != 0 {
 		return
 	}
 
diff --git a/pkg/sessionctx/vardef/tidb_vars.go b/pkg/sessionctx/vardef/tidb_vars.go
index 966bc1a545..ce0a2b0c84 100644
--- a/pkg/sessionctx/vardef/tidb_vars.go
+++ b/pkg/sessionctx/vardef/tidb_vars.go
@@ -1661,6 +1661,7 @@ const (
 	DefTiDBCircuitBreakerPDMetaErrorRatePct           = 0.0
 	DefTiDBAccelerateUserCreationUpdate               = false
 	DefTiDBEnableTSValidation                         = true
+	DefTiDBLoadBindingTimeout                         = 200
 )
 
 // Process global variables.
diff --git a/pkg/sessionctx/variable/sysvar.go b/pkg/sessionctx/variable/sysvar.go
index 96ef7ea530..d09b8001c8 100644
--- a/pkg/sessionctx/variable/sysvar.go
+++ b/pkg/sessionctx/variable/sysvar.go
@@ -1697,13 +1697,13 @@ var defaultSysVars = []*SysVar{
 	{
 		Scope:                   vardef.ScopeGlobal,
 		Name:                    vardef.TiDBLoadBindingTimeout,
-		Value:                   "200",
+		Value:                   strconv.Itoa(vardef.DefTiDBLoadBindingTimeout),
 		Type:                    vardef.TypeUnsigned,
 		MinValue:                0,
 		MaxValue:                math.MaxInt32,
 		IsHintUpdatableVerified: false,
 		SetGlobal: func(ctx context.Context, vars *SessionVars, s string) error {
-			timeoutMS := tidbOptPositiveInt32(s, 0)
+			timeoutMS := tidbOptPositiveInt32(s, vardef.DefTiDBLoadBindingTimeout)
 			vars.LoadBindingTimeout = uint64(timeoutMS)
 			return nil
 		}},


Test patch:
diff --git a/pkg/ddl/db_test.go b/pkg/ddl/db_test.go
index d24d11de45..5cf15b6a2c 100644
--- a/pkg/ddl/db_test.go
+++ b/pkg/ddl/db_test.go
@@ -634,7 +634,8 @@ func TestTxnSavepointWithDDL(t *testing.T) {
 	tk2.MustExec("alter table t2 add index idx2(c2)")
 	tk.MustExec("commit")
 	tk.MustQuery("select * from t2").Check(testkit.Rows())
-	tk.MustExec("admin check table t1, t2")
+	tk.MustExec("admin check table t1")
+	tk.MustExec("admin check table t2")
 
 	prepareFn()
 	tk.MustExec("truncate table t1")
@@ -650,7 +651,8 @@ func TestTxnSavepointWithDDL(t *testing.T) {
 	require.Error(t, err)
 	require.Regexp(t, ".*8028.*Information schema is changed during the execution of the statement.*", err.Error())
 	tk.MustQuery("select * from t1").Check(testkit.Rows())
-	tk.MustExec("admin check table t1, t2")
+	tk.MustExec("admin check table t1")
+	tk.MustExec("admin check table t2")
 }
 
 func TestSnapshotVersion(t *testing.T) {
diff --git a/pkg/executor/test/admintest/admin_test.go b/pkg/executor/test/admintest/admin_test.go
index bb4553d47a..577bfba8d7 100644
--- a/pkg/executor/test/admintest/admin_test.go
+++ b/pkg/executor/test/admintest/admin_test.go
@@ -1495,6 +1495,10 @@ func TestAdminCheckTableFailed(t *testing.T) {
 	require.EqualError(t, err, "[admin:8223]data inconsistency in table: admin_test, index: c2, handle: ‹10›, index-values:‹\"handle: 10, values: [KindInt64 19]\"› != record-values:‹\"handle: 10, values: [KindInt64 20]\"›")
 	tk.MustExec("set @@tidb_redact_log=0;")
 
+	tk.MustExec("create table other (a int);")
+	tk.MustGetErrMsg("admin check table other, admin_test;",
+		"admin check only supports one table at a time")
+
 	// Recover records.
 	txn, err = store.Begin()
 	require.NoError(t, err)
diff --git a/pkg/executor/test/executor/executor_test.go b/pkg/executor/test/executor/executor_test.go
index 27a163eb3a..0063a7ca3d 100644
--- a/pkg/executor/test/executor/executor_test.go
+++ b/pkg/executor/test/executor/executor_test.go
@@ -2630,9 +2630,8 @@ func TestAdmin(t *testing.T) {
 	// check table test
 	tk.MustExec("create table admin_test1 (c1 int, c2 int default 1, index (c1))")
 	tk.MustExec("insert admin_test1 (c1) values (21),(22)")
-	r, err = tk.Exec("admin check table admin_test, admin_test1")
-	require.NoError(t, err)
-	require.Nil(t, r)
+	tk.MustExec("admin check table admin_test")
+	tk.MustExec("admin check table admin_test1")
 	// error table name
 	require.Error(t, tk.ExecToErr("admin check table admin_test_error"))
 	// different index values
diff --git a/pkg/session/bootstrap_test.go b/pkg/session/bootstrap_test.go
index 74d6417fdb..51bb2f3ae7 100644
--- a/pkg/session/bootstrap_test.go
+++ b/pkg/session/bootstrap_test.go
@@ -2323,6 +2323,20 @@ func TestTiDBUpgradeToVer212(t *testing.T) {
 	MustExec(t, seCurVer, "select sample_sql, start_time, plan_digest from mysql.tidb_runaway_queries")
 }
 
+func TestIssue61890(t *testing.T) {
+	store, dom := CreateStoreAndBootstrap(t)
+	defer func() { require.NoError(t, store.Close()) }()
+
+	s1 := CreateSessionAndSetID(t, store)
+	MustExec(t, s1, "drop table mysql.global_variables")
+	MustExec(t, s1, "create table mysql.global_variables(`VARIABLE_NAME` varchar(64) NOT NULL PRIMARY KEY clustered, `VARIABLE_VALUE` varchar(16383) DEFAULT NULL)")
+
+	s2 := CreateSessionAndSetID(t, store)
+	initGlobalVariableIfNotExists(s2, vardef.TiDBEnableINLJoinInnerMultiPattern, vardef.Off)
+
+	dom.Close()
+}
+
 func TestIndexJoinMultiPatternByUpgrade650To840(t *testing.T) {
 	ctx := context.Background()
 	store, dom := CreateStoreAndBootstrap(t)
diff --git a/pkg/statistics/handle/globalstats/global_stats_internal_test.go b/pkg/statistics/handle/globalstats/global_stats_internal_test.go
index 3602b46f69..17afc76c9a 100644
--- a/pkg/statistics/handle/globalstats/global_stats_internal_test.go
+++ b/pkg/statistics/handle/globalstats/global_stats_internal_test.go
@@ -439,6 +439,8 @@ func testGlobalStatsAndSQLBinding(tk *testkit.TestKit) {
 	tk.MustExec("insert into trange values " + strings.Join(vals, ","))
 	tk.MustExec("insert into tlist values " + strings.Join(listVals, ","))
 
+	// Disable auto analyze to ensure that stats are not automatically collected
+	tk.MustExec("set @@global.tidb_enable_auto_analyze='OFF'")
 	// before analyzing, the planner will choose TableScan to access the 1% of records
 	tk.MustHavePlan("select * from thash where a<100", "TableFullScan")
 	tk.MustHavePlan("select * from trange where a<100", "TableFullScan")
@@ -470,4 +472,6 @@ func testGlobalStatsAndSQLBinding(tk *testkit.TestKit) {
 	tk.MustHavePlan("select * from thash where a<100", "TableFullScan")
 	tk.MustHavePlan("select * from trange where a<100", "TableFullScan")
 	tk.MustHavePlan("select * from tlist where a<1", "TableFullScan")
+	// Reset auto analyze after test
+	tk.MustExec("set @@global.tidb_enable_auto_analyze='ON'")
 }
diff --git a/tests/integrationtest/r/ddl/foreign_key.result b/tests/integrationtest/r/ddl/foreign_key.result
index 0d3a86cdb6..155a2b20f4 100644
--- a/tests/integrationtest/r/ddl/foreign_key.result
+++ b/tests/integrationtest/r/ddl/foreign_key.result
@@ -205,7 +205,8 @@ id	b
 select * from t2;
 id	b
 2	2
-admin check table t1,t2;
+admin check table t1;
+admin check table t2;
 create database test_db_1;
 create database test_db_2;
 create database test_db_3;
diff --git a/tests/integrationtest/t/ddl/foreign_key.test b/tests/integrationtest/t/ddl/foreign_key.test
index 5e5d68312f..f29422a843 100644
--- a/tests/integrationtest/t/ddl/foreign_key.test
+++ b/tests/integrationtest/t/ddl/foreign_key.test
@@ -211,7 +211,8 @@ alter table t2 rename index idx to idx0;
 delete from t1 where id=1;
 select * from t1;
 select * from t2;
-admin check table t1,t2;
+admin check table t1;
+admin check table t2;
 
 # TestCheckFKDatabaseRefWithSchemaSimpleTableInfos
 create database test_db_1;
diff --git a/tests/realtikvtest/addindextest2/global_sort_test.go b/tests/realtikvtest/addindextest2/global_sort_test.go
index b5a360d8b9..1b1883831f 100644
--- a/tests/realtikvtest/addindextest2/global_sort_test.go
+++ b/tests/realtikvtest/addindextest2/global_sort_test.go
@@ -135,7 +135,7 @@ func getTaskID(t *testing.T, jobID int64) int64 {
 	mgr, err := diststorage.GetTaskManager()
 	require.NoError(t, err)
 	ctx := util.WithInternalSourceType(context.Background(), "scheduler")
-	task, err := mgr.GetTaskByKeyWithHistory(ctx, fmt.Sprintf("ddl/backfill/%d", jobID))
+	task, err := mgr.GetTaskByKeyWithHistory(ctx, ddl.TaskKey(jobID))
 	require.NoError(t, err)
 	return task.ID
 }