Commit 94e8b9c4 authored by gwenn's avatar gwenn

Adds blob support.

parent c22f0a7c
......@@ -10,6 +10,7 @@ CGOFILES=\
sqlite.go\
backup.go\
meta.go\
trace.go
trace.go\
blob.go
include $(GOROOT)/src/Make.pkg
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package sqlite provides access to the SQLite library, version 3.
package sqlite
/*
#include <sqlite3.h>
#include <stdlib.h>
*/
import "C"
import (
"os"
"unsafe"
)
type BlobReader struct {
c *Conn
bl *C.sqlite3_blob
}
type BlobReadWriter struct {
BlobReader
}
type ZeroBlobLength int
func (c *Conn) NewBlobReader(db, table, column string, row int64) (*BlobReader, os.Error) {
bl, err := c.blob_open(db, table, column, row, false)
if err != nil {
return nil, err
}
return &BlobReader{c, bl}, nil
}
func (c *Conn) NewBlobReadWriter(db, table, column string, row int64) (*BlobReadWriter, os.Error) {
bl, err := c.blob_open(db, table, column, row, true)
if err != nil {
return nil, err
}
return &BlobReadWriter{BlobReader{c, bl}}, nil
}
func (c *Conn) blob_open(db, table, column string, row int64, write bool) (*C.sqlite3_blob, os.Error) {
zDb := C.CString(db)
defer C.free(unsafe.Pointer(zDb))
zTable := C.CString(table)
defer C.free(unsafe.Pointer(zTable))
zColumn := C.CString(column)
defer C.free(unsafe.Pointer(zColumn))
var bl *C.sqlite3_blob
rv := C.sqlite3_blob_open(c.db, zDb, zTable, zColumn, C.sqlite3_int64(row), btocint(write), &bl)
if rv != C.SQLITE_OK {
if bl != nil {
C.sqlite3_blob_close(bl)
}
return nil, c.error(rv)
}
if bl == nil {
return nil, os.NewError("sqlite succeeded without returning a blob")
}
return bl, nil
}
func (r *BlobReader) Close() os.Error {
rv := C.sqlite3_blob_close(r.bl)
if rv != C.SQLITE_OK {
return r.c.error(rv)
}
r.bl = nil
return nil
}
func (r *BlobReader) Read(v []byte) (int, os.Error) {
var p *byte
if len(v) > 0 {
p = &v[0]
}
rv := C.sqlite3_blob_read(r.bl, unsafe.Pointer(p), C.int(len(v)), 0) // TODO offset
if rv != C.SQLITE_OK {
return 0, r.c.error(rv)
}
return len(v), nil
}
func (r *BlobReader) Size() (int, os.Error) {
s := C.sqlite3_blob_bytes(r.bl)
return int(s), nil
}
func (w *BlobReadWriter) Write(v []byte) (int, os.Error) {
var p *byte
if len(v) > 0 {
p = &v[0]
}
rv := C.sqlite3_blob_write(w.bl, unsafe.Pointer(p), C.int(len(v)), 0) // TODO offset
if rv != C.SQLITE_OK {
return 0, w.c.error(rv)
}
return len(v), nil
}
func (r *BlobReader) Reopen(rowid int64) os.Error {
rv := C.sqlite3_blob_reopen(r.bl, C.sqlite3_int64(rowid))
if rv != C.SQLITE_OK {
return r.c.error(rv)
}
return nil
}
......@@ -345,6 +345,10 @@ func (s *Stmt) Bind(args ...interface{}) os.Error {
p = &v[0]
}
rv = C.my_bind_blob(s.stmt, index, unsafe.Pointer(p), C.int(len(v)))
case ZeroBlobLength:
rv = C.sqlite3_bind_zeroblob(s.stmt, index, C.int(v))
default:
return os.NewError("unsupported type in Bind: " + reflect.TypeOf(v).String())
}
if rv != C.SQLITE_OK {
return s.c.error(rv)
......
......@@ -25,7 +25,7 @@ func open(t *testing.T) *Conn {
t.Fatal("opened database is nil")
}
//db.Trace(trace, "TRACE")
//db.SetAuthorizer(authorizer, "AUTH") FIXME panic
//db.SetAuthorizer(authorizer, "AUTH")
return db
}
......@@ -275,6 +275,60 @@ func TestForeignKeys(t *testing.T) {
}
}
func TestBlob(t *testing.T) {
db := open(t)
defer db.Close()
err := db.Exec("CREATE TABLE test (content BLOB);")
if err != nil {
t.Fatalf("error creating tables: %s", err)
}
s, err := db.Prepare("INSERT INTO test VALUES (?)")
if err != nil {
t.Fatalf("prepare error: %s", err)
}
if s == nil {
t.Fatal("statement is nil")
}
defer s.Finalize()
err = s.Exec(ZeroBlobLength(10))
if err != nil {
t.Fatalf("insert error: %s", err)
}
rowid := db.LastInsertRowid()
bw, err := db.NewBlobReadWriter("main", "test", "content", rowid)
if err != nil {
t.Fatalf("blob open error: %s", err)
}
defer bw.Close()
content := []byte("Clob")
n, err := bw.Write(content)
if err != nil {
t.Fatalf("blob write error: %s", err)
}
br, err := db.NewBlobReader("main", "test", "content", rowid)
if err != nil {
t.Fatalf("blob open error: %s", err)
}
defer br.Close()
size, err := br.Size()
if err != nil {
t.Fatalf("blob size error: %s", err)
}
content = make([]byte, size)
n, err = br.Read(content)
if err != nil {
t.Fatalf("blob read error: %s", err)
}
if n != 10 {
t.Fatalf("Expected 10 bytes <> %d", n)
}
//fmt.Printf("%#v\n", content)
br.Close()
}
func BenchmarkScan(b *testing.B) {
b.StopTimer()
db, _ := Open("")
......
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