Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return useful error when attempting to reuse a blocked connection #526

Open
ycybaby opened this issue Dec 8, 2016 · 10 comments
Open

Return useful error when attempting to reuse a blocked connection #526

ycybaby opened this issue Dec 8, 2016 · 10 comments
Milestone

Comments

@ycybaby
Copy link

ycybaby commented Dec 8, 2016

Issue description

the latest version: 1.3.

Prepare one statement and execute it on one transaction, keep rows open. Error happens when trying to prepare another statement:
[mysql] 2016/12/08 15:45:57 packets.go:431: busy buffer

I see issue#314 which was similiar with the problem and closed. Looks like this problem not fixed in 1.3.

Example code

func query(db *sql.DB) {
	var (
		tx    *sql.Tx
		stmt1 *sql.Stmt
		stmt2 *sql.Stmt
		rs1   *sql.Rows
		rs2   *sql.Rows
	)

	tx, _ = db.Begin()
	stmt1, _ = tx.Prepare("select f1, f2 from test where f2 = 11")
	rs1, _ = stmt1.Query()
	rs1.Next()

	stmt2, _ = tx.Prepare("select f2 from test where f2 = 111")  // error here
	rs2, _ = stmt2.Query()
	rs2.Next()

}

Error log

[mysql] 2016/12/08 15:45:57 packets.go:431: busy buffer

Configuration

*Driver version:1.3

Go version: go version go1.7.1 windows/amd64,go version go1.7.4 linux/amd64

@methane
Copy link
Member

methane commented Dec 8, 2016

#314 and this is completely different.

MySQL protocol is not async. Previous request must be finished before sending next request.
It means you must Close previous ResultSet before Prepare (or any other request like Exec or Query).

@julienschmidt
Copy link
Member

This should however return a different error than "busy buffer". I'm surprised database/sql even allows this.

@ycybaby
Copy link
Author

ycybaby commented Dec 8, 2016

I am not sure whether it depends on the setting of STMT_ATTR_CURSOR_TYPE.

In packets.go:915, it is set to CURSOR_TYPE_NO_CURSOR.
// flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte]
data[9] = 0x00

We also use mysql c driver in other project. It is set to CURSOR_TYPE_READ_ONLY so that more than one resultset can be opened on one connection at the same time.

@methane
Copy link
Member

methane commented Dec 8, 2016

http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html

If you use the STMT_ATTR_CURSOR_TYPE option with CURSOR_TYPE_READ_ONLY, a cursor is opened for the statement when you invoke mysql_stmt_execute(). If there is already an open cursor from a previous mysql_stmt_execute() call, it closes the cursor before opening a new one.

So you cannot keep old resultset opened even when using STMT_ATTR_CURSOR_TYPE.

@ycybaby
Copy link
Author

ycybaby commented Dec 9, 2016

This note just says the open cursor for the stmt to be re-executed will be closed, not cursors for all stmts on the connection, i.e. only one cursor can be opened for one stmt at any time.
But more than one stmt can be open on one connection.

@methane
Copy link
Member

methane commented Dec 9, 2016

Hmm. You may right.
But I'm not interested in supporting server side cursor.

@ycybaby
Copy link
Author

ycybaby commented Dec 13, 2016

I think in many scenarios this feature is needed, such as nest-loop search, ...

Another problem is, without no cursor all dataset will be fetched to client-side. Maybe one performance issue when dataset is huge.

Hope it can be added in the future version :)

@methane
Copy link
Member

methane commented Nov 14, 2018

I don't understand this yet.
I can't find any protocol for concurrent resultset fetching.

Could you provide complete example written in C, using MySQL Connector/C?
Or could you get packet capture with tcpdump?

@methane
Copy link
Member

methane commented Nov 14, 2018

Ah, I found the document. It is in "Stored Procedures" section, not "Prepared Statements" section.
https://dev.mysql.com/doc/internals/en/com-stmt-fetch-response.html

@methane methane mentioned this issue Nov 16, 2018
5 tasks
@julienschmidt julienschmidt modified the milestones: v1.5.0, v1.6.0 Jan 7, 2020
@julienschmidt julienschmidt changed the title Can not prepare statement when another statement is executed and resultset is not closed yet. Return useful when attempting to reuse a blocked connection Jan 7, 2020
@julienschmidt
Copy link
Member

julienschmidt commented Jan 7, 2020

I created issue #1053 regarding cursor support. Please continue the discussion about that over there.

The original issue still returns the same confusing error:

=== RUN   TestIssue526
[mysql] 2020/01/07 16:51:31 packets.go:446: busy buffer
[mysql] 2020/01/07 16:51:31 connection.go:158: bad connection
--- FAIL: TestIssue526 (0.02s)
    driver_test.go:1802: driver: bad connection
FAIL

With the following adopted test code, which still has to modified to check for the correct error type:

func TestIssue526(t *testing.T) {
	runTests(t, dsn, func(dbt *DBTest) {
		tx, err := dbt.db.Begin()
		if err != nil {
			dbt.Fatal(err)
		}
		stmt1, err := tx.Prepare("SELECT 1")
		if err != nil {
			dbt.Fatal(err)
		}

		rs1, err := stmt1.Query()
		if err != nil {
			dbt.Fatal(err)
		}
		rs1.Next()
		err = rs1.Err()
		if err != nil {
			dbt.Fatal(err)
		}

		stmt2, err := tx.Prepare("SELECT 2")
		if err != nil {
			dbt.Fatal(err)
		}
		rs2, err := stmt2.Query()
		if err != nil {
			dbt.Fatal(err)
		}
		rs2.Next()
		err = rs2.Err()
		if err != nil {
			dbt.Fatal(err)
		}
	})
}

@julienschmidt julienschmidt changed the title Return useful when attempting to reuse a blocked connection Return useful error when attempting to reuse a blocked connection Jan 7, 2020
@julienschmidt julienschmidt modified the milestones: v1.6.0, v1.7.0 Apr 1, 2021
@methane methane modified the milestones: v1.7.0, v1.8.0 May 2, 2023
@methane methane modified the milestones: v1.8.0, v1.9.0 Mar 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants