qustavo / sqlhooks

Attach hooks to any database/sql driver
MIT License
646 stars 44 forks source link

runtime error: comparing uncomparable type mssql.Error #56

Open tochka opened 1 month ago

tochka commented 1 month ago

I've got a panic when using your library (2.1.0) with github.com/microsoft/go-mssqldb@v1.7.2 sql driver.

Stack trace

/usr/local/go/src/runtime/panic.go:770 +0x124
github.com/qustavo/sqlhooks/v2.composed.OnError({0x14000a5a650?, 0x2?, 0x104ad1740?}, {0x1051a44d8, 0x140009884e0}, {0x10517a120, 0x14000acade0}, {0x1043e2b1a, 0x23}, {0x1400073c940, ...})
    /Users/vvinogradov/go/pkg/mod/github.com/qustavo/sqlhooks/v2@v2.1.0/compose.go:52 +0xfc
github.com/qustavo/sqlhooks/v2.handlerErr({0x1051a44d8?, 0x140009884e0?}, {0x1051851f0?, 0x14000915908?}, {0x10517a120, 0x14000acade0}, {0x1043e2b1a?, 0x23?}, {0x1400073c940?, 0x2?, ...})
    /Users/vvinogradov/go/pkg/mod/github.com/qustavo/sqlhooks/v2@v2.1.0/sqlhooks.go:32 +0x8c
github.com/qustavo/sqlhooks/v2.(*Stmt).QueryContext(0x140009884b0, {0x1051a4430, 0x106abf780}, {0x14000534a50, 0x2, 0x2})
    /Users/vvinogradov/go/pkg/mod/github.com/qustavo/sqlhooks/v2@v2.1.0/sqlhooks.go:312 +0x1c4
database/sql.ctxDriverStmtQuery({0x1051a4430, 0x106abf780}, {0x1051a56c8, 0x140009884b0}, {0x14000534a50, 0x2, 0x2?})
    /usr/local/go/src/database/sql/ctxutil.go:82 +0x9c
database/sql.rowsiFromStatement({0x1051a4430, 0x106abf780}, {0x1051935e0, 0x1400073c900}, 0x1400095d640, {0x14000a91828, 0x2, 0x2})
    /usr/local/go/src/database/sql/sql.go:2836 +0x118
database/sql.(*DB).queryDC(0x14000856a90?, {0x1051a4430, 0x106abf780}, {0x0, 0x0}, 0x14000d8abd0, 0x14000c71e40, {0x1043e2b1a, 0x23}, {0x14000a91828, ...})
    /usr/local/go/src/database/sql/sql.go:1806 +0x26c
database/sql.(*DB).query(0x14000856a90, {0x1051a4430, 0x106abf780}, {0x1043e2b1a, 0x23}, {0x14000a91828, 0x2, 0x2}, 0x0?)
    /usr/local/go/src/database/sql/sql.go:1754 +0xb4
database/sql.(*DB).QueryContext.func1(0xf8?)
    /usr/local/go/src/database/sql/sql.go:1732 +0x54
database/sql.(*DB).retry(0x58?, 0x14000a91630)
    /usr/local/go/src/database/sql/sql.go:1566 +0x4c
database/sql.(*DB).QueryContext(0x104e3c2e0?, {0x1051a4430?, 0x106abf780?}, {0x1043e2b1a?, 0x1400014af00?}, {0x14000a91828?, 0x14000a91718?, 0x104312878?})
    /usr/local/go/src/database/sql/sql.go:1731 +0x94
database/sql.(*DB).Query(...)
    /usr/local/go/src/database/sql/sql.go:1745
qustavo commented 1 month ago

can you provide the code you are using?

tochka commented 1 month ago
package mssql_test

import (
    "context"
    "database/sql"
    "database/sql/driver"
    "fmt"
    "net"
    "testing"

    "github.com/docker/docker/api/types/container"
    "github.com/docker/go-connections/nat"
    gomssql "github.com/microsoft/go-mssqldb"
    "github.com/qustavo/sqlhooks/v2"
    "github.com/stretchr/testify/require"
    "github.com/testcontainers/testcontainers-go"
    "github.com/testcontainers/testcontainers-go/wait"
)

const ddlTestFunc = `create procedure test_proc  AS
begin
    DECLARE @ErrorMsg varchar(7000)

    SET NOCOUNT ON;
    select @ErrorMsg = 'Test error'
    raiserror(@ErrorMsg, 16, 1)
    return
end;`

func TestMsSQL(t *testing.T) {
    ctx := context.Background()
    req := testcontainers.ContainerRequest{
        Image:        "mcr.microsoft.com/mssql/server:2019-latest",
        ExposedPorts: []string{"1433/tcp"},
        SkipReaper:   true,
        Env: map[string]string{
            "ACCEPT_EULA":       "Y",
            "MSSQL_PID":         "Evaluation",
            "MSSQL_SA_PASSWORD": "Test87654321",
        },
        WaitingFor: wait.ForSQL("1433/tcp", "sqlserver", func(host string, port nat.Port) string {
            return fmt.Sprintf("sqlserver://sa:Test87654321@%s/master", net.JoinHostPort(host, port.Port()))
        }),
        HostConfigModifier: func(hc *container.HostConfig) {
            hc.AutoRemove = true
        },
    }
    container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
        ContainerRequest: req,
        Started:          true,
        Logger:           testcontainers.TestLogger(t),
    })
    require.NoError(t, err)

    t.Cleanup(func() {
        container.Stop(ctx, nil)
    })

    hostPort, err := container.PortEndpoint(ctx, "1433/tcp", "")
    require.NoError(t, err)

    connStr := fmt.Sprintf("sqlserver://sa:Test87654321@%s/master", hostPort)
    t.Log(connStr)

    db := openDB(connStr, []sqlhooks.Hooks{simpleHook{}})

    _, err = db.Exec(ddlTestFunc)
    require.NoError(t, err)

    _, err = db.Exec(`EXEC test_proc`)
    require.Error(t, err, "error is: %v", err)
}

type simpleHook struct{}

func (h simpleHook) Before(ctx context.Context, query string, args ...interface{}) (context.Context, error) {
    return ctx, nil
}
func (h simpleHook) After(ctx context.Context, query string, args ...interface{}) (context.Context, error) {
    return ctx, nil
}
func (h simpleHook) OnError(ctx context.Context, err error, query string, args ...interface{}) error {
    return err
}

// openDB opens new sql DB pool with an optional hooks and optional tracing.
func openDB(dsn string, hooks []sqlhooks.Hooks) *sql.DB {
    var drv driver.Driver = &gomssql.Driver{}

    if len(hooks) > 0 {
        drv = sqlhooks.Wrap(drv, sqlhooks.Compose(hooks...))
    }

    // Open DB connections pool.
    return sql.OpenDB(&connector{
        driver: drv, dsn: dsn,
    })
}

// connector is a connector with dsn and driver.
type connector struct {
    driver driver.Driver
    dsn    string
}

// Connect returns a connection to the database.
func (c *connector) Connect(_ context.Context) (driver.Conn, error) {
    return c.driver.Open(c.dsn)
}

// Driver returns the underlying Driver of the Connector.
func (c *connector) Driver() driver.Driver {
    return c.driver
}
tochka commented 1 month ago

@qustavo Do you have any news about the panic?

qustavo commented 1 month ago

sorry @tochka for the late reply. Unfortunately I haven't had the capacity nor the possibility to experiment with mssql. Have you tried to debug it?