From 1a113428c51ec4b5e8ffe7bb2f8a5f9d8be9519b Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Mon, 28 Mar 2022 18:28:51 +0800 Subject: [PATCH] executor: fix execute failed when table schema changed --- planner/core/cache.go | 1 - server/driver_tidb.go | 25 ++++++----------------- server/tidb_serial_test.go | 41 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/planner/core/cache.go b/planner/core/cache.go index 05432bbe98599..1963652e3692b 100644 --- a/planner/core/cache.go +++ b/planner/core/cache.go @@ -215,7 +215,6 @@ type CachedPrepareStmt struct { PreparedAst *ast.Prepared StmtDB string // which DB the statement will be processed over VisitInfos []visitInfo - ColumnInfos interface{} Executor interface{} NormalizedSQL string NormalizedPlan string diff --git a/server/driver_tidb.go b/server/driver_tidb.go index 3092b3b4df37c..2594f9a140b46 100644 --- a/server/driver_tidb.go +++ b/server/driver_tidb.go @@ -80,8 +80,7 @@ func (ts *TiDBStatement) Execute(ctx context.Context, args []types.Datum) (rs Re return } rs = &tidbResultSet{ - recordSet: tidbRecordset, - preparedStmt: ts.ctx.GetSessionVars().PreparedStmts[ts.id].(*core.CachedPrepareStmt), + recordSet: tidbRecordset, } return } @@ -302,11 +301,10 @@ func (tc *TiDBContext) GetStmtStats() *stmtstats.StatementStats { } type tidbResultSet struct { - recordSet sqlexec.RecordSet - columns []*ColumnInfo - rows []chunk.Row - closed int32 - preparedStmt *core.CachedPrepareStmt + recordSet sqlexec.RecordSet + columns []*ColumnInfo + rows []chunk.Row + closed int32 } func (trs *tidbResultSet) NewChunk(alloc chunk.Allocator) *chunk.Chunk { @@ -348,23 +346,12 @@ func (trs *tidbResultSet) Columns() []*ColumnInfo { if trs.columns != nil { return trs.columns } - // for prepare statement, try to get cached columnInfo array - if trs.preparedStmt != nil { - ps := trs.preparedStmt - if colInfos, ok := ps.ColumnInfos.([]*ColumnInfo); ok { - trs.columns = colInfos - } - } + if trs.columns == nil { fields := trs.recordSet.Fields() for _, v := range fields { trs.columns = append(trs.columns, convertColumnInfo(v)) } - if trs.preparedStmt != nil { - // if ColumnInfo struct has allocated object, - // here maybe we need deep copy ColumnInfo to do caching - trs.preparedStmt.ColumnInfos = trs.columns - } } return trs.columns } diff --git a/server/tidb_serial_test.go b/server/tidb_serial_test.go index 39907170ade80..468f840c888ee 100644 --- a/server/tidb_serial_test.go +++ b/server/tidb_serial_test.go @@ -348,6 +348,47 @@ func TestPrepareCount(t *testing.T) { require.NoError(t, qctx.Close()) } +func TestPrepareExecute(t *testing.T) { + ts, cleanup := createTidbTestSuite(t) + defer cleanup() + + qctx, err := ts.tidbdrv.OpenCtx(uint64(0), 0, uint8(tmysql.DefaultCollationID), "test", nil) + require.NoError(t, err) + + ctx := context.Background() + _, err = qctx.Execute(ctx, "use test") + require.NoError(t, err) + _, err = qctx.Execute(ctx, "create table t1(id int primary key, v int)") + require.NoError(t, err) + _, err = qctx.Execute(ctx, "insert into t1 values(1, 100)") + require.NoError(t, err) + + stmt, _, _, err := qctx.Prepare("select * from t1 where id=1") + require.NoError(t, err) + rs, err := stmt.Execute(ctx, nil) + require.NoError(t, err) + req := rs.NewChunk(nil) + require.NoError(t, rs.Next(ctx, req)) + require.Equal(t, 2, req.NumCols()) + require.Equal(t, req.NumCols(), len(rs.Columns())) + require.Equal(t, 1, req.NumRows()) + require.Equal(t, int64(1), req.GetRow(0).GetInt64(0)) + require.Equal(t, int64(100), req.GetRow(0).GetInt64(1)) + + // issue #33509 + _, err = qctx.Execute(ctx, "alter table t1 drop column v") + require.NoError(t, err) + + rs, err = stmt.Execute(ctx, nil) + require.NoError(t, err) + req = rs.NewChunk(nil) + require.NoError(t, rs.Next(ctx, req)) + require.Equal(t, 1, req.NumCols()) + require.Equal(t, req.NumCols(), len(rs.Columns())) + require.Equal(t, 1, req.NumRows()) + require.Equal(t, int64(1), req.GetRow(0).GetInt64(0)) +} + func TestDefaultCharacterAndCollation(t *testing.T) { ts, cleanup := createTidbTestSuite(t) defer cleanup()