Commit c1430720 authored by gwenn's avatar gwenn

Fix text binding and blob scanning.

When specifying SQLITE_TRANSIENT, SQLite makes a copy of the string
so we can pass directly a pointer when calling sqlite3_bind_text/
sqlite3_result_text.
On the other hand, when loading blobs with sqlite3_column_bytes/
sqlite3_value_bytes, we must make a copy.
parent f9f92f05
...@@ -193,9 +193,8 @@ func (c *Context) ResultNull() { ...@@ -193,9 +193,8 @@ func (c *Context) ResultNull() {
// ResultText sets the result of an SQL function. // ResultText sets the result of an SQL function.
// (See sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html) // (See sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html)
func (c *Context) ResultText(s string) { func (c *Context) ResultText(s string) {
cs := C.CString(s) cs, l := cstring(s)
defer C.free(unsafe.Pointer(cs)) C.my_result_text(c.sc, cs, l)
C.my_result_text(c.sc, cs, -1)
} }
// ResultValue sets the result of an SQL function. // ResultValue sets the result of an SQL function.
...@@ -250,7 +249,8 @@ func (c *FunctionContext) Blob(i int) (value []byte) { ...@@ -250,7 +249,8 @@ func (c *FunctionContext) Blob(i int) (value []byte) {
p := C.my_value_blob(c.argv, C.int(i)) p := C.my_value_blob(c.argv, C.int(i))
if p != nil { if p != nil {
n := C.my_value_bytes(c.argv, C.int(i)) n := C.my_value_bytes(c.argv, C.int(i))
value = (*[1 << 30]byte)(unsafe.Pointer(p))[:n] // value = (*[1 << 30]byte)(unsafe.Pointer(p))[:n]
value = C.GoBytes(p, n) // The memory space used to hold strings and BLOBs is freed automatically.
} }
return return
} }
......
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"reflect"
"unsafe" "unsafe"
) )
...@@ -561,3 +562,7 @@ func btocint(b bool) C.int { ...@@ -561,3 +562,7 @@ func btocint(b bool) C.int {
} }
return 0 return 0
} }
func cstring(s string) (*C.char, C.int) {
cs := *(*reflect.StringHeader)(unsafe.Pointer(&s))
return (*C.char)(unsafe.Pointer(cs.Data)), C.int(cs.Len)
}
...@@ -92,7 +92,8 @@ func (c *Conn) prepare(cmd string, args ...interface{}) (*Stmt, error) { ...@@ -92,7 +92,8 @@ func (c *Conn) prepare(cmd string, args ...interface{}) (*Stmt, error) {
defer C.free(unsafe.Pointer(cmdstr)) defer C.free(unsafe.Pointer(cmdstr))
var stmt *C.sqlite3_stmt var stmt *C.sqlite3_stmt
var tail *C.char var tail *C.char
rv := C.my_prepare_v2(c.db, cmdstr, -1, &stmt, &tail) // If the caller knows that the supplied string is nul-terminated, then there is a small performance advantage to be gained by passing an nByte parameter that is equal to the number of bytes in the input string including the nul-terminator bytes as this saves SQLite from having to make a copy of the input string.
rv := C.my_prepare_v2(c.db, cmdstr, C.int(len(cmd)+1), &stmt, &tail)
if rv != C.SQLITE_OK { if rv != C.SQLITE_OK {
return nil, c.error(rv, cmd) return nil, c.error(rv, cmd)
} }
...@@ -318,10 +319,8 @@ func (s *Stmt) BindByIndex(index int, value interface{}) error { ...@@ -318,10 +319,8 @@ func (s *Stmt) BindByIndex(index int, value interface{}) error {
case nil: case nil:
rv = C.sqlite3_bind_null(s.stmt, i) rv = C.sqlite3_bind_null(s.stmt, i)
case string: case string:
cstr := C.CString(value) cs, l := cstring(value)
rv = C.my_bind_text(s.stmt, i, cstr, C.int(len(value))) rv = C.my_bind_text(s.stmt, i, cs, l)
C.free(unsafe.Pointer(cstr))
//rv = C.my_bind_text(s.stmt, i, (*C.char)(unsafe.Pointer(&value)), C.int(len(value)))
case int: case int:
rv = C.sqlite3_bind_int(s.stmt, i, C.int(value)) rv = C.sqlite3_bind_int(s.stmt, i, C.int(value))
case int64: case int64:
...@@ -817,7 +816,8 @@ func (s *Stmt) ScanBlob(index int) (value []byte, isNull bool) { ...@@ -817,7 +816,8 @@ func (s *Stmt) ScanBlob(index int) (value []byte, isNull bool) {
isNull = true isNull = true
} else { } else {
n := C.sqlite3_column_bytes(s.stmt, C.int(index)) n := C.sqlite3_column_bytes(s.stmt, C.int(index))
value = (*[1 << 30]byte)(unsafe.Pointer(p))[:n] // value = (*[1 << 30]byte)(unsafe.Pointer(p))[:n]
value = C.GoBytes(p, n) // The memory space used to hold strings and BLOBs is freed automatically.
} }
return return
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment