diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/shell.c.in | 18 | ||||
-rw-r--r-- | src/sqlite.h.in | 4 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 | ||||
-rw-r--r-- | src/vtab.c | 55 |
5 files changed, 67 insertions, 18 deletions
diff --git a/src/main.c b/src/main.c index ecc7e5c51..79a17e5a5 100644 --- a/src/main.c +++ b/src/main.c @@ -1236,11 +1236,8 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ Module *pMod = (Module *)sqliteHashData(i); - if( pMod->xDestroy ){ - pMod->xDestroy(pMod->pAux); - } sqlite3VtabEponymousTableClear(db, pMod); - sqlite3DbFree(db, pMod); + sqlite3VtabModuleUnref(db, pMod); } sqlite3HashClear(&db->aModule); #endif diff --git a/src/shell.c.in b/src/shell.c.in index 0ffd9aece..494a3d7e2 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -3649,6 +3649,9 @@ static const char *(azHelp[]) = { " --row Trace each row (SQLITE_TRACE_ROW)", " --close Trace connection close (SQLITE_TRACE_CLOSE)", #endif /* SQLITE_OMIT_TRACE */ +#ifdef SQLITE_DEBUG + ".unmodule NAME ... Unregister virtual table modules", +#endif ".vfsinfo ?AUX? Information about the top-level VFS", ".vfslist List all available VFSes", ".vfsname ?AUX? Print the name of the VFS stack", @@ -9401,6 +9404,21 @@ static int do_meta_command(char *zLine, ShellState *p){ }else #endif /* !defined(SQLITE_OMIT_TRACE) */ +#ifdef SQLITE_DEBUG + if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){ + int ii; + if( nArg<2 ){ + raw_printf(stderr, "Usage: .unmodule NAME ...\n"); + rc = 1; + goto meta_command_exit; + } + open_db(p, 0); + for(ii=1; ii<nArg; ii++){ + sqlite3_create_module(p->db, azArg[ii], 0, 0); + } + }else +#endif + #if SQLITE_USER_AUTHENTICATION if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ if( nArg<2 ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 4b1d4723b..e0d02b272 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6624,6 +6624,10 @@ struct sqlite3_index_info { ** ^The sqlite3_create_module() ** interface is equivalent to sqlite3_create_module_v2() with a NULL ** destructor. +** +** ^If the third parameter (the pointer to the sqlite3_module object) is +** NULL then no new module is create and any existing modules with the +** same name are dropped. */ int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 52c982159..07e241a1c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1797,6 +1797,7 @@ struct Savepoint { struct Module { const sqlite3_module *pModule; /* Callback pointers */ const char *zName; /* Name passed to create_module() */ + int nRefModule; /* Number of pointers to this object */ void *pAux; /* pAux passed to create_module() */ void (*xDestroy)(void *); /* Module destructor function */ Table *pEpoTab; /* Eponymous table for this module */ @@ -4438,6 +4439,7 @@ void sqlite3AutoLoadExtensions(sqlite3*); # define sqlite3VtabInSync(db) 0 # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) +# define sqlite3VtabModuleUnref(D,X) # define sqlite3VtabUnlockList(X) # define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK # define sqlite3GetVTable(X,Y) ((VTable*)0) @@ -4449,6 +4451,7 @@ void sqlite3AutoLoadExtensions(sqlite3*); int sqlite3VtabCommit(sqlite3 *db); void sqlite3VtabLock(VTable *); void sqlite3VtabUnlock(VTable *); + void sqlite3VtabModuleUnref(sqlite3*,Module*); void sqlite3VtabUnlockList(sqlite3*); int sqlite3VtabSavepoint(sqlite3 *, int, int); void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); diff --git a/src/vtab.c b/src/vtab.c index 41e26ef62..a711a7be5 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -32,6 +32,9 @@ struct VtabCtx { ** Construct and install a Module object for a virtual table. When this ** routine is called, it is guaranteed that all appropriate locks are held ** and the module is not already part of the connection. +** +** If there already exists a module with zName, replace it with the new one. +** If pModule==0, then delete the module zName if it exists. */ Module *sqlite3VtabCreateModule( sqlite3 *db, /* Database in which module is registered */ @@ -41,25 +44,35 @@ Module *sqlite3VtabCreateModule( void (*xDestroy)(void *) /* Module destructor function */ ){ Module *pMod; - int nName = sqlite3Strlen30(zName); - pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1); - if( pMod==0 ){ - sqlite3OomFault(db); + Module *pDel; + char *zCopy; + if( pModule==0 ){ + zCopy = (char*)zName; + pMod = 0; }else{ - Module *pDel; - char *zCopy = (char *)(&pMod[1]); + int nName = sqlite3Strlen30(zName); + pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1); + if( pMod==0 ){ + sqlite3OomFault(db); + return 0; + } + zCopy = (char *)(&pMod[1]); memcpy(zCopy, zName, nName+1); pMod->zName = zCopy; pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; pMod->pEpoTab = 0; - pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); - assert( pDel==0 || pDel==pMod ); - if( pDel ){ + pMod->nRefModule = 1; + } + pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); + if( pDel ){ + if( pDel==pMod ){ sqlite3OomFault(db); sqlite3DbFree(db, pDel); pMod = 0; + }else{ + sqlite3VtabModuleUnref(db, pDel); } } return pMod; @@ -80,11 +93,7 @@ static int createModule( int rc = SQLITE_OK; sqlite3_mutex_enter(db->mutex); - if( sqlite3HashFind(&db->aModule, zName) ){ - rc = SQLITE_MISUSE_BKPT; - }else{ - (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy); - } + (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy); rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux); sqlite3_mutex_leave(db->mutex); @@ -124,6 +133,22 @@ int sqlite3_create_module_v2( } /* +** Decrement the reference count on a Module object. Destroy the +** module when the reference count reaches zero. +*/ +void sqlite3VtabModuleUnref(sqlite3 *db, Module *pMod){ + assert( pMod->nRefModule>0 ); + pMod->nRefModule--; + if( pMod->nRefModule==0 ){ + if( pMod->xDestroy ){ + pMod->xDestroy(pMod->pAux); + } + assert( pMod->pEpoTab==0 ); + sqlite3DbFree(db, pMod); + } +} + +/* ** Lock the virtual table so that it cannot be disconnected. ** Locks nest. Every lock should have a corresponding unlock. ** If an unlock is omitted, resources leaks will occur. @@ -162,6 +187,7 @@ void sqlite3VtabUnlock(VTable *pVTab){ pVTab->nRef--; if( pVTab->nRef==0 ){ sqlite3_vtab *p = pVTab->pVtab; + sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod); if( p ){ p->pModule->xDisconnect(p); } @@ -566,6 +592,7 @@ static int vtabCallConstructor( ** the sqlite3_vtab object if successful. */ memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; + pMod->nRefModule++; pVTable->nRef = 1; if( sCtx.bDeclared==0 ){ const char *zFormat = "vtable constructor did not declare schema: %s"; |