From 9468226fc7d70035de0d7929a0b42e4e1eb438ed Mon Sep 17 00:00:00 2001 From: aidan Date: Wed, 19 Jul 2023 14:39:50 +0800 Subject: [PATCH 1/4] fix issue 1361 --- driver_test.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ rows.go | 8 ++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/driver_test.go b/driver_test.go index 2748870b7..2efd0cc0b 100644 --- a/driver_test.go +++ b/driver_test.go @@ -3406,3 +3406,62 @@ func TestConnectionAttributes(t *testing.T) { } rows.Close() } + +func TestIssue1361(t *testing.T) { + var db *sql.DB + if _, err := ParseDSN(dsn); err != errInvalidDSNUnsafeCollation { + db, err = sql.Open("mysql", dsn) + if err != nil { + t.Fatalf("error connecting: %s", err.Error()) + } + defer db.Close() + } + + dbt := &DBTest{t, db} + // for _, test := range tests { + // test(dbt) + // dbt.db.Exec("DROP TABLE IF EXISTS test") + // } + queries := []string{ + ` + CREATE PROCEDURE test_proc1() + BEGIN + SIGNAL SQLSTATE '10000' SET MESSAGE_TEXT = "some error", MYSQL_ERRNO = 10000; + END; + `, + ` + CREATE PROCEDURE test_proc2() + BEGIN + SELECT 1,2; + SELECT 3,4; + SIGNAL SQLSTATE '10000' SET MESSAGE_TEXT = "some error", MYSQL_ERRNO = 10000; + END; + `, + } + names := []string{ + "test_proc1", "test_proc2", + } + for i, query := range queries { + runCallCommand(dbt, query, names[i]) + } + +} + +func runCallCommand(dbt *DBTest, query, name string) { + + dbt.mustExec(fmt.Sprintf("DROP PROCEDURE IF EXISTS %s;", name)) + dbt.mustExec(query) + defer dbt.mustExec("drop procedure " + name) + rows, err := dbt.db.Query(fmt.Sprintf("call %s;", name)) + if err != nil { + return + } + defer rows.Close() + + for rows.Next() { + } + for rows.NextResultSet() { // thread will be blocked when exec rs.Close() + for rows.Next() { + } + } +} diff --git a/rows.go b/rows.go index 63d0ed2d5..81fa6062c 100644 --- a/rows.go +++ b/rows.go @@ -163,7 +163,13 @@ func (rows *mysqlRows) nextResultSet() (int, error) { rows.rs = resultSet{} // rows.mc.affectedRows and rows.mc.insertIds accumulate on each call to // nextResultSet. - return rows.mc.resultUnchanged().readResultSetHeaderPacket() + resLen, err := rows.mc.resultUnchanged().readResultSetHeaderPacket() + if err != nil { + // Clean up about multi-results flag + rows.rs.done = true + rows.mc.status = rows.mc.status & (^statusMoreResultsExists) + } + return resLen, err } func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { From 41670f66160080e74f05ce9202d266c1baa6c952 Mon Sep 17 00:00:00 2001 From: aidan Date: Wed, 19 Jul 2023 14:51:55 +0800 Subject: [PATCH 2/4] modified: AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 29e08b0ca..f9e96cc6b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ Aaron Hopkins Achille Roussel +Aidan Alex Snast Alexey Palazhchenko Andrew Reid From d8ca4e4bd99c1369edcb7400294a874481c47acd Mon Sep 17 00:00:00 2001 From: aidan Date: Wed, 19 Jul 2023 14:56:06 +0800 Subject: [PATCH 3/4] modified: driver_test.go --- driver_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/driver_test.go b/driver_test.go index 2efd0cc0b..ab3fa6ddb 100644 --- a/driver_test.go +++ b/driver_test.go @@ -3418,10 +3418,6 @@ func TestIssue1361(t *testing.T) { } dbt := &DBTest{t, db} - // for _, test := range tests { - // test(dbt) - // dbt.db.Exec("DROP TABLE IF EXISTS test") - // } queries := []string{ ` CREATE PROCEDURE test_proc1() @@ -3460,7 +3456,7 @@ func runCallCommand(dbt *DBTest, query, name string) { for rows.Next() { } - for rows.NextResultSet() { // thread will be blocked when exec rs.Close() + for rows.NextResultSet() { // original thread will be blocked when exec rs.Close() for rows.Next() { } } From 7a0fc259ec0ffe9fc0126099ab9cdee1ca6b7258 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 19:32:54 +0900 Subject: [PATCH 4/4] simplify test --- driver_test.go | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/driver_test.go b/driver_test.go index ab3fa6ddb..7b872ae4f 100644 --- a/driver_test.go +++ b/driver_test.go @@ -3407,7 +3407,8 @@ func TestConnectionAttributes(t *testing.T) { rows.Close() } -func TestIssue1361(t *testing.T) { +func TestErrorInMultiResult(t *testing.T) { + // https://github.com/go-sql-driver/mysql/issues/1361 var db *sql.DB if _, err := ParseDSN(dsn); err != errInvalidDSNUnsafeCollation { db, err = sql.Open("mysql", dsn) @@ -3418,37 +3419,22 @@ func TestIssue1361(t *testing.T) { } dbt := &DBTest{t, db} - queries := []string{ - ` - CREATE PROCEDURE test_proc1() - BEGIN - SIGNAL SQLSTATE '10000' SET MESSAGE_TEXT = "some error", MYSQL_ERRNO = 10000; - END; - `, - ` - CREATE PROCEDURE test_proc2() - BEGIN - SELECT 1,2; - SELECT 3,4; - SIGNAL SQLSTATE '10000' SET MESSAGE_TEXT = "some error", MYSQL_ERRNO = 10000; - END; - `, - } - names := []string{ - "test_proc1", "test_proc2", - } - for i, query := range queries { - runCallCommand(dbt, query, names[i]) - } - + query := ` +CREATE PROCEDURE test_proc1() +BEGIN + SELECT 1,2; + SELECT 3,4; + SIGNAL SQLSTATE '10000' SET MESSAGE_TEXT = "some error", MYSQL_ERRNO = 10000; +END; +` + runCallCommand(dbt, query, "test_proc1") } func runCallCommand(dbt *DBTest, query, name string) { - - dbt.mustExec(fmt.Sprintf("DROP PROCEDURE IF EXISTS %s;", name)) + dbt.mustExec(fmt.Sprintf("DROP PROCEDURE IF EXISTS %s", name)) dbt.mustExec(query) - defer dbt.mustExec("drop procedure " + name) - rows, err := dbt.db.Query(fmt.Sprintf("call %s;", name)) + defer dbt.mustExec("DROP PROCEDURE " + name) + rows, err := dbt.db.Query(fmt.Sprintf("CALL %s", name)) if err != nil { return } @@ -3456,7 +3442,7 @@ func runCallCommand(dbt *DBTest, query, name string) { for rows.Next() { } - for rows.NextResultSet() { // original thread will be blocked when exec rs.Close() + for rows.NextResultSet() { for rows.Next() { } }