denisenkom / go-mssqldb

Microsoft SQL server driver written in go language
BSD 3-Clause "New" or "Revised" License
1.82k stars 500 forks source link

Used with procedure #632

Closed 370750149 closed 3 years ago

370750149 commented 3 years ago

While I used and tracked the code,like: golang's version is 1.15.3,go-mssqldb's version is v0.9.0 1.my code: tx, err := db.Begin()

if err != nil {
    log.Error(err)
    return err
}
_,err=tx.ExecContext(context.TODO(),"dbo.sp_xxx",sql.Named("flag",sql.Out{Dest:&flag}),sql.Named("msg",sql.Out{Dest:&msg}))

2.golang code 'database/sql.go' at line 1553

func (db *DB) execDC(ctx context.Context, dc *driverConn, release func(error), query string, args []interface{}) (res Result, err error) {
    defer func() {
        release(err)
    }()
    execerCtx, ok := dc.ci.(driver.ExecerContext)
    var execer driver.Execer
    if !ok {
        execer, ok = dc.ci.(driver.Execer)
    }
    if ok {
        var nvdargs []driver.NamedValue
        var resi driver.Result
        withLock(dc, func() {
            nvdargs, err = driverArgsConnLocked(dc.ci, nil, args)
            if err != nil {
                return
            }
            resi, err = ctxDriverExec(ctx, execerCtx, execer, query, nvdargs)
        })
        if err != driver.ErrSkip {
            if err != nil {
                return nil, err
            }
            return driverResult{dc, resi}, nil
        }
    }

    var si driver.Stmt
    withLock(dc, func() {
        si, err = ctxDriverPrepare(ctx, dc.ci, query)
    })
    if err != nil {
        return nil, err
    }
    ds := &driverStmt{Locker: dc, si: si}
    defer ds.Close()
    return resultFromStatement(ctx, dc.ci, ds, args...)
}

at:

execerCtx, ok := dc.ci.(driver.ExecerContext)
    var execer driver.Execer
    if !ok {
        execer, ok = dc.ci.(driver.Execer)
    }

parameter "dc.ci" is reference to "*.../go-mssqldb/Conn",then I read the source code,found the Struct "Conn" not implement the interface "driver.Execer" or "driver.ExecerContext" at last,the code run as the query statment and painc error,expect 0 arguments,got 2. What's the right way to call the procedure and handle output parameter values?

370750149 commented 3 years ago

I'm sorry for bad code. my code: _,err=tx.ExecContext(context.TODO(),"dbo.sp_xxx :flag,:msg", sql.Named("flag",sql.Out{Dest:&flag}),sql.Named("msg",sql.Out{Dest:&msg})) and I get a mssql error like ''formal parameter @flag not defind to output..." Two hours later,I read the source code,foud in file mssql.go at line 561: decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+offset].ti)) the value like @flag nvarchar(max) but '@flag' is an output parameter then I change to:

if params[i+offset].Flags==1 {
            decls[i] = fmt.Sprintf("%s %s output", name, makeDecl(params[i+offset].ti))
        } else {
            decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+offset].ti))
        }

the value like: @flag nvarchar(max) output and it run success! I don't known what is the usuage that property 'Flags' in struct 'param',what trouble will be happend after the source code changed?