Commit c699a930 authored by gwenn's avatar gwenn

Small step toward Virtual table support

parent 24e630f3
...@@ -39,11 +39,12 @@ static int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv, ...@@ -39,11 +39,12 @@ static int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv,
} }
static int cXBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *info) { static int cXBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *info) {
// TODO
return SQLITE_OK; return SQLITE_OK;
} }
static int cXRelease(sqlite3_vtab *pVTab, int isDestroy) { static int cXRelease(sqlite3_vtab *pVTab, int isDestroy) {
char *pzErr = goMRelease(((goVTab*)pVTab)->vTab, isDestroy); char *pzErr = goVRelease(((goVTab*)pVTab)->vTab, isDestroy);
if (pzErr) { if (pzErr) {
if (pVTab->zErrMsg) if (pVTab->zErrMsg)
sqlite3_free(pVTab->zErrMsg); sqlite3_free(pVTab->zErrMsg);
...@@ -63,11 +64,34 @@ static int cXDestroy(sqlite3_vtab *pVTab) { ...@@ -63,11 +64,34 @@ static int cXDestroy(sqlite3_vtab *pVTab) {
return cXRelease(pVTab, 1); return cXRelease(pVTab, 1);
} }
typedef struct goVTabCursor goVTabCursor;
struct goVTabCursor {
sqlite3_vtab_cursor base;
void *vTabCursor;
};
static int cXOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) { static int cXOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
return 0; void *vTabCursor = goVOpen(((goVTab*)pVTab)->vTab, &(pVTab->zErrMsg));
goVTabCursor *pCursor = (goVTabCursor *)sqlite3_malloc(sizeof(goVTabCursor));
if (!pCursor) {
return SQLITE_NOMEM;
}
memset(pCursor, 0, sizeof(goVTabCursor));
pCursor->vTabCursor = vTabCursor;
*ppCursor = (sqlite3_vtab_cursor *)pCursor;
return SQLITE_OK;
} }
static int cXClose(sqlite3_vtab_cursor *pCursor) { static int cXClose(sqlite3_vtab_cursor *pCursor) {
return 0; char *pzErr = goVClose(((goVTabCursor*)pCursor)->vTabCursor);
if (pzErr) {
if (pCursor->pVtab->zErrMsg)
sqlite3_free(pCursor->pVtab->zErrMsg);
pCursor->pVtab->zErrMsg = pzErr;
return SQLITE_ERROR;
}
sqlite3_free(pCursor);
return SQLITE_OK;
} }
static int cXFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) { static int cXFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) {
return 0; return 0;
......
...@@ -17,15 +17,28 @@ import ( ...@@ -17,15 +17,28 @@ import (
"unsafe" "unsafe"
) )
type sqliteModule struct {
c *Conn
name string
module Module
vts map[*sqliteVTab]bool
}
type sqliteVTab struct { type sqliteVTab struct {
c *Conn // TODO Useful? module *sqliteModule
vTab VTab vTab VTab
vtcs map[*sqliteVTabCursor]bool
}
type sqliteVTabCursor struct {
vTab *sqliteVTab
vTabCursor VTabCursor
} }
//export goMInit //export goMInit
func goMInit(db, pClientData unsafe.Pointer, argc int, argv **C.char, pzErr **C.char, isCreate int) unsafe.Pointer { func goMInit(db, pClientData unsafe.Pointer, argc int, argv **C.char, pzErr **C.char, isCreate int) unsafe.Pointer {
udm := (*sqliteModule)(pClientData) m := (*sqliteModule)(pClientData)
if udm.c.db != (*C.sqlite3)(db) { if m.c.db != (*C.sqlite3)(db) {
*pzErr = mPrintf("%s", "Inconsistent db handles") *pzErr = mPrintf("%s", "Inconsistent db handles")
return nil return nil
} }
...@@ -39,45 +52,84 @@ func goMInit(db, pClientData unsafe.Pointer, argc int, argv **C.char, pzErr **C. ...@@ -39,45 +52,84 @@ func goMInit(db, pClientData unsafe.Pointer, argc int, argv **C.char, pzErr **C.
var vTab VTab var vTab VTab
var err error var err error
if isCreate == 1 { if isCreate == 1 {
vTab, err = udm.module.Create(udm.c, args) vTab, err = m.module.Create(m.c, args)
} else { } else {
vTab, err = udm.module.Connect(udm.c, args) vTab, err = m.module.Connect(m.c, args)
} }
if err != nil { if err != nil {
*pzErr = mPrintf("%s", err.Error()) *pzErr = mPrintf("%s", err.Error())
return nil return nil
} }
udt := &sqliteVTab{udm.c, vTab} vt := &sqliteVTab{m, vTab, nil}
// prevents 'vt' from being gced
if m.vts == nil {
m.vts = make(map[*sqliteVTab]bool)
}
m.vts[vt] = true
*pzErr = nil *pzErr = nil
return unsafe.Pointer(udt) return unsafe.Pointer(vt)
} }
//export goMRelease //export goVRelease
func goMRelease(pVTab unsafe.Pointer, isDestroy int) *C.char { func goVRelease(pVTab unsafe.Pointer, isDestroy int) *C.char {
udt := (*sqliteVTab)(pVTab) vt := (*sqliteVTab)(pVTab)
var err error var err error
if isDestroy == 1 { if isDestroy == 1 {
err = udt.vTab.Destroy() err = vt.vTab.Destroy()
} else { } else {
err = udt.vTab.Disconnect() err = vt.vTab.Disconnect()
} }
if err != nil { if err != nil {
return mPrintf("%s", err.Error()) return mPrintf("%s", err.Error())
} }
// TODO Check vt.vtcs is empty
vt.vtcs = nil
delete(vt.module.vts, vt)
return nil
}
//export goVOpen
func goVOpen(pVTab unsafe.Pointer, pzErr **C.char) unsafe.Pointer {
vt := (*sqliteVTab)(pVTab)
vTabCursor, err := vt.vTab.Open()
if err != nil {
*pzErr = mPrintf("%s", err.Error())
return nil
}
// prevents 'vt' from being gced
vtc := &sqliteVTabCursor{vt, vTabCursor}
if vt.vtcs == nil {
vt.vtcs = make(map[*sqliteVTabCursor]bool)
}
vt.vtcs[vtc] = true
*pzErr = nil
return unsafe.Pointer(vtc)
}
//export goVClose
func goVClose(pCursor unsafe.Pointer) *C.char {
vtc := (*sqliteVTabCursor)(pCursor)
err := vtc.vTabCursor.Close()
if err != nil {
return mPrintf("%s", err.Error())
}
delete(vtc.vTab.vtcs, vtc)
return nil return nil
} }
//export goMDestroy //export goMDestroy
func goMDestroy(pClientData unsafe.Pointer) { func goMDestroy(pClientData unsafe.Pointer) {
udm := (*sqliteModule)(pClientData) m := (*sqliteModule)(pClientData)
udm.module.Destroy() m.module.Destroy()
delete(udm.c.modules, udm.name) // TODO Check m.vts is empty
m.vts = nil
delete(m.c.modules, m.name)
} }
//export goXNext //export goXNext
func goXNext(cursor unsafe.Pointer) C.int { func goXNext(pCursor unsafe.Pointer) C.int {
//c := (*VTableCursor)(cursor) //vtc := (*sqliteVTabCursor)(pCursor)
return 0 return 0
} }
...@@ -124,10 +176,6 @@ type VTabCursor interface { ...@@ -124,10 +176,6 @@ type VTabCursor interface {
Rowid() (int64, error) // See http://sqlite.org/vtab.html#xrowid Rowid() (int64, error) // See http://sqlite.org/vtab.html#xrowid
} }
type vTabCursor struct {
base *C.sqlite3_vtab_cursor
}
// DeclareVTab declares the Schema of a virtual table. // DeclareVTab declares the Schema of a virtual table.
// (See http://sqlite.org/c3ref/declare_vtab.html) // (See http://sqlite.org/c3ref/declare_vtab.html)
func (c *Conn) DeclareVTab(sql string) error { func (c *Conn) DeclareVTab(sql string) error {
...@@ -136,19 +184,13 @@ func (c *Conn) DeclareVTab(sql string) error { ...@@ -136,19 +184,13 @@ func (c *Conn) DeclareVTab(sql string) error {
return c.error(C.sqlite3_declare_vtab(c.db, zSQL)) return c.error(C.sqlite3_declare_vtab(c.db, zSQL))
} }
type sqliteModule struct {
c *Conn
name string
module Module
}
// CreateModule registers a virtual table implementation. // CreateModule registers a virtual table implementation.
// (See http://sqlite.org/c3ref/create_module.html) // (See http://sqlite.org/c3ref/create_module.html)
func (c *Conn) CreateModule(moduleName string, module Module) error { func (c *Conn) CreateModule(moduleName string, module Module) error {
mname := C.CString(moduleName) mname := C.CString(moduleName)
defer C.free(unsafe.Pointer(mname)) defer C.free(unsafe.Pointer(mname))
// To make sure it is not gced, keep a reference in the connection. // To make sure it is not gced, keep a reference in the connection.
udm := &sqliteModule{c, moduleName, module} udm := &sqliteModule{c, moduleName, module, nil}
if len(c.modules) == 0 { if len(c.modules) == 0 {
c.modules = make(map[string]*sqliteModule) c.modules = make(map[string]*sqliteModule)
} }
...@@ -168,15 +210,15 @@ CreateModule( int sqlite3_create_module_v2( ...@@ -168,15 +210,15 @@ CreateModule( int sqlite3_create_module_v2(
goModule sqlite3_module { goModule sqlite3_module {
|- int iVersion |- int iVersion
x |- int (*xCreate)(sqlite3*, void *pAux, int argc, char **argv, sqlite3_vtab **ppVTab, goMInit |- int (*xCreate)(sqlite3*, void *pAux, int argc, char **argv, sqlite3_vtab **ppVTab,
char **pzErr) char **pzErr)
x |- int (*xConnect)(sqlite3*, void *pAux, int argc, char **argv, sqlite3_vtab **ppVTab, goMInit |- int (*xConnect)(sqlite3*, void *pAux, int argc, char **argv, sqlite3_vtab **ppVTab,
char **pzErr) char **pzErr)
x |- int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*) x |- int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*)
x |- int (*xDisconnect)(sqlite3_vtab *pVTab) goVRelease |- int (*xDisconnect)(sqlite3_vtab *pVTab)
x |- int (*xDestroy)(sqlite3_vtab *pVTab) goVRelease |- int (*xDestroy)(sqlite3_vtab *pVTab)
x |- int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) goVOpen |- int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor)
x |- int (*xClose)(sqlite3_vtab_cursor*) goVClose |- int (*xClose)(sqlite3_vtab_cursor*)
x |- int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, x |- int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc,
sqlite3_value **argv) sqlite3_value **argv)
x |- int (*xNext)(sqlite3_vtab_cursor*) x |- int (*xNext)(sqlite3_vtab_cursor*)
...@@ -201,7 +243,7 @@ o \- int (*xRollbackTo)(sqlite3_vtab *pVTab, ...@@ -201,7 +243,7 @@ o \- int (*xRollbackTo)(sqlite3_vtab *pVTab,
\- const char *zCreateTable \- const char *zCreateTable
) )
? sqlite3_vtab { (Created by xCreate/xConnect) sqliteVTab sqlite3_vtab { (Created by xCreate/xConnect)
|- const sqlite3_module *pModule |- const sqlite3_module *pModule
|- int nRef |- int nRef
|- char *zErrMsg |- char *zErrMsg
......
...@@ -16,6 +16,9 @@ type testModule struct { ...@@ -16,6 +16,9 @@ type testModule struct {
type testVTab struct { type testVTab struct {
} }
type testVTabCursor struct {
}
func (m testModule) Create(c *Conn, args []string) (VTab, error) { func (m testModule) Create(c *Conn, args []string) (VTab, error) {
//println("testVTab.Create") //println("testVTab.Create")
assert(m.t, "Six arguments expected", len(args) == 6) assert(m.t, "Six arguments expected", len(args) == 6)
...@@ -50,8 +53,33 @@ func (v testVTab) Destroy() error { ...@@ -50,8 +53,33 @@ func (v testVTab) Destroy() error {
return nil return nil
} }
func (v testVTab) Open() (VTabCursor, error) { func (v testVTab) Open() (VTabCursor, error) {
println("testVTab.Open") //println("testVTab.Open")
return nil, nil return testVTabCursor{}, nil
}
func (v testVTabCursor) Close() error {
//println("testVTabCursor.Close")
return nil
}
func (v testVTabCursor) Filter(idxNum int, idxStr string /*, int argc, sqlite3_value **argv*/) error {
println("testVTabCursor.Filter")
return nil
}
func (v testVTabCursor) Next() error {
println("testVTabCursor.Next")
return nil
}
func (v testVTabCursor) Eof() bool {
println("testVTabCursor.Eof")
return true
}
func (v testVTabCursor) Column(c *Context, col int) error {
println("testVTabCursor.Column")
return nil
}
func (v testVTabCursor) Rowid() (int64, error) {
println("testVTabCursor.Rowid")
return 1, nil
} }
func TestCreateModule(t *testing.T) { func TestCreateModule(t *testing.T) {
...@@ -61,6 +89,11 @@ func TestCreateModule(t *testing.T) { ...@@ -61,6 +89,11 @@ func TestCreateModule(t *testing.T) {
checkNoError(t, err, "couldn't create module: %s") checkNoError(t, err, "couldn't create module: %s")
err = db.Exec("CREATE VIRTUAL TABLE vtab USING test('1', 2, three)") err = db.Exec("CREATE VIRTUAL TABLE vtab USING test('1', 2, three)")
checkNoError(t, err, "couldn't create virtual table: %s") checkNoError(t, err, "couldn't create virtual table: %s")
var value *string
err = db.OneValue("SELECT * from vtab", &value)
checkNoError(t, err, "couldn't select from virtual table: %s")
//assert(t, "Not null value expected", value != nil)
//assertEquals(t, "Expected '%s' but got '%s'", "test", *value)
err = db.Exec("DROP TABLE vtab") err = db.Exec("DROP TABLE vtab")
checkNoError(t, err, "couldn't drop virtual table: %s") checkNoError(t, err, "couldn't drop virtual table: %s")
} }
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