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() {
// ResultText sets the result of an SQL function.
// (See sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html)
func (c *Context) ResultText(s string) {
cs := C.CString(s)
defer C.free(unsafe.Pointer(cs))
C.my_result_text(c.sc, cs, -1)
cs, l := cstring(s)
C.my_result_text(c.sc, cs, l)
}
// ResultValue sets the result of an SQL function.
......@@ -250,7 +249,8 @@ func (c *FunctionContext) Blob(i int) (value []byte) {
p := C.my_value_blob(c.argv, C.int(i))
if p != nil {
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
}
......
......@@ -22,6 +22,7 @@ import (
"errors"
"fmt"
"io"
"reflect"
"unsafe"
)
......@@ -561,3 +562,7 @@ func btocint(b bool) C.int {
}
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) {
defer C.free(unsafe.Pointer(cmdstr))
var stmt *C.sqlite3_stmt
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 {
return nil, c.error(rv, cmd)
}
......@@ -318,10 +319,8 @@ func (s *Stmt) BindByIndex(index int, value interface{}) error {
case nil:
rv = C.sqlite3_bind_null(s.stmt, i)
case string:
cstr := C.CString(value)
rv = C.my_bind_text(s.stmt, i, cstr, C.int(len(value)))
C.free(unsafe.Pointer(cstr))
//rv = C.my_bind_text(s.stmt, i, (*C.char)(unsafe.Pointer(&value)), C.int(len(value)))
cs, l := cstring(value)
rv = C.my_bind_text(s.stmt, i, cs, l)
case int:
rv = C.sqlite3_bind_int(s.stmt, i, C.int(value))
case int64:
......@@ -817,7 +816,8 @@ func (s *Stmt) ScanBlob(index int) (value []byte, isNull bool) {
isNull = true
} else {
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
}
......
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