Description
The driver naively splits multi-statement queries by ;
, which doesn't match how Vitess and GMS process the queries: In particular, procedure definitions are not parsed as a single statement, and DELIMITER
statements are not respected.
Additionally, the driver processes multi-statement queries by executing the statements directly in Prepare
, which is unexpected behaviour.
Demonstration of the issue; the below yields the error Error 1105: syntax error at position 42 near '1'
when running the last query, but works correctly if connecting to a Dolt server using the MySQL driver:
package main
import (
"context"
"database/sql"
"net/url"
"os"
_ "github.com/dolthub/driver"
)
func main() {
dir := must(os.MkdirTemp("", "dolt-test-db-*"))
defer os.RemoveAll(dir)
params := url.Values{
"database": []string{"testdb"}, "multistatements": []string{"true"},
"commitname": []string{"a"}, "commitemail": []string{"a@a.com"}}
dsn := url.URL{Scheme: "file", Path: dir, RawQuery: params.Encode()}
db := must(sql.Open("dolt", dsn.String()))
ctx := context.Background()
must(db.ExecContext(ctx, "CREATE DATABASE testdb"))
must(db.ExecContext(ctx, "COMMIT")) // workaround for implicit transactions not being committed
must(db.ExecContext(ctx, `
CREATE PROCEDURE myproc()
BEGIN
SELECT 1;
END;
CALL myproc();
`))
}
func must[T any](t T, err error) T {
if err != nil {
panic(err)
}
return t
}
I had a quick look at it myself, but it wasn't obvious what the best approach would be - perhaps the easiest would be to implement ExecContext
and QueryContext
and move the multi-statement processing there, maybe using MysqlParser
from GMS to split the queries and calling QueryWithBindings
for each, if prepared multi-statement queries aren't a requirement? (They don't seem to be supported by MySQL anyway.) Would be nice if the result also implemented driver.RowsNextResultSet
.