diff --git a/build_deps.sh b/build_deps.sh index 3d13d46..f2c1062 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -34,7 +34,8 @@ zig cc --target=wasm32-wasi -flto -g0 -O2 \ -DSQLITE_OMIT_UTF16 \ -Wl,--export=sqlite3_open_v2 \ -Wl,--export=sqlite3_close \ - -Wl,--export=sqlite3_prepare_v2 \ + -Wl,--export=sqlite3_prepare_v3 \ + -Wl,--export=sqlite3_finalize \ -Wl,--export=sqlite3_exec \ -Wl,--export=sqlite3_step \ -Wl,--export=sqlite3_column_text \ diff --git a/cmd/main.go b/cmd/main.go index f419601..1c33bb3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -23,6 +23,16 @@ func main() { log.Fatal(err) } + stmt, _, err := db.Prepare(`SELECT id, name FROM users`, 0) + if err != nil { + log.Fatal(err) + } + + err = stmt.Close() + if err != nil { + log.Fatal(err) + } + err = db.Close() if err != nil { log.Fatal(err) diff --git a/conn.go b/conn.go index b703cdd..3a6c249 100644 --- a/conn.go +++ b/conn.go @@ -56,7 +56,8 @@ func Open(name string, flags uint64, vfs string) (conn *Conn, err error) { errext: module.ExportedFunction("sqlite3_extended_errcode"), open: module.ExportedFunction("sqlite3_open_v2"), close: module.ExportedFunction("sqlite3_close"), - prepare: module.ExportedFunction("sqlite3_prepare_v2"), + prepare: module.ExportedFunction("sqlite3_prepare_v3"), + finalize: module.ExportedFunction("sqlite3_finalize"), exec: module.ExportedFunction("sqlite3_exec"), step: module.ExportedFunction("sqlite3_step"), columnText: module.ExportedFunction("sqlite3_column_text"), @@ -72,7 +73,7 @@ func Open(name string, flags uint64, vfs string) (conn *Conn, err error) { }() namePtr := c.newString(name) - handlePtr := c.newBytes(4) + connPtr := c.newBytes(ptrSize) if flags == 0 { flags = OPEN_READWRITE | OPEN_CREATE @@ -83,13 +84,13 @@ func Open(name string, flags uint64, vfs string) (conn *Conn, err error) { vfsPtr = c.newString(vfs) } - r, err := c.api.open.Call(ctx, uint64(namePtr), uint64(handlePtr), flags, uint64(vfsPtr)) + r, err := c.api.open.Call(ctx, uint64(namePtr), uint64(connPtr), flags, uint64(vfsPtr)) if err != nil { return nil, err } - c.handle, _ = c.memory.ReadUint32Le(handlePtr) - c.free(handlePtr) + c.handle, _ = c.memory.ReadUint32Le(connPtr) + c.free(connPtr) c.free(namePtr) c.free(vfsPtr) @@ -127,6 +128,36 @@ func (c *Conn) Exec(sql string) error { return nil } +func (c *Conn) Prepare(sql string, flags uint64, args ...any) (stmt *Stmt, tail string, err error) { + sqlPtr := c.newString(sql) + stmtPtr := c.newBytes(ptrSize) + tailPtr := c.newBytes(ptrSize) + + r, err := c.api.prepare.Call(context.TODO(), uint64(c.handle), + uint64(sqlPtr), uint64(len(sql)+1), flags, + uint64(stmtPtr), uint64(tailPtr)) + if err != nil { + return nil, "", err + } + + stmt = &Stmt{c: c} + stmt.handle, _ = c.memory.ReadUint32Le(stmtPtr) + i, _ := c.memory.ReadUint32Le(tailPtr) + tail = sql[i-sqlPtr:] + + c.free(tailPtr) + c.free(stmtPtr) + c.free(sqlPtr) + + if r[0] != OK { + return nil, "", c.error(r[0]) + } + if stmt.handle == 0 { + return nil, "", nil + } + return +} + func (c *Conn) error(rc uint64) *Error { serr := Error{Code: int(rc)} @@ -209,6 +240,8 @@ func (c *Conn) getString(ptr, maxlen uint32) string { } } +const ptrSize = 4 + type sqliteAPI struct { malloc api.Function free api.Function @@ -219,6 +252,7 @@ type sqliteAPI struct { open api.Function close api.Function prepare api.Function + finalize api.Function exec api.Function step api.Function columnInt api.Function diff --git a/go.mod b/go.mod index 9a7f7de..5d839fc 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/ncruces/go-sqlite3 go 1.19 -require github.com/tetratelabs/wazero v1.0.0-pre.7 +require github.com/tetratelabs/wazero v1.0.0-pre.7.0.20230114234926-2ce8988ab763 diff --git a/go.sum b/go.sum index bc626fa..d995df7 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,2 @@ -github.com/tetratelabs/wazero v1.0.0-pre.7 h1:WI5N14XxoXw+ZWhcjSazJ6rEowhJbH/x8hglxC5gN7k= -github.com/tetratelabs/wazero v1.0.0-pre.7/go.mod h1:u8wrFmpdrykiFK0DFPiFm5a4+0RzsdmXYVtijBKqUVo= +github.com/tetratelabs/wazero v1.0.0-pre.7.0.20230114234926-2ce8988ab763 h1:cuXa6OWMd3L3+nNrX9SfT6GxS6ykUAvx8/eegN6KeNo= +github.com/tetratelabs/wazero v1.0.0-pre.7.0.20230114234926-2ce8988ab763/go.mod h1:u8wrFmpdrykiFK0DFPiFm5a4+0RzsdmXYVtijBKqUVo= diff --git a/stmt.go b/stmt.go new file mode 100644 index 0000000..90d1b5e --- /dev/null +++ b/stmt.go @@ -0,0 +1,21 @@ +package sqlite3 + +import "context" + +type Stmt struct { + c *Conn + handle uint32 +} + +func (s *Stmt) Close() error { + r, err := s.c.api.finalize.Call(context.TODO(), uint64(s.handle)) + if err != nil { + return err + } + + s.handle = 0 + if r[0] != OK { + return s.c.error(r[0]) + } + return nil +}