Repository: pingcap/tidb (go)

Issue:
`initGlobalVariableIfNotExists` function forget close `rs`
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

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

https://github.com/pingcap/tidb/blob/c597cb5e0a290153916d52a5600c7ee4b30c634a/pkg/session/bootstrap.go#L1043-L1058

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

call `rs.Close` before return

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

forget call it and caused some states of `s` to not be cleaned up.

If `mysql.GLOBAL_VARIABLES` has a clustered index, it will report an error log like 

```
[2025/06/20 16:07:36.838 +08:00] [FATAL] [bootstrap.go:3591] ["mustExecute error"] [error="try to commit with invalid txnStartTS: 18446744073709551615"] [stack="github.com/pingcap/tidb/pkg/session.mustExecute\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/bootstrap.go:3591\ngithub.com/pingcap/tidb/pkg/session.initGlobalVariableIfNotExists\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/bootstrap.go:3327\ngithub.com/pingcap/tidb/pkg/session.upgradeToVer209\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/bootstrap.go:3181\ngithub.com/pingcap/tidb/pkg/session.upgrade\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/bootstrap.go:1556\ngithub.com/pingcap/tidb/pkg/session.runInBootstrapSession\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/session.go:3732\ngithub.com/pingcap/tidb/pkg/session.bootstrapSessionImpl\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/session.go:3458\ngithub.com/pingcap/tidb/pkg/session.BootstrapSession\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/session.go:3404\nmain.createStoreDDLOwnerMgrAndDomain\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/cmd/tidb-server/main.go:416\nmain.main\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/cmd/tidb-server/main.go:320\nruntime.main\n\t/Users/pingcap/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.6.darwin-arm64/src/runtime/proc.go:272"] [stack="github.com/pingcap/tidb/pkg/session.mustExecute\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/bootstrap.go:3591\ngithub.com/pingcap/tidb/pkg/session.initGlobalVariableIfNotExists\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/bootstrap.go:3327\ngithub.com/pingcap/tidb/pkg/session.upgradeToVer209\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/bootstrap.go:3181\ngithub.com/pingcap/tidb/pkg/session.upgrade\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/bootstrap.go:1556\ngithub.com/pingcap/tidb/pkg/session.runInBootstrapSession\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/session.go:3732\ngithub.com/pingcap/tidb/pkg/session.bootstrapSessionImpl\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/session.go:3458\ngithub.com/pingcap/tidb/pkg/session.BootstrapSession\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/pkg/session/session.go:3404\nmain.createStoreDDLOwnerMgrAndDomain\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/cmd/tidb-server/main.go:416\nmain.main\n\t/Users/pingcap/workspace/bp-tidb-release-darwin-arm64-w2tsl-build-binaries/source/tidb/cmd/tidb-server/main.go:320\nruntime.main\n\t/Users/pingcap/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.6.darwin-arm64/src/runtime/proc.go:272"]
```

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

<!-- Paste the output of SELECT tidb_version() -->
v8.5.2, master


Pull request:
session: fix `initGlobalVariableIfNotExists` function forget call rs.close
<!--

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 #61884

Problem Summary:

### What changed and how does it work?

### Check List

Tests <!-- At least one of them must be included. -->

- [x] Unit test
- [ ] Integration test
- [x] Manual test (add detailed scripts or steps below)
```
Modified v7.5.6 and let it create a mysql.global_variables table with clustered index.

Run v8.5.2 to upgrade the cluster, before this PR, it will failed. After this PR, cluster start up success.

```
- [ ] 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
None
```


Patch:
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/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
 	}
 


Test patch:
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'")
 }