Commit 64f1f035 authored by gwenn's avatar gwenn

Improved Blob support.

parent 09aabd90
......@@ -12,6 +12,7 @@ import "C"
import (
"errors"
"io"
"unsafe"
)
......@@ -19,6 +20,7 @@ import (
type BlobReader struct {
c *Conn
bl *C.sqlite3_blob
size int
ReadOffset int
}
......@@ -39,7 +41,7 @@ func (c *Conn) NewBlobReader(db, table, column string, row int64) (*BlobReader,
if err != nil {
return nil, err
}
return &BlobReader{c, bl, 0}, nil
return &BlobReader{c, bl, -1, 0}, nil
}
// NewBlobReadWriter open a BLOB for incremental I/O
......@@ -49,7 +51,7 @@ func (c *Conn) NewBlobReadWriter(db, table, column string, row int64) (*BlobRead
if err != nil {
return nil, err
}
return &BlobReadWriter{BlobReader{c, bl, 0}, 0}, nil
return &BlobReadWriter{BlobReader{c, bl, -1, 0}, 0}, nil
}
func (c *Conn) blob_open(db, table, column string, row int64, write bool) (*C.sqlite3_blob, error) {
......@@ -90,38 +92,67 @@ func (r *BlobReader) Close() error {
// Read reads data from a BLOB incrementally
// (See http://sqlite.org/c3ref/blob_read.html)
func (r *BlobReader) Read(v []byte) (int, error) {
var p *byte
if len(v) > 0 {
p = &v[0]
if len(v) == 0 {
return 0, nil
}
rv := C.sqlite3_blob_read(r.bl, unsafe.Pointer(p), C.int(len(v)), C.int(r.ReadOffset))
size, err := r.Size()
if err != nil {
return 0, err
}
if r.ReadOffset >= size {
return 0, io.EOF
}
if len(v) > (size - r.ReadOffset) {
v = v[0 : size-r.ReadOffset]
}
p := &v[0]
n := len(v)
rv := C.sqlite3_blob_read(r.bl, unsafe.Pointer(p), C.int(n), C.int(r.ReadOffset))
if rv != C.SQLITE_OK {
return 0, r.c.error(rv)
}
r.ReadOffset += len(v)
return len(v), nil
r.ReadOffset += n
return n, nil
}
// Size returns the size of an opened BLOB
// (See http://sqlite.org/c3ref/blob_bytes.html)
func (r *BlobReader) Size() (int, error) {
s := C.sqlite3_blob_bytes(r.bl)
return int(s), nil
if r.bl == nil {
return 0, errors.New("blob reader already closed")
}
if r.size < 0 {
r.size = int(C.sqlite3_blob_bytes(r.bl))
}
return r.size, nil
}
// Write writes data into a BLOB incrementally
// (See http://sqlite.org/c3ref/blob_write.html)
func (w *BlobReadWriter) Write(v []byte) (int, error) {
var p *byte
if len(v) > 0 {
p = &v[0]
if len(v) == 0 {
return 0, nil
}
size, err := w.Size()
if err != nil {
return 0, err
}
if w.WriteOffset >= size {
return 0, io.EOF
}
/* Write must return a non-nil error if it returns n < len(v) */
if len(v) > (size - w.WriteOffset) {
v = v[0 : size-w.WriteOffset]
err = io.EOF
}
rv := C.sqlite3_blob_write(w.bl, unsafe.Pointer(p), C.int(len(v)), C.int(w.WriteOffset))
p := &v[0]
n := len(v)
rv := C.sqlite3_blob_write(w.bl, unsafe.Pointer(p), C.int(n), C.int(w.WriteOffset))
if rv != C.SQLITE_OK {
return 0, w.c.error(rv)
}
w.WriteOffset += len(v)
return len(v), nil
w.WriteOffset += n
return n, err
}
// Reopen moves a BLOB handle to a new row
......@@ -131,6 +162,7 @@ func (r *BlobReader) Reopen(rowid int64) error {
if rv != C.SQLITE_OK {
return r.c.error(rv)
}
r.size = -1
r.ReadOffset = 0
return nil
}
......
......@@ -6,6 +6,7 @@ package sqlite_test
import (
. "github.com/gwenn/gosqlite"
"io"
"testing"
)
......@@ -31,6 +32,7 @@ func TestBlob(t *testing.T) {
content := []byte("Clob")
n, err := bw.Write(content)
checkNoError(t, err, "blob write error: %s")
bw.Close()
br, err := db.NewBlobReader("main", "test", "content", rowid)
checkNoError(t, err, "blob open error: %s")
......@@ -38,7 +40,7 @@ func TestBlob(t *testing.T) {
size, err := br.Size()
checkNoError(t, err, "blob size error: %s")
content = make([]byte, size)
content = make([]byte, size+5)
n, err = br.Read(content[:5])
checkNoError(t, err, "blob read error: %s")
assertEquals(t, "expected %d bytes but got %d", 5, n)
......@@ -47,6 +49,9 @@ func TestBlob(t *testing.T) {
checkNoError(t, err, "blob read error: %s")
assertEquals(t, "expected %d bytes but got %d", 5, n)
//fmt.Printf("%#v\n", content)
n, err = br.Read(content[10:])
assert(t, "error expected", n == 0 && err == io.EOF)
br.Close()
}
......
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