Skip to content

Commit 928f5c4

Browse files
authored
Merge pull request #3247 from dolthub/elian/9865
dolthub/dolt#9865: Fix EOF on procedure
2 parents 2be75e4 + 8cbeec8 commit 928f5c4

File tree

3 files changed

+45
-3
lines changed

3 files changed

+45
-3
lines changed

enginetest/queries/script_queries.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,37 @@ type ScriptTestAssertion struct {
122122
// Unlike other engine tests, ScriptTests must be self-contained. No other tables are created outside the definition of
123123
// the tests.
124124
var ScriptTests = []ScriptTest{
125+
{
126+
// https://github.com/dolthub/dolt/issues/9865
127+
Name: "Stored procedure containing a transaction does not return EOF",
128+
Dialect: "mysql",
129+
SetUpScript: []string{
130+
"CREATE TABLE test_table (id INT PRIMARY KEY, name TEXT)",
131+
`CREATE PROCEDURE my_proc()
132+
BEGIN
133+
START TRANSACTION;
134+
INSERT INTO test_table VALUES (1, 'test');
135+
COMMIT;
136+
END`,
137+
`CREATE PROCEDURE empty_procedure()
138+
BEGIN
139+
END`,
140+
},
141+
Assertions: []ScriptTestAssertion{
142+
{
143+
Query: "CALL my_proc()",
144+
Expected: []sql.Row{{types.OkResult{RowsAffected: 0, InsertID: 0, Info: nil}}},
145+
},
146+
{
147+
Query: "SELECT * FROM test_table",
148+
Expected: []sql.Row{{1, "test"}},
149+
},
150+
{
151+
Query: "CALL empty_procedure()",
152+
Expected: []sql.Row{{types.OkResult{RowsAffected: 0, InsertID: 0, Info: nil}}},
153+
},
154+
},
155+
},
125156
{
126157
// https://github.com/dolthub/dolt/issues/9873
127158
// TODO: `FOR UPDATE OF` (`FOR UPDATE` in general) is currently a no-op: https://www.dolthub.com/blog/2023-10-23-hold-my-beer/

sql/procedures/interpreter_logic.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,11 @@ func Call(ctx *sql.Context, iNode InterpreterNode) (sql.RowIter, *InterpreterSta
965965
rowIters = append(rowIters, sql.RowsToRowIter(sql.Row{types.NewOkResult(0)}))
966966
} else if retSch != nil {
967967
iNode.SetSchema(retSch)
968+
} else {
969+
// If we have rowIters but no meaningful schema, return OkResult
970+
// This ensures CALL statements always return proper result sets for MySQL protocol
971+
iNode.SetSchema(types.OkResultSchema)
972+
rowIters = []sql.RowIter{sql.RowsToRowIter(sql.Row{types.NewOkResult(0)})}
968973
}
969974

970975
return rowIters[len(rowIters)-1], stack, nil

sql/rowexec/proc_iters.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,20 @@ var _ sql.MutableRowIter = (*callIter)(nil)
121121

122122
// Next implements the sql.RowIter interface.
123123
func (ci *callIter) Next(ctx *sql.Context) (sql.Row, error) {
124+
if ci.innerIter == nil {
125+
return nil, io.EOF
126+
}
124127
return ci.innerIter.Next(ctx)
125128
}
126129

127130
// Close implements the sql.RowIter interface.
128131
func (ci *callIter) Close(ctx *sql.Context) error {
129-
err := ci.innerIter.Close(ctx)
130-
if err != nil {
131-
return err
132+
var err error
133+
if ci.innerIter != nil {
134+
err = ci.innerIter.Close(ctx)
135+
if err != nil {
136+
return err
137+
}
132138
}
133139
err = ci.call.Pref.CloseAllCursors(ctx)
134140
if err != nil {

0 commit comments

Comments
 (0)