bindings/go: Add error propagation from bindings lib

This commit is contained in:
PThorpe92 2025-02-01 14:16:42 -05:00
parent 593febd9a4
commit 1493d499e5
No known key found for this signature in database
GPG key ID: 66DB3FBACBDD05CC
8 changed files with 307 additions and 66 deletions

View file

@ -13,29 +13,39 @@ type limboStmt struct {
mu sync.Mutex
ctx uintptr
sql string
err error
}
func newStmt(ctx uintptr, sql string) *limboStmt {
return &limboStmt{
ctx: uintptr(ctx),
sql: sql,
err: nil,
}
}
func (ls *limboStmt) NumInput() int {
ls.mu.Lock()
defer ls.mu.Unlock()
return int(stmtParamCount(ls.ctx))
res := int(stmtParamCount(ls.ctx))
if res < 0 {
// set the error from rust
_ = ls.getError()
}
return res
}
func (ls *limboStmt) Close() error {
ls.mu.Lock()
res := closeStmt(ls.ctx)
ls.mu.Unlock()
defer ls.mu.Unlock()
if ls.ctx == 0 {
return nil
}
res := stmtClose(ls.ctx)
ls.ctx = 0
if ResultCode(res) != Ok {
return fmt.Errorf("error closing statement: %s", ResultCode(res).String())
}
ls.ctx = 0
return nil
}
@ -52,8 +62,8 @@ func (ls *limboStmt) Exec(args []driver.Value) (driver.Result, error) {
}
var changes uint64
ls.mu.Lock()
defer ls.mu.Unlock()
rc := stmtExec(ls.ctx, argPtr, argCount, uintptr(unsafe.Pointer(&changes)))
ls.mu.Unlock()
switch ResultCode(rc) {
case Ok, Done:
return driver.RowsAffected(changes), nil
@ -66,7 +76,7 @@ func (ls *limboStmt) Exec(args []driver.Value) (driver.Result, error) {
case Invalid:
return nil, errors.New("invalid statement")
default:
return nil, fmt.Errorf("unexpected status: %d", rc)
return nil, ls.getError()
}
}
@ -81,10 +91,10 @@ func (ls *limboStmt) Query(args []driver.Value) (driver.Rows, error) {
argPtr = uintptr(unsafe.Pointer(&queryArgs[0]))
}
ls.mu.Lock()
defer ls.mu.Unlock()
rowsPtr := stmtQuery(ls.ctx, argPtr, uint64(len(queryArgs)))
ls.mu.Unlock()
if rowsPtr == 0 {
return nil, fmt.Errorf("query failed for: %q", ls.sql)
return nil, ls.getError()
}
return newRows(rowsPtr), nil
}
@ -96,27 +106,26 @@ func (ls *limboStmt) ExecContext(ctx context.Context, query string, args []drive
if err != nil {
return nil, err
}
ls.mu.Lock()
select {
case <-ctx.Done():
ls.mu.Unlock()
return nil, ctx.Err()
default:
}
var changes uint64
ls.mu.Lock()
res := stmtExec(ls.ctx, argArray, uint64(len(args)), uintptr(unsafe.Pointer(&changes)))
ls.mu.Unlock()
switch ResultCode(res) {
case Ok, Done:
changes := uint64(changes)
return driver.RowsAffected(changes), nil
case Error:
return nil, errors.New("error executing statement")
case Busy:
return nil, errors.New("busy")
case Interrupt:
return nil, errors.New("interrupted")
default:
return nil, fmt.Errorf("unexpected status: %d", res)
var changes uint64
defer ls.mu.Unlock()
res := stmtExec(ls.ctx, argArray, uint64(len(args)), uintptr(unsafe.Pointer(&changes)))
switch ResultCode(res) {
case Ok, Done:
changes := uint64(changes)
return driver.RowsAffected(changes), nil
case Busy:
return nil, errors.New("Database is Busy")
case Interrupt:
return nil, errors.New("Interrupted")
default:
return nil, ls.getError()
}
}
}
@ -130,16 +139,38 @@ func (ls *limboStmt) QueryContext(ctx context.Context, args []driver.NamedValue)
if len(queryArgs) > 0 {
argsPtr = uintptr(unsafe.Pointer(&queryArgs[0]))
}
ls.mu.Lock()
select {
case <-ctx.Done():
ls.mu.Unlock()
return nil, ctx.Err()
default:
defer ls.mu.Unlock()
rowsPtr := stmtQuery(ls.ctx, argsPtr, uint64(len(queryArgs)))
if rowsPtr == 0 {
return nil, ls.getError()
}
return newRows(rowsPtr), nil
}
ls.mu.Lock()
rowsPtr := stmtQuery(ls.ctx, argsPtr, uint64(len(queryArgs)))
ls.mu.Unlock()
if rowsPtr == 0 {
return nil, fmt.Errorf("query failed for: %q", ls.sql)
}
return newRows(rowsPtr), nil
}
func (ls *limboStmt) Err() error {
if ls.err == nil {
ls.mu.Lock()
defer ls.mu.Unlock()
ls.getError()
}
return ls.err
}
// mutex should always be locked when calling - always called after FFI
func (ls *limboStmt) getError() error {
err := stmtGetError(ls.ctx)
if err == 0 {
return nil
}
defer freeCString(err)
cpy := fmt.Sprintf("%s", GoString(err))
ls.err = errors.New(cpy)
return ls.err
}