Add the ability to unregister a virtual table module by invoking

sqlite3_create_module() with a NULL sqlite3_module pointer.

FossilOrigin-Name: 31e34fa3390196cdc3178bf120224b08df5ec58fa2c77079ede6e9461a430dad
This commit is contained in:
drh 2019-08-16 22:58:29 +00:00
parent 4043cfef75
commit cc5979dbd3
9 changed files with 86 additions and 37 deletions

View File

@ -1,5 +1,5 @@
C Fix\sharmless\scompiler\swarnings\sin\sthe\sTCL\sinterface.
D 2019-08-15T23:11:42.012
C Add\sthe\sability\sto\sunregister\sa\svirtual\stable\smodule\sby\sinvoking\nsqlite3_create_module()\swith\sa\sNULL\ssqlite3_module\spointer.
D 2019-08-16T22:58:29.636
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -487,7 +487,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c c2194dd2886337b870226fcb31c13e7df8c4b5e0ea85140e510a6f1daf1ad65b
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 22afc33c3a61b4fd80a60a54f1882688371e6bc64685df2696b008fce65a999c
F src/main.c 9465ba2bfc021f5c2ec1f58fc97c55b123d277ad0993c49a2f333df9da483f8f
F src/main.c 1ffcd1890908444567471e72246f22595a8f63cfa84fa8f5ee7fc80c0d2a1863
F src/malloc.c 0f9da2a66b230a5785af94b9672126845099b57b70a32c987d04ac28c69da990
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@ -524,11 +524,11 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 14ae3326af3d8b94bd64a29e0369986f3125cf4c0dcb8f8dc1b8be2cd1bcdbaa
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
F src/select.c 80b8b4c857db2f20d98f80b71ef3bb0d70cdd17bd6b00217dcff803e9b989bd8
F src/shell.c.in b748cfb4277fe1952609d688b181b152dd5920425a83dab1baddbfdcb722346c
F src/sqlite.h.in fe09e2452f68148dcd2724fa1aefe0939802b4fab89355fb194aa40126ac4b51
F src/shell.c.in d2465e7747a014bd48a75c1bcf648e8e6cb46832dcc6e1293c5f285bc5542e8b
F src/sqlite.h.in fe836f566b3517201077f4ff69ec7379b626b311ccc6e24ad5ca11c262775ca7
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5
F src/sqliteInt.h d8e878fa1cb949ee8943f51965cbb917acdb4cc1238af8481eb839d11bf34d0a
F src/sqliteInt.h a89fe72e4a00652fdad88911e73ad376a351a477ec86a822f602863f01a495d3
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@ -604,7 +604,7 @@ F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b
F src/vdbemem.c 920285c3b7f5c64369e02da437dab71e9e91862df9c486541c14633739f91d75
F src/vdbesort.c 3531ae3a431ad6b98b67bd891fb42ec9d66867157188a2b1a9e58c55da6151b2
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
F src/vtab.c 1fa256c6ddad7a81e2a4dc080d015d4b0a7135767717d311298e47f6fca64bb3
F src/vtab.c 4d833811e3784409627919899e1fd75ee08f0e5db6d9924eac9a0bfe0cb762dc
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c bbd6838bd79c0a32144d482fb0b6a9d2d1a252fb3b16d5005ec30f2f80413b0d
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
@ -1064,7 +1064,7 @@ F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
F test/insertfault.test ac63d14ea3b49c573673a572f4014b9117383a03e497c58f308b5c776e4a7f74
F test/instr.test 9a8802f28437d8ade53fedfc47b2ca599b4e48ba
F test/instrfault.test 0f870b218ea17cd477bb19ed330eecdb460dd53a
F test/intarray.test 8319986182af37c8eb4879c6bfe9cf0074e9d43b193a4c728a0efa3417c53fb7
F test/intarray.test bb976b0b3df0ebb6a2eddfb61768280440e672beba5460ed49679ea984ccf440
F test/interrupt.test 16ea879ec728cb76414c148c5f24afd5d1f91054
F test/interrupt2.test e4408ca770a6feafbadb0801e54a0dcd1a8d108d
F test/intpkey.test ac71107a49a06492b69b82aafaf225400598d3c8
@ -1611,7 +1611,7 @@ F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
F test/view.test 10ea54300a097d7c0337fd104abffe4a4786d1598b94017a37efe0e0d3e04dd5
F test/vtab1.test efb4c4a45146193d6d55fb85f7162febd6423f29c72ede09bb96383f49e3abc1
F test/vtab1.test c5d9e90ed02bcacd776dcbb7360199d290f7f53c26b484ddece543060c54319f
F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3
@ -1836,7 +1836,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 61b4bccd2984f4c2cf50f58ef08677588e57aa7e079af07473b2e188d9ce4f52
R ad07753edbdb65bae98d204ed9a7c2cb
P f17e72291f197a92b3e15e054271b997d45211a5a31ca4ea6c7fbb33026d5f1f
R cde2fc12434d097e80f94e2e70c1f8fb
U drh
Z f83b80ce99769ab61a563e51215a8c91
Z bcecf677f5410a7291761a23528080f1

View File

@ -1 +1 @@
f17e72291f197a92b3e15e054271b997d45211a5a31ca4ea6c7fbb33026d5f1f
31e34fa3390196cdc3178bf120224b08df5ec58fa2c77079ede6e9461a430dad

View File

@ -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

View File

@ -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 ){

View File

@ -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 */

View File

@ -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*);

View File

@ -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);
@ -123,6 +132,22 @@ int sqlite3_create_module_v2(
return createModule(db, zName, pModule, pAux, xDestroy);
}
/*
** 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.
@ -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";

View File

@ -47,12 +47,12 @@ do_test intarray-1.1 {
}
} {table ia1 table ia2 table ia3 table ia4}
# Verify the inability to DROP and recreate an intarray virtual table.
# Verify the ability to DROP and recreate an intarray virtual table.
do_test intarray-1.1b {
db eval {DROP TABLE ia1}
set rc [catch {sqlite3_intarray_create db ia1} msg]
lappend rc $msg
} {1 SQLITE_MISUSE}
set rc [catch {sqlite3_intarray_create db ia1} ia1]
lappend rc $ia1
} {/0 [0-9A-Z]+/}
do_test intarray-1.2 {
db eval {

View File

@ -1352,7 +1352,7 @@ foreach {tn sql res filter} {
do_execsql_test 18.2.x { PRAGMA case_sensitive_like = OFF }
#-------------------------------------------------------------------------
# Test that an existing module may not be overridden.
# Test that it is ok to override and existing module.
#
do_test 19.1 {
sqlite3 db2 test.db
@ -1360,7 +1360,7 @@ do_test 19.1 {
} SQLITE_OK
do_test 19.2 {
register_echo_module [sqlite3_connection_pointer db2]
} SQLITE_MISUSE
} SQLITE_OK
do_test 19.3 {
db2 close
} {}