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

implemented ExecuteMultiple #668

Merged
merged 2 commits into from
Jan 27, 2022
Merged

Conversation

skoef
Copy link
Contributor

@skoef skoef commented Jan 21, 2022

Like mentioned before in earlier PRs, I wrote/maintain a MySQL proxy acting as a gateway between client and server. When a client connects with the CLIENT_MULTI_STATEMENTS capability, it could execute multiple queries at once, for instance SELECT 1; INSERT INTO foo VALUES (1, "foo"). When such a query is executed through the regular Execute() function, the server will return multiple results, one for each query with the SERVER_MORE_RESULTS_EXISTS flag set for all results except the last. The additional results are not handled properly in the current implementation.

ExecuteMultiple allows me to keep handling all results in a user-defined callback, for instance:

func (q MyHandler) HandleQuery(query string) (*mysql.Result, error) {
	// ...

        if clientConn.HasStatus(mysql.CLIENT_MULTIPLE_STATEMENTS) {
            // execute multiple queries and write back the results to the client one by one
	    return backendConn.ExecuteMultiple(queries, func(result *mysql.Result, err error) {
                    // set proper status according to server results
                    clientConn.SetStatus(mysql.SERVER_MORE_RESULTS_EXISTS)
		    // if this is the last result, unset the more_results status
		    if result.Status&mysql.SERVER_MORE_RESULTS_EXISTS == 0 {
                        clientConn.UnsetStatus(mysql.SERVER_MORE_RESULTS_EXISTS)
		    }

         	    // if the query resulted in an error, write that back to the client
		    if err != nil {
		        clientConn.WriteValue(err)
		    } else {
  		        // handle result appropriately
		        clientConn.WriteValue(result)
		    }
	    })
	} else {
            // assume single query command
            return backendConn.Execute(query)
	}
}

ExecuteMultiple returns an empty resultset with the new streamingtype StreamingMulti set, so when it bubbles from HandleQuery towards WriteQuery/writeResultSet it doesn't send an additional OK or EOF to the client.

I have been running this in production for a while (about a year) and I was in the process of backporting my local changes to go-mysql to the repo so I can hopefully one day just use the upstream repo itself again 🤗

…d then

handle the results in a user-defined callback
@lance6716 lance6716 merged commit 051905b into go-mysql-org:master Jan 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants