From 32ab0d8730130a4e69e06861571a84bcba3c9955 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Sun, 5 Mar 2017 22:16:51 +0900 Subject: [PATCH] refactoring --- sqlite3.go | 4 +- vtable.go => sqlite3_vtable.go | 211 +++++++++++++++++++++-- vtable_test.go => sqlite3_vtable_test.go | 2 +- vtable.c | 182 ------------------- 4 files changed, 202 insertions(+), 197 deletions(-) rename vtable.go => sqlite3_vtable.go (58%) rename vtable_test.go => sqlite3_vtable_test.go (98%) delete mode 100644 vtable.c diff --git a/sqlite3.go b/sqlite3.go index c7eaf4d..f363549 100644 --- a/sqlite3.go +++ b/sqlite3.go @@ -431,7 +431,7 @@ func (c *SQLiteConn) exec(ctx context.Context, query string, args []namedValue) na := s.NumInput() if len(args) < na { s.Close() - return nil, fmt.Errorf("Not enough args to execute query. Expected %d, got %d.", na, len(args)) + return nil, fmt.Errorf("not enough args to execute query: want %d got %d", na, len(args)) } for i := 0; i < na; i++ { args[i].Ordinal -= start @@ -481,7 +481,7 @@ func (c *SQLiteConn) query(ctx context.Context, query string, args []namedValue) s.(*SQLiteStmt).cls = true na := s.NumInput() if len(args) < na { - return nil, fmt.Errorf("Not enough args to execute query. Expected %d, got %d.", na, len(args)) + return nil, fmt.Errorf("not enough args to execute query: want %d got %d", na, len(args)) } for i := 0; i < na; i++ { args[i].Ordinal -= start diff --git a/vtable.go b/sqlite3_vtable.go similarity index 58% rename from vtable.go rename to sqlite3_vtable.go index 9b26727..e86a06b 100644 --- a/vtable.go +++ b/sqlite3_vtable.go @@ -20,11 +20,198 @@ package sqlite3 #endif #include #include +#include -int goSqlite3CreateModule(sqlite3 *db, const char *zName, uintptr_t pClientData); +static inline char *_sqlite3_mprintf(char *zFormat, char *arg) { + return sqlite3_mprintf(zFormat, arg); +} -static inline char *my_mprintf(char *zFormat, char *arg) { - return sqlite3_mprintf(zFormat, arg); +typedef struct goVTab goVTab; + +struct goVTab { + sqlite3_vtab base; + void *vTab; +}; + +uintptr_t goMInit(void *db, void *pAux, int argc, char **argv, char **pzErr, int isCreate); + +static int cXInit(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr, int isCreate) { + void *vTab = (void *)goMInit(db, pAux, argc, (char**)argv, pzErr, isCreate); + if (!vTab || *pzErr) { + return SQLITE_ERROR; + } + goVTab *pvTab = (goVTab *)sqlite3_malloc(sizeof(goVTab)); + if (!pvTab) { + *pzErr = sqlite3_mprintf("%s", "Out of memory"); + return SQLITE_NOMEM; + } + memset(pvTab, 0, sizeof(goVTab)); + pvTab->vTab = vTab; + + *ppVTab = (sqlite3_vtab *)pvTab; + *pzErr = 0; + return SQLITE_OK; +} + +static inline int cXCreate(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { + return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 1); +} +static inline int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { + return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 0); +} + +char* goVBestIndex(void *pVTab, void *icp); + +static inline int cXBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *info) { + char *pzErr = goVBestIndex(((goVTab*)pVTab)->vTab, info); + if (pzErr) { + if (pVTab->zErrMsg) + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = pzErr; + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +char* goVRelease(void *pVTab, int isDestroy); + +static int cXRelease(sqlite3_vtab *pVTab, int isDestroy) { + char *pzErr = goVRelease(((goVTab*)pVTab)->vTab, isDestroy); + if (pzErr) { + if (pVTab->zErrMsg) + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = pzErr; + return SQLITE_ERROR; + } + if (pVTab->zErrMsg) + sqlite3_free(pVTab->zErrMsg); + sqlite3_free(pVTab); + return SQLITE_OK; +} + +static inline int cXDisconnect(sqlite3_vtab *pVTab) { + return cXRelease(pVTab, 0); +} +static inline int cXDestroy(sqlite3_vtab *pVTab) { + return cXRelease(pVTab, 1); +} + +typedef struct goVTabCursor goVTabCursor; + +struct goVTabCursor { + sqlite3_vtab_cursor base; + void *vTabCursor; +}; + +uintptr_t goVOpen(void *pVTab, char **pzErr); + +static int cXOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) { + void *vTabCursor = (void *)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 setErrMsg(sqlite3_vtab_cursor *pCursor, char *pzErr) { + if (pCursor->pVtab->zErrMsg) + sqlite3_free(pCursor->pVtab->zErrMsg); + pCursor->pVtab->zErrMsg = pzErr; + return SQLITE_ERROR; +} + +char* goVClose(void *pCursor); + +static int cXClose(sqlite3_vtab_cursor *pCursor) { + char *pzErr = goVClose(((goVTabCursor*)pCursor)->vTabCursor); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + sqlite3_free(pCursor); + return SQLITE_OK; +} + +char* goVFilter(void *pCursor, int idxNum, char* idxName, int argc, sqlite3_value **argv); + +static int cXFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) { + char *pzErr = goVFilter(((goVTabCursor*)pCursor)->vTabCursor, idxNum, (char*)idxStr, argc, argv); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + return SQLITE_OK; +} + +char* goVNext(void *pCursor); + +static int cXNext(sqlite3_vtab_cursor *pCursor) { + char *pzErr = goVNext(((goVTabCursor*)pCursor)->vTabCursor); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + return SQLITE_OK; +} + +int goVEof(void *pCursor); + +static inline int cXEof(sqlite3_vtab_cursor *pCursor) { + return goVEof(((goVTabCursor*)pCursor)->vTabCursor); +} + +char* goVColumn(void *pCursor, void *cp, int col); + +static int cXColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i) { + char *pzErr = goVColumn(((goVTabCursor*)pCursor)->vTabCursor, ctx, i); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + return SQLITE_OK; +} + +char* goVRowid(void *pCursor, sqlite3_int64 *pRowid); + +static int cXRowid(sqlite3_vtab_cursor *pCursor, sqlite3_int64 *pRowid) { + char *pzErr = goVRowid(((goVTabCursor*)pCursor)->vTabCursor, pRowid); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + return SQLITE_OK; +} + +static sqlite3_module goModule = { + 0, // iVersion + cXCreate, // xCreate - create a table + cXConnect, // xConnect - connect to an existing table + cXBestIndex, // xBestIndex - Determine search strategy + cXDisconnect, // xDisconnect - Disconnect from a table + cXDestroy, // xDestroy - Drop a table + cXOpen, // xOpen - open a cursor + cXClose, // xClose - close a cursor + cXFilter, // xFilter - configure scan constraints + cXNext, // xNext - advance a cursor + cXEof, // xEof + cXColumn, // xColumn - read data + cXRowid, // xRowid - read data +// Not implemented + 0, // xUpdate - write data + 0, // xBegin - begin transaction + 0, // xSync - sync transaction + 0, // xCommit - commit transaction + 0, // xRollback - rollback transaction + 0, // xFindFunction - function overloading + 0, // xRename - rename the table + 0, // xSavepoint + 0, // xRelease + 0 // xRollbackTo +}; + +void goMDestroy(void*); + +static int _sqlite3_create_module(sqlite3 *db, const char *zName, uintptr_t pClientData) { + return sqlite3_create_module_v2(db, zName, &goModule, (void*) pClientData, goMDestroy); } */ import "C" @@ -136,11 +323,11 @@ func mPrintf(format, arg string) *C.char { defer C.free(unsafe.Pointer(cf)) ca := C.CString(arg) defer C.free(unsafe.Pointer(ca)) - return C.my_mprintf(cf, ca) + return C._sqlite3_mprintf(cf, ca) } //export goMInit -func goMInit(db, pClientData unsafe.Pointer, argc int, argv **C.char, pzErr **C.char, isCreate int) C.uintptr_t { +func goMInit(db, pClientData unsafe.Pointer, argc C.int, argv **C.char, pzErr **C.char, isCreate C.int) C.uintptr_t { m := lookupHandle(uintptr(pClientData)).(*sqliteModule) if m.c.db != (*C.sqlite3)(db) { *pzErr = mPrintf("%s", "Inconsistent db handles") @@ -148,7 +335,7 @@ func goMInit(db, pClientData unsafe.Pointer, argc int, argv **C.char, pzErr **C. } args := make([]string, argc) var A []*C.char - slice := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(argv)), Len: argc, Cap: argc} + slice := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(argv)), Len: int(argc), Cap: int(argc)} a := reflect.NewAt(reflect.TypeOf(A), unsafe.Pointer(&slice)).Elem().Interface() for i, s := range a.([]*C.char) { args[i] = C.GoString(s) @@ -171,7 +358,7 @@ func goMInit(db, pClientData unsafe.Pointer, argc int, argv **C.char, pzErr **C. } //export goVRelease -func goVRelease(pVTab unsafe.Pointer, isDestroy int) *C.char { +func goVRelease(pVTab unsafe.Pointer, isDestroy C.int) *C.char { vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) var err error if isDestroy == 1 { @@ -254,7 +441,7 @@ func goMDestroy(pClientData unsafe.Pointer) { } //export goVFilter -func goVFilter(pCursor unsafe.Pointer, idxNum int, idxName *C.char, argc int, argv **C.sqlite3_value) *C.char { +func goVFilter(pCursor unsafe.Pointer, idxNum C.int, idxName *C.char, argc C.int, argv **C.sqlite3_value) *C.char { vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc] vals := make([]interface{}, 0, argc) @@ -265,7 +452,7 @@ func goVFilter(pCursor unsafe.Pointer, idxNum int, idxName *C.char, argc int, ar } vals = append(vals, conv.Interface()) } - err := vtc.vTabCursor.Filter(idxNum, C.GoString(idxName), vals) + err := vtc.vTabCursor.Filter(int(idxNum), C.GoString(idxName), vals) if err != nil { return mPrintf("%s", err.Error()) } @@ -293,10 +480,10 @@ func goVEof(pCursor unsafe.Pointer) C.int { } //export goVColumn -func goVColumn(pCursor, cp unsafe.Pointer, col int) *C.char { +func goVColumn(pCursor, cp unsafe.Pointer, col C.int) *C.char { vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) c := (*SQLiteContext)(cp) - err := vtc.vTabCursor.Column(c, col) + err := vtc.vTabCursor.Column(c, int(col)) if err != nil { return mPrintf("%s", err.Error()) } @@ -373,7 +560,7 @@ func (c *SQLiteConn) CreateModule(moduleName string, module Module) error { mname := C.CString(moduleName) defer C.free(unsafe.Pointer(mname)) udm := sqliteModule{c, moduleName, module} - rv := C.goSqlite3CreateModule(c.db, mname, C.uintptr_t(newHandle(c, &udm))) + rv := C._sqlite3_create_module(c.db, mname, C.uintptr_t(newHandle(c, &udm))) if rv != C.SQLITE_OK { return c.lastError() } diff --git a/vtable_test.go b/sqlite3_vtable_test.go similarity index 98% rename from vtable_test.go rename to sqlite3_vtable_test.go index f4587fe..31fb506 100644 --- a/vtable_test.go +++ b/sqlite3_vtable_test.go @@ -133,7 +133,7 @@ func TestCreateModule(t *testing.T) { } _, err = db.Exec("CREATE VIRTUAL TABLE vtab USING test('1', 2, three)") if err != nil { - t.Fatal("could not create vtable: %v", err) + t.Fatalf("could not create vtable: %v", err) } var i, value int diff --git a/vtable.c b/vtable.c deleted file mode 100644 index e1d7575..0000000 --- a/vtable.c +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (C) 2014 Yasuhiro Matsumoto . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -#ifndef USE_LIBSQLITE3 -#include -#else -#include -#endif -#include -#include -#include -#include "_cgo_export.h" - - -typedef struct goVTab goVTab; - -struct goVTab { - sqlite3_vtab base; - void *vTab; -}; - -static int cXInit(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr, int isCreate) { - void *vTab = (void *)goMInit(db, pAux, argc, (char**)argv, pzErr, isCreate); - if (!vTab || *pzErr) { - return SQLITE_ERROR; - } - goVTab *pvTab = (goVTab *)sqlite3_malloc(sizeof(goVTab)); - if (!pvTab) { - *pzErr = sqlite3_mprintf("%s", "Out of memory"); - return SQLITE_NOMEM; - } - memset(pvTab, 0, sizeof(goVTab)); - pvTab->vTab = vTab; - - *ppVTab = (sqlite3_vtab *)pvTab; - *pzErr = 0; - return SQLITE_OK; -} - -static inline int cXCreate(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { - return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 1); -} -static inline int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { - return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 0); -} - -static inline int cXBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *info) { - char *pzErr = goVBestIndex(((goVTab*)pVTab)->vTab, info); - if (pzErr) { - if (pVTab->zErrMsg) - sqlite3_free(pVTab->zErrMsg); - pVTab->zErrMsg = pzErr; - return SQLITE_ERROR; - } - return SQLITE_OK; -} - -static int cXRelease(sqlite3_vtab *pVTab, int isDestroy) { - char *pzErr = goVRelease(((goVTab*)pVTab)->vTab, isDestroy); - if (pzErr) { - if (pVTab->zErrMsg) - sqlite3_free(pVTab->zErrMsg); - pVTab->zErrMsg = pzErr; - return SQLITE_ERROR; - } - if (pVTab->zErrMsg) - sqlite3_free(pVTab->zErrMsg); - sqlite3_free(pVTab); - return SQLITE_OK; -} - -static inline int cXDisconnect(sqlite3_vtab *pVTab) { - return cXRelease(pVTab, 0); -} -static inline int cXDestroy(sqlite3_vtab *pVTab) { - 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) { - void *vTabCursor = (void *)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 setErrMsg(sqlite3_vtab_cursor *pCursor, char *pzErr) { - if (pCursor->pVtab->zErrMsg) - sqlite3_free(pCursor->pVtab->zErrMsg); - pCursor->pVtab->zErrMsg = pzErr; - return SQLITE_ERROR; -} - -static int cXClose(sqlite3_vtab_cursor *pCursor) { - char *pzErr = goVClose(((goVTabCursor*)pCursor)->vTabCursor); - if (pzErr) { - return setErrMsg(pCursor, pzErr); - } - sqlite3_free(pCursor); - return SQLITE_OK; -} - -static int cXFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) { - char *pzErr = goVFilter(((goVTabCursor*)pCursor)->vTabCursor, idxNum, (char*)idxStr, argc, argv); - if (pzErr) { - return setErrMsg(pCursor, pzErr); - } - return SQLITE_OK; -} - -static int cXNext(sqlite3_vtab_cursor *pCursor) { - char *pzErr = goVNext(((goVTabCursor*)pCursor)->vTabCursor); - if (pzErr) { - return setErrMsg(pCursor, pzErr); - } - return SQLITE_OK; -} - -static inline int cXEof(sqlite3_vtab_cursor *pCursor) { - return goVEof(((goVTabCursor*)pCursor)->vTabCursor); -} - -static int cXColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i) { - char *pzErr = goVColumn(((goVTabCursor*)pCursor)->vTabCursor, ctx, i); - if (pzErr) { - return setErrMsg(pCursor, pzErr); - } - return SQLITE_OK; -} - -static int cXRowid(sqlite3_vtab_cursor *pCursor, sqlite3_int64 *pRowid) { - char *pzErr = goVRowid(((goVTabCursor*)pCursor)->vTabCursor, pRowid); - if (pzErr) { - return setErrMsg(pCursor, pzErr); - } - return SQLITE_OK; -} - -static sqlite3_module goModule = { - 0, /* iVersion */ - cXCreate, /* xCreate - create a table */ - cXConnect, /* xConnect - connect to an existing table */ - cXBestIndex, /* xBestIndex - Determine search strategy */ - cXDisconnect, /* xDisconnect - Disconnect from a table */ - cXDestroy, /* xDestroy - Drop a table */ - cXOpen, /* xOpen - open a cursor */ - cXClose, /* xClose - close a cursor */ - cXFilter, /* xFilter - configure scan constraints */ - cXNext, /* xNext - advance a cursor */ - cXEof, /* xEof */ - cXColumn, /* xColumn - read data */ - cXRowid, /* xRowid - read data */ -// Not implemented - 0, /* xUpdate - write data */ - 0, /* xBegin - begin transaction */ - 0, /* xSync - sync transaction */ - 0, /* xCommit - commit transaction */ - 0, /* xRollback - rollback transaction */ - 0, /* xFindFunction - function overloading */ - 0, /* xRename - rename the table */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0 /* xRollbackTo */ -}; - - -int goSqlite3CreateModule(sqlite3 *db, const char *zName, uintptr_t pClientData) { - return sqlite3_create_module_v2(db, zName, &goModule, (void*) pClientData, goMDestroy); -} \ No newline at end of file