dolthub / go-mysql-server

A MySQL-compatible relational database with a storage agnostic query engine. Implemented in pure Go.
Apache License 2.0
2.32k stars 199 forks source link

Can't turn on multiStatements when using memory driver #2314

Closed seanlaff closed 7 months ago

seanlaff commented 7 months ago

If I create an in-memory server and supply multiStatements=true in the connection dsn, mutli statements work. However, I have not been able to find a way to reproduce this behavior when using the the in-memory driver directly- is that an expected limitation?

My usecase: I have tests that depend on mysql and I'm interested in running an in-memory go-mysql-server in such a way that I wouldn't have to worry about port coordination. I thought I could use the driver directly to avoid the networking stack, but maybe I misunderstand the abstractions.

I copied the example from driver/example (Im using main d5876b4)

import (
    "database/sql"
    "testing"

    "github.com/dolthub/go-mysql-server/driver"
    "github.com/dolthub/go-mysql-server/memory"
    msql "github.com/dolthub/go-mysql-server/sql"
)

var provider = memory.NewDBProvider(memory.NewDatabase("mydb"))

type factory struct{}

func (factory) Resolve(name string, options *driver.Options) (string, msql.DatabaseProvider, error) {
    return name, provider, nil
}

func TestMultiStatement(t *testing.T) {
    sql.Register("sqle", driver.New(factory{}, nil))
    db, err := sql.Open("sqle", "")
    if err != nil {
        panic(err)
    }

    _, err = db.Exec("USE mydb")
    if err != nil {
        panic(err)
    }
    const createTwoTables = `CREATE TABLE table1 (id int); CREATE TABLE table2 (id int);`
    _, err = db.Exec(createTwoTables)
    if err != nil {
        panic(err)
    }
    res, err := db.Query("show tables")
    if err != nil {
        panic(err)
    }

    tables := []string{}
    for res.Next() {
        var table string
        res.Scan(&table)
        tables = append(tables, table)
    }
    if len(tables) != 2 {
        t.Fatalf("didn't find both tables, tables: %s", tables)
    }
}

This test fails- which I assume is expected since I have yet to supply the multiStatements flag. I tried a few variations:

Building a conn from the driver, supplying the multiStatements flag, no luck:

    drv := driver.New(factory{}, nil)
    conn, err := drv.OpenConnector("/mydb?multiStatements=true")
        if err != nil {
        panic(err)
    }
    db := sql.OpenDB(conn)

Also tried having my factory implement SessionBuilder, and then supplying the raw Capabilities bit flag directly

func (factory) NewSession(ctx context.Context, id uint32, conn *driver.Connector) (msql.Session, error) {
    sess := msql.NewBaseSessionWithClientServer(conn.Server(), msql.Client{
        Address:      "",
        Capabilities: 1 << 16, // copied from "vitess.io/vitess/go/mysql".CapabilityClientMultiStatements
    }, id)
    return memory.NewSession(sess, provider), nil
}

also no luck.

Would anyone be able to point me in the right direction? I am also happy to make a PR if needed. (I have a mysqldump of my db schema which I'm trying to load, as a precursor to tests).

seanlaff commented 7 months ago

Looking further, it seems like the driver dir is a separate implementation from the main server. Perhaps I'd be better off trying something like https://pkg.go.dev/google.golang.org/grpc/test/bufconn as a way to avoid using the host's networking stack- though I'm not sure if I'll be able to thread that through as Handler is all private

seanlaff commented 7 months ago

Closing in favor of https://github.com/dolthub/go-mysql-server/pull/2319, which seems like a better approach