123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- /*
- ** 2013-06-12
- **
- ** The author disclaims copyright to this source code. In place of
- ** a legal notice, here is a blessing:
- **
- ** May you do good and not evil.
- ** May you find forgiveness for yourself and forgive others.
- ** May you share freely, never taking more than you give.
- **
- *************************************************************************
- **
- ** A shim that sits between the SQLite virtual table interface and
- ** runtimes with garbage collector based memory management.
- */
- #include "sqlite3ext.h"
- SQLITE_EXTENSION_INIT1
- #include <assert.h>
- #include <string.h>
- #ifndef SQLITE_OMIT_VIRTUALTABLE
- /* Forward references */
- typedef struct vtshim_aux vtshim_aux;
- typedef struct vtshim_vtab vtshim_vtab;
- typedef struct vtshim_cursor vtshim_cursor;
- /* The vtshim_aux argument is the auxiliary parameter that is passed
- ** into sqlite3_create_module_v2().
- */
- struct vtshim_aux {
- void *pChildAux; /* pAux for child virtual tables */
- void (*xChildDestroy)(void*); /* Destructor for pChildAux */
- sqlite3_module *pMod; /* Methods for child virtual tables */
- sqlite3 *db; /* The database to which we are attached */
- char *zName; /* Name of the module */
- int bDisposed; /* True if disposed */
- vtshim_vtab *pAllVtab; /* List of all vtshim_vtab objects */
- sqlite3_module sSelf; /* Methods used by this shim */
- };
- /* A vtshim virtual table object */
- struct vtshim_vtab {
- sqlite3_vtab base; /* Base class - must be first */
- sqlite3_vtab *pChild; /* Child virtual table */
- vtshim_aux *pAux; /* Pointer to vtshim_aux object */
- vtshim_cursor *pAllCur; /* List of all cursors */
- vtshim_vtab **ppPrev; /* Previous on list */
- vtshim_vtab *pNext; /* Next on list */
- };
- /* A vtshim cursor object */
- struct vtshim_cursor {
- sqlite3_vtab_cursor base; /* Base class - must be first */
- sqlite3_vtab_cursor *pChild; /* Cursor generated by the managed subclass */
- vtshim_cursor **ppPrev; /* Previous on list of all cursors */
- vtshim_cursor *pNext; /* Next on list of all cursors */
- };
- /* Macro used to copy the child vtable error message to outer vtable */
- #define VTSHIM_COPY_ERRMSG() \
- do { \
- sqlite3_free(pVtab->base.zErrMsg); \
- pVtab->base.zErrMsg = sqlite3_mprintf("%s", pVtab->pChild->zErrMsg); \
- } while (0)
- /* Methods for the vtshim module */
- static int vtshimCreate(
- sqlite3 *db,
- void *ppAux,
- int argc,
- const char *const*argv,
- sqlite3_vtab **ppVtab,
- char **pzErr
- ){
- vtshim_aux *pAux = (vtshim_aux*)ppAux;
- vtshim_vtab *pNew;
- int rc;
- assert( db==pAux->db );
- if( pAux->bDisposed ){
- if( pzErr ){
- *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
- pAux->zName);
- }
- return SQLITE_ERROR;
- }
- pNew = sqlite3_malloc( sizeof(*pNew) );
- *ppVtab = (sqlite3_vtab*)pNew;
- if( pNew==0 ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(*pNew));
- rc = pAux->pMod->xCreate(db, pAux->pChildAux, argc, argv,
- &pNew->pChild, pzErr);
- if( rc ){
- sqlite3_free(pNew);
- *ppVtab = 0;
- return rc;
- }
- pNew->pAux = pAux;
- pNew->ppPrev = &pAux->pAllVtab;
- pNew->pNext = pAux->pAllVtab;
- if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
- pAux->pAllVtab = pNew;
- return rc;
- }
- static int vtshimConnect(
- sqlite3 *db,
- void *ppAux,
- int argc,
- const char *const*argv,
- sqlite3_vtab **ppVtab,
- char **pzErr
- ){
- vtshim_aux *pAux = (vtshim_aux*)ppAux;
- vtshim_vtab *pNew;
- int rc;
- assert( db==pAux->db );
- if( pAux->bDisposed ){
- if( pzErr ){
- *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
- pAux->zName);
- }
- return SQLITE_ERROR;
- }
- pNew = sqlite3_malloc( sizeof(*pNew) );
- *ppVtab = (sqlite3_vtab*)pNew;
- if( pNew==0 ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(*pNew));
- rc = pAux->pMod->xConnect(db, pAux->pChildAux, argc, argv,
- &pNew->pChild, pzErr);
- if( rc ){
- sqlite3_free(pNew);
- *ppVtab = 0;
- return rc;
- }
- pNew->pAux = pAux;
- pNew->ppPrev = &pAux->pAllVtab;
- pNew->pNext = pAux->pAllVtab;
- if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
- pAux->pAllVtab = pNew;
- return rc;
- }
- static int vtshimBestIndex(
- sqlite3_vtab *pBase,
- sqlite3_index_info *pIdxInfo
- ){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xBestIndex(pVtab->pChild, pIdxInfo);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimDisconnect(sqlite3_vtab *pBase){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc = SQLITE_OK;
- if( !pAux->bDisposed ){
- rc = pAux->pMod->xDisconnect(pVtab->pChild);
- }
- if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
- *pVtab->ppPrev = pVtab->pNext;
- sqlite3_free(pVtab);
- return rc;
- }
- static int vtshimDestroy(sqlite3_vtab *pBase){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc = SQLITE_OK;
- if( !pAux->bDisposed ){
- rc = pAux->pMod->xDestroy(pVtab->pChild);
- }
- if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
- *pVtab->ppPrev = pVtab->pNext;
- sqlite3_free(pVtab);
- return rc;
- }
- static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- vtshim_cursor *pCur;
- int rc;
- *ppCursor = 0;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- pCur = sqlite3_malloc( sizeof(*pCur) );
- if( pCur==0 ) return SQLITE_NOMEM;
- memset(pCur, 0, sizeof(*pCur));
- rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild);
- if( rc ){
- sqlite3_free(pCur);
- VTSHIM_COPY_ERRMSG();
- return rc;
- }
- pCur->pChild->pVtab = pVtab->pChild;
- *ppCursor = &pCur->base;
- pCur->ppPrev = &pVtab->pAllCur;
- if( pVtab->pAllCur ) pVtab->pAllCur->ppPrev = &pCur->pNext;
- pCur->pNext = pVtab->pAllCur;
- pVtab->pAllCur = pCur;
- return SQLITE_OK;
- }
- static int vtshimClose(sqlite3_vtab_cursor *pX){
- vtshim_cursor *pCur = (vtshim_cursor*)pX;
- vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
- vtshim_aux *pAux = pVtab->pAux;
- int rc = SQLITE_OK;
- if( !pAux->bDisposed ){
- rc = pAux->pMod->xClose(pCur->pChild);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- }
- if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev;
- *pCur->ppPrev = pCur->pNext;
- sqlite3_free(pCur);
- return rc;
- }
- static int vtshimFilter(
- sqlite3_vtab_cursor *pX,
- int idxNum,
- const char *idxStr,
- int argc,
- sqlite3_value **argv
- ){
- vtshim_cursor *pCur = (vtshim_cursor*)pX;
- vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xFilter(pCur->pChild, idxNum, idxStr, argc, argv);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimNext(sqlite3_vtab_cursor *pX){
- vtshim_cursor *pCur = (vtshim_cursor*)pX;
- vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xNext(pCur->pChild);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimEof(sqlite3_vtab_cursor *pX){
- vtshim_cursor *pCur = (vtshim_cursor*)pX;
- vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return 1;
- rc = pAux->pMod->xEof(pCur->pChild);
- VTSHIM_COPY_ERRMSG();
- return rc;
- }
- static int vtshimColumn(sqlite3_vtab_cursor *pX, sqlite3_context *ctx, int i){
- vtshim_cursor *pCur = (vtshim_cursor*)pX;
- vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xColumn(pCur->pChild, ctx, i);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimRowid(sqlite3_vtab_cursor *pX, sqlite3_int64 *pRowid){
- vtshim_cursor *pCur = (vtshim_cursor*)pX;
- vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xRowid(pCur->pChild, pRowid);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimUpdate(
- sqlite3_vtab *pBase,
- int argc,
- sqlite3_value **argv,
- sqlite3_int64 *pRowid
- ){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xUpdate(pVtab->pChild, argc, argv, pRowid);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimBegin(sqlite3_vtab *pBase){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xBegin(pVtab->pChild);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimSync(sqlite3_vtab *pBase){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xSync(pVtab->pChild);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimCommit(sqlite3_vtab *pBase){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xCommit(pVtab->pChild);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimRollback(sqlite3_vtab *pBase){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xRollback(pVtab->pChild);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimFindFunction(
- sqlite3_vtab *pBase,
- int nArg,
- const char *zName,
- void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
- void **ppArg
- ){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return 0;
- rc = pAux->pMod->xFindFunction(pVtab->pChild, nArg, zName, pxFunc, ppArg);
- VTSHIM_COPY_ERRMSG();
- return rc;
- }
- static int vtshimRename(sqlite3_vtab *pBase, const char *zNewName){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xRename(pVtab->pChild, zNewName);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimSavepoint(sqlite3_vtab *pBase, int n){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xSavepoint(pVtab->pChild, n);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimRelease(sqlite3_vtab *pBase, int n){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xRelease(pVtab->pChild, n);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- static int vtshimRollbackTo(sqlite3_vtab *pBase, int n){
- vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
- vtshim_aux *pAux = pVtab->pAux;
- int rc;
- if( pAux->bDisposed ) return SQLITE_ERROR;
- rc = pAux->pMod->xRollbackTo(pVtab->pChild, n);
- if( rc!=SQLITE_OK ){
- VTSHIM_COPY_ERRMSG();
- }
- return rc;
- }
- /* The destructor function for a disposible module */
- static void vtshimAuxDestructor(void *pXAux){
- vtshim_aux *pAux = (vtshim_aux*)pXAux;
- assert( pAux->pAllVtab==0 );
- if( !pAux->bDisposed && pAux->xChildDestroy ){
- pAux->xChildDestroy(pAux->pChildAux);
- pAux->xChildDestroy = 0;
- }
- sqlite3_free(pAux->zName);
- sqlite3_free(pAux->pMod);
- sqlite3_free(pAux);
- }
- static int vtshimCopyModule(
- const sqlite3_module *pMod, /* Source module to be copied */
- sqlite3_module **ppMod /* Destination for copied module */
- ){
- sqlite3_module *p;
- if( !pMod || !ppMod ) return SQLITE_ERROR;
- p = sqlite3_malloc( sizeof(*p) );
- if( p==0 ) return SQLITE_NOMEM;
- memcpy(p, pMod, sizeof(*p));
- *ppMod = p;
- return SQLITE_OK;
- }
- #ifdef _WIN32
- __declspec(dllexport)
- #endif
- void *sqlite3_create_disposable_module(
- sqlite3 *db, /* SQLite connection to register module with */
- const char *zName, /* Name of the module */
- const sqlite3_module *p, /* Methods for the module */
- void *pClientData, /* Client data for xCreate/xConnect */
- void(*xDestroy)(void*) /* Module destructor function */
- ){
- vtshim_aux *pAux;
- sqlite3_module *pMod;
- int rc;
- pAux = sqlite3_malloc( sizeof(*pAux) );
- if( pAux==0 ){
- if( xDestroy ) xDestroy(pClientData);
- return 0;
- }
- rc = vtshimCopyModule(p, &pMod);
- if( rc!=SQLITE_OK ){
- sqlite3_free(pAux);
- return 0;
- }
- pAux->pChildAux = pClientData;
- pAux->xChildDestroy = xDestroy;
- pAux->pMod = pMod;
- pAux->db = db;
- pAux->zName = sqlite3_mprintf("%s", zName);
- pAux->bDisposed = 0;
- pAux->pAllVtab = 0;
- pAux->sSelf.iVersion = p->iVersion<=2 ? p->iVersion : 2;
- pAux->sSelf.xCreate = p->xCreate ? vtshimCreate : 0;
- pAux->sSelf.xConnect = p->xConnect ? vtshimConnect : 0;
- pAux->sSelf.xBestIndex = p->xBestIndex ? vtshimBestIndex : 0;
- pAux->sSelf.xDisconnect = p->xDisconnect ? vtshimDisconnect : 0;
- pAux->sSelf.xDestroy = p->xDestroy ? vtshimDestroy : 0;
- pAux->sSelf.xOpen = p->xOpen ? vtshimOpen : 0;
- pAux->sSelf.xClose = p->xClose ? vtshimClose : 0;
- pAux->sSelf.xFilter = p->xFilter ? vtshimFilter : 0;
- pAux->sSelf.xNext = p->xNext ? vtshimNext : 0;
- pAux->sSelf.xEof = p->xEof ? vtshimEof : 0;
- pAux->sSelf.xColumn = p->xColumn ? vtshimColumn : 0;
- pAux->sSelf.xRowid = p->xRowid ? vtshimRowid : 0;
- pAux->sSelf.xUpdate = p->xUpdate ? vtshimUpdate : 0;
- pAux->sSelf.xBegin = p->xBegin ? vtshimBegin : 0;
- pAux->sSelf.xSync = p->xSync ? vtshimSync : 0;
- pAux->sSelf.xCommit = p->xCommit ? vtshimCommit : 0;
- pAux->sSelf.xRollback = p->xRollback ? vtshimRollback : 0;
- pAux->sSelf.xFindFunction = p->xFindFunction ? vtshimFindFunction : 0;
- pAux->sSelf.xRename = p->xRename ? vtshimRename : 0;
- if( p->iVersion>=2 ){
- pAux->sSelf.xSavepoint = p->xSavepoint ? vtshimSavepoint : 0;
- pAux->sSelf.xRelease = p->xRelease ? vtshimRelease : 0;
- pAux->sSelf.xRollbackTo = p->xRollbackTo ? vtshimRollbackTo : 0;
- }else{
- pAux->sSelf.xSavepoint = 0;
- pAux->sSelf.xRelease = 0;
- pAux->sSelf.xRollbackTo = 0;
- }
- rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf,
- pAux, vtshimAuxDestructor);
- return rc==SQLITE_OK ? (void*)pAux : 0;
- }
- #ifdef _WIN32
- __declspec(dllexport)
- #endif
- void sqlite3_dispose_module(void *pX){
- vtshim_aux *pAux = (vtshim_aux*)pX;
- if( !pAux->bDisposed ){
- vtshim_vtab *pVtab;
- vtshim_cursor *pCur;
- for(pVtab=pAux->pAllVtab; pVtab; pVtab=pVtab->pNext){
- for(pCur=pVtab->pAllCur; pCur; pCur=pCur->pNext){
- pAux->pMod->xClose(pCur->pChild);
- }
- pAux->pMod->xDisconnect(pVtab->pChild);
- }
- pAux->bDisposed = 1;
- if( pAux->xChildDestroy ){
- pAux->xChildDestroy(pAux->pChildAux);
- pAux->xChildDestroy = 0;
- }
- }
- }
- #endif /* SQLITE_OMIT_VIRTUALTABLE */
- #ifdef _WIN32
- __declspec(dllexport)
- #endif
- int sqlite3_vtshim_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
- ){
- SQLITE_EXTENSION_INIT2(pApi);
- return SQLITE_OK;
- }
|