From 0652903b6d82be4cde6a95bc7ac44da5e00268bf Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Tue, 17 Jan 2023 18:31:46 +0000 Subject: [PATCH] Result columns. --- README.md | 1 - cmd/main.go | 10 +++++++ conn.go | 40 ++++++++++++++------------ stmt.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9804793..bb65bf6 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ Roadmap: - [`modernc.org/sqlite`](https://modernc.org/sqlite) Random TODO list: -- wrap more of the SQLite API, enough to run useful queries; - create a Go VFS that's enough to use `:memory:` databases without WASI; - expand that VFS to wrap an `io.ReaderAt`; - optimize small allocations that last a single function call; diff --git a/cmd/main.go b/cmd/main.go index a517408..2476513 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "log" "github.com/ncruces/go-sqlite3" @@ -28,6 +29,15 @@ func main() { log.Fatal(err) } + for { + if row, err := stmt.Step(); err != nil { + log.Fatal(err) + } else if !row { + break + } + fmt.Println(stmt.ColumnInt(0), stmt.ColumnText(1)) + } + err = stmt.Close() if err != nil { log.Fatal(err) diff --git a/conn.go b/conn.go index a961c9c..d59385e 100644 --- a/conn.go +++ b/conn.go @@ -182,46 +182,50 @@ func (c *Conn) new(len uint32) uint32 { } func (c *Conn) newBytes(s []byte) uint32 { - ptr := c.new(uint32(len(s))) - - buf, ok := c.memory.Read(ptr, uint32(len(s))) - if !ok { - c.api.free.Call(context.TODO(), uint64(ptr)) - panic("sqlite3: failed to init bytes") + if s == nil { + return 0 } - copy(buf, s) + siz := uint32(len(s)) + ptr := c.new(siz) + mem, ok := c.memory.Read(ptr, siz) + if !ok { + c.api.free.Call(context.TODO(), uint64(ptr)) + panic("sqlite3: out of range") + } + + copy(mem, s) return ptr } func (c *Conn) newString(s string) uint32 { - ptr := c.new(uint32(len(s) + 1)) - - buf, ok := c.memory.Read(ptr, uint32(len(s)+1)) + siz := uint32(len(s) + 1) + ptr := c.new(siz) + mem, ok := c.memory.Read(ptr, siz) if !ok { c.api.free.Call(context.TODO(), uint64(ptr)) - panic("sqlite3: failed to init string") + panic("sqlite3: out of range") } - buf[len(s)] = 0 - copy(buf, s) + mem[len(s)] = 0 + copy(mem, s) return ptr } func (c *Conn) getString(ptr, maxlen uint32) string { - buf, ok := c.memory.Read(ptr, maxlen) + mem, ok := c.memory.Read(ptr, maxlen) if !ok { if size := c.memory.Size(); ptr < size { - buf, ok = c.memory.Read(ptr, size-ptr) + mem, ok = c.memory.Read(ptr, size-ptr) } if !ok { - panic("sqlite3: invalid pointer") + panic("sqlite3: out of range") } } - if i := bytes.IndexByte(buf, 0); i < 0 { + if i := bytes.IndexByte(mem, 0); i < 0 { panic("sqlite3: missing NUL terminator") } else { - return string(buf[:i]) + return string(mem[:i]) } } diff --git a/stmt.go b/stmt.go index ff5f489..108a957 100644 --- a/stmt.go +++ b/stmt.go @@ -103,3 +103,84 @@ func (s *Stmt) BindNull(param int) error { } return s.c.error(r[0]) } + +func (s *Stmt) ColumnBool(col int) bool { + if i := s.ColumnInt64(col); i != 0 { + return true + } + return false +} + +func (s *Stmt) ColumnInt(col int) int { + return int(s.ColumnInt64(col)) +} + +func (s *Stmt) ColumnInt64(col int) int64 { + r, err := s.c.api.columnInteger.Call(context.TODO(), + uint64(s.handle), uint64(col)) + if err != nil { + panic(err) + } + return int64(r[0]) +} + +func (s *Stmt) ColumnFloat(col int) float64 { + r, err := s.c.api.columnInteger.Call(context.TODO(), + uint64(s.handle), uint64(col)) + if err != nil { + panic(err) + } + return math.Float64frombits(r[0]) +} + +func (s *Stmt) ColumnText(col int) string { + r, err := s.c.api.columnText.Call(context.TODO(), + uint64(s.handle), uint64(col)) + if err != nil { + panic(err) + } + + ptr := uint32(r[0]) + if ptr == 0 { + // handle error + return "" + } + + r, err = s.c.api.columnBytes.Call(context.TODO(), + uint64(s.handle), uint64(col)) + if err != nil { + panic(err) + } + + mem, ok := s.c.memory.Read(ptr, uint32(r[0])) + if !ok { + panic("sqlite3: out of range") + } + return string(mem) +} + +func (s *Stmt) ColumnBlob(col int, buf []byte) int { + r, err := s.c.api.columnBlob.Call(context.TODO(), + uint64(s.handle), uint64(col)) + if err != nil { + panic(err) + } + + ptr := uint32(r[0]) + if ptr == 0 { + // handle error + return 0 + } + + r, err = s.c.api.columnBytes.Call(context.TODO(), + uint64(s.handle), uint64(col)) + if err != nil { + panic(err) + } + + mem, ok := s.c.memory.Read(ptr, uint32(r[0])) + if !ok { + panic("sqlite3: out of range") + } + return copy(mem, buf) +}