Named parameters.

This commit is contained in:
Nuno Cruces
2023-02-18 00:47:56 +00:00
parent 5f7a72a553
commit 4ac2ccf473
7 changed files with 79 additions and 7 deletions

8
api.go
View File

@@ -45,12 +45,14 @@ func newConn(ctx context.Context, module api.Module) (_ *Conn, err error) {
exec: getFun("sqlite3_exec"),
clearBindings: getFun("sqlite3_clear_bindings"),
bindCount: getFun("sqlite3_bind_parameter_count"),
bindIndex: getFun("sqlite3_bind_parameter_index"),
bindName: getFun("sqlite3_bind_parameter_name"),
bindNull: getFun("sqlite3_bind_null"),
bindInteger: getFun("sqlite3_bind_int64"),
bindFloat: getFun("sqlite3_bind_double"),
bindText: getFun("sqlite3_bind_text64"),
bindBlob: getFun("sqlite3_bind_blob64"),
bindZeroBlob: getFun("sqlite3_bind_zeroblob64"),
bindNull: getFun("sqlite3_bind_null"),
columnCount: getFun("sqlite3_column_count"),
columnName: getFun("sqlite3_column_name"),
columnType: getFun("sqlite3_column_type"),
@@ -86,13 +88,15 @@ type sqliteAPI struct {
step api.Function
exec api.Function
clearBindings api.Function
bindNull api.Function
bindCount api.Function
bindIndex api.Function
bindName api.Function
bindInteger api.Function
bindFloat api.Function
bindText api.Function
bindBlob api.Function
bindZeroBlob api.Function
bindNull api.Function
columnCount api.Function
columnName api.Function
columnType api.Function

View File

@@ -236,12 +236,12 @@ func (c *Conn) error(rc uint64, sql ...string) error {
r, _ = c.api.errstr.Call(c.ctx, rc)
if r != nil {
err.str = c.mem.readString(uint32(r[0]), 512)
err.str = c.mem.readString(uint32(r[0]), _MAX_STRING)
}
r, _ = c.api.errmsg.Call(c.ctx, uint64(c.handle))
if r != nil {
err.msg = c.mem.readString(uint32(r[0]), 512)
err.msg = c.mem.readString(uint32(r[0]), _MAX_STRING)
}
if sql != nil {

View File

@@ -9,6 +9,7 @@ const (
_UTF8 = 1
_MAX_STRING = 512 // Used for short strings: names, error messages…
_MAX_PATHNAME = 512
ptrlen = 4

View File

@@ -29,12 +29,14 @@ zig cc --target=wasm32-wasi -flto -g0 -Os \
-Wl,--export=sqlite3_exec \
-Wl,--export=sqlite3_clear_bindings \
-Wl,--export=sqlite3_bind_parameter_count \
-Wl,--export=sqlite3_bind_parameter_index \
-Wl,--export=sqlite3_bind_parameter_name \
-Wl,--export=sqlite3_bind_null \
-Wl,--export=sqlite3_bind_int64 \
-Wl,--export=sqlite3_bind_double \
-Wl,--export=sqlite3_bind_text64 \
-Wl,--export=sqlite3_bind_blob64 \
-Wl,--export=sqlite3_bind_zeroblob64 \
-Wl,--export=sqlite3_bind_null \
-Wl,--export=sqlite3_column_count \
-Wl,--export=sqlite3_column_name \
-Wl,--export=sqlite3_column_type \

Binary file not shown.

37
stmt.go
View File

@@ -94,7 +94,7 @@ func (s *Stmt) Exec() error {
return s.Reset()
}
// BindCount gets the number of SQL parameters in a prepared statement.
// BindCount returns the number of SQL parameters in the prepared statement.
//
// https://www.sqlite.org/c3ref/bind_parameter_count.html
func (s *Stmt) BindCount() int {
@@ -106,6 +106,39 @@ func (s *Stmt) BindCount() int {
return int(r[0])
}
// BindIndex returns the index of a parameter in the prepared statement
// given its name.
//
// https://www.sqlite.org/c3ref/bind_parameter_index.html
func (s *Stmt) BindIndex(name string) int {
defer s.c.arena.reset()
namePtr := s.c.arena.string(name)
r, err := s.c.api.bindIndex.Call(s.c.ctx,
uint64(s.handle), uint64(namePtr))
if err != nil {
panic(err)
}
return int(r[0])
}
// BindName returns the name of a parameter in the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_parameter_name.html
func (s *Stmt) BindName(param int) string {
r, err := s.c.api.bindName.Call(s.c.ctx,
uint64(s.handle), uint64(param))
if err != nil {
panic(err)
}
ptr := uint32(r[0])
if ptr == 0 {
return ""
}
return s.c.mem.readString(ptr, _MAX_STRING)
}
// BindBool binds a bool to the prepared statement.
// The leftmost SQL parameter has an index of 1.
// SQLite does not have a separate boolean storage class.
@@ -226,7 +259,7 @@ func (s *Stmt) ColumnName(col int) string {
if ptr == 0 {
return ""
}
return s.c.mem.readString(ptr, 512)
return s.c.mem.readString(ptr, _MAX_STRING)
}
// ColumnType returns the initial [Datatype] of the result column.

View File

@@ -366,3 +366,35 @@ func TestStmt_Close(t *testing.T) {
var stmt *Stmt
stmt.Close()
}
func TestStmt_BindName(t *testing.T) {
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
want := []string{"", "", "", "", "?5", ":AAA", "@AAA", "$AAA"}
stmt, _, err := db.Prepare(`SELECT ?, ?5, :AAA, @AAA, $AAA`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
if got := stmt.BindCount(); got != len(want) {
t.Errorf("got %d, want %d", got, len(want))
}
for i, name := range want {
id := i + 1
if got := stmt.BindName(id); got != name {
t.Errorf("got %q, want %q", got, name)
}
if name == "" {
id = 0
}
if got := stmt.BindIndex(name); got != id {
t.Errorf("got %d, want %d", got, id)
}
}
}