mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-07-19 18:35:01 +00:00
121 lines
2 KiB
Go
121 lines
2 KiB
Go
package limbo
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"sync"
|
|
)
|
|
|
|
type limboRows struct {
|
|
mu sync.Mutex
|
|
ctx uintptr
|
|
columns []string
|
|
err error
|
|
closed bool
|
|
}
|
|
|
|
func newRows(ctx uintptr) *limboRows {
|
|
return &limboRows{
|
|
mu: sync.Mutex{},
|
|
ctx: ctx,
|
|
columns: nil,
|
|
err: nil,
|
|
closed: false,
|
|
}
|
|
}
|
|
|
|
func (r *limboRows) isClosed() bool {
|
|
if r.ctx == 0 || r.closed {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (r *limboRows) Columns() []string {
|
|
if r.isClosed() {
|
|
return nil
|
|
}
|
|
if r.columns == nil {
|
|
r.mu.Lock()
|
|
count := rowsGetColumns(r.ctx)
|
|
if count > 0 {
|
|
columns := make([]string, 0, count)
|
|
for i := 0; i < int(count); i++ {
|
|
cstr := rowsGetColumnName(r.ctx, int32(i))
|
|
columns = append(columns, fmt.Sprintf("%s", GoString(cstr)))
|
|
freeCString(cstr)
|
|
}
|
|
r.mu.Unlock()
|
|
r.columns = columns
|
|
}
|
|
}
|
|
return r.columns
|
|
}
|
|
|
|
func (r *limboRows) Close() error {
|
|
r.err = errors.New(RowsClosedErr)
|
|
if r.isClosed() {
|
|
return r.err
|
|
}
|
|
r.mu.Lock()
|
|
r.closed = true
|
|
closeRows(r.ctx)
|
|
r.ctx = 0
|
|
r.mu.Unlock()
|
|
return nil
|
|
}
|
|
|
|
func (r *limboRows) Err() error {
|
|
if r.err == nil {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.getError()
|
|
}
|
|
return r.err
|
|
}
|
|
|
|
func (r *limboRows) Next(dest []driver.Value) error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
if r.isClosed() {
|
|
return r.err
|
|
}
|
|
for {
|
|
status := rowsNext(r.ctx)
|
|
switch ResultCode(status) {
|
|
case Row:
|
|
for i := range dest {
|
|
valPtr := rowsGetValue(r.ctx, int32(i))
|
|
val := toGoValue(valPtr)
|
|
if val == nil {
|
|
r.getError()
|
|
}
|
|
dest[i] = val
|
|
}
|
|
return nil
|
|
case Io:
|
|
continue
|
|
case Done:
|
|
return io.EOF
|
|
default:
|
|
return r.getError()
|
|
}
|
|
}
|
|
}
|
|
|
|
// mutex will already be locked. this is always called after FFI
|
|
func (r *limboRows) getError() error {
|
|
if r.isClosed() {
|
|
return r.err
|
|
}
|
|
err := rowsGetError(r.ctx)
|
|
if err == 0 {
|
|
return nil
|
|
}
|
|
defer freeCString(err)
|
|
cpy := fmt.Sprintf("%s", GoString(err))
|
|
r.err = errors.New(cpy)
|
|
return r.err
|
|
}
|