diff --git a/executor/executor_test.go b/executor/executor_test.go index 02feb44abaa65..d4b11b0758d8b 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -9686,3 +9686,29 @@ func (s *testSerialSuite) TestUnreasonablyClose(c *C) { } c.Assert(opsAlreadyCoveredMask, Equals, opsNeedsCoveredMask, Commentf("these operators are not covered %s", commentBuf.String())) } + +func (s *testSerialSuite) TestIssue30971(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2") + tk.MustExec("create table t1 (id int);") + tk.MustExec("create table t2 (id int, c int);") + + testCases := []struct { + sql string + fields int + }{ + // Fix a bug that the column length field returned to client is incorrect using MySQL prepare protocol. + {"select * from t1 union select 1 from t1", 1}, + {"select c from t2 union select * from t1", 1}, + {"select * from t1", 1}, + {"select * from t2 where c in (select * from t1)", 2}, + {"insert into t1 values (?)", 0}, + {"update t1 set id = ?", 0}, + } + for _, test := range testCases { + _, _, fields, err := tk.Se.PrepareStmt(test.sql) + c.Assert(err, IsNil) + c.Assert(fields, HasLen, test.fields) + } +} diff --git a/executor/prepared.go b/executor/prepared.go index e18495d45c601..0676a77215f2e 100644 --- a/executor/prepared.go +++ b/executor/prepared.go @@ -220,7 +220,7 @@ func (e *PrepareExec) Next(ctx context.Context, req *chunk.Chunk) error { if err != nil { return err } - if _, ok := stmt.(*ast.SelectStmt); ok { + if p.Schema().Len() > 0 { e.Fields = colNames2ResultFields(p.Schema(), p.OutputNames(), vars.CurrentDB) } if e.ID == 0 {