aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/shell.c.in22
-rw-r--r--src/sqlite.h.in19
-rw-r--r--src/test1.c27
-rw-r--r--src/vtab.c22
4 files changed, 85 insertions, 5 deletions
diff --git a/src/shell.c.in b/src/shell.c.in
index e2c49dd3e..0ee136389 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -3651,6 +3651,7 @@ static const char *(azHelp[]) = {
#endif /* SQLITE_OMIT_TRACE */
#ifdef SQLITE_DEBUG
".unmodule NAME ... Unregister virtual table modules",
+ " --allexcept Unregister everything except those named",
#endif
".vfsinfo ?AUX? Information about the top-level VFS",
".vfslist List all available VFSes",
@@ -6892,7 +6893,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int nArg = 0;
int n, c;
int rc = 0;
- char *azArg[50];
+ char *azArg[52];
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( p->expert.pExpert ){
@@ -6902,7 +6903,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* Parse the input line into tokens.
*/
- while( zLine[h] && nArg<ArraySize(azArg) ){
+ while( zLine[h] && nArg<ArraySize(azArg)-1 ){
while( IsSpace(zLine[h]) ){ h++; }
if( zLine[h]==0 ) break;
if( zLine[h]=='\'' || zLine[h]=='"' ){
@@ -6923,6 +6924,7 @@ static int do_meta_command(char *zLine, ShellState *p){
resolve_backslashes(azArg[nArg-1]);
}
}
+ azArg[nArg] = 0;
/* Process the input line.
*/
@@ -9407,14 +9409,24 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifdef SQLITE_DEBUG
if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){
int ii;
+ int lenOpt;
+ char *zOpt;
if( nArg<2 ){
- raw_printf(stderr, "Usage: .unmodule NAME ...\n");
+ raw_printf(stderr, "Usage: .unmodule [--allexcept] 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);
+ zOpt = azArg[1];
+ if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
+ lenOpt = (int)strlen(zOpt);
+ if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){
+ assert( azArg[nArg]==0 );
+ sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0);
+ }else{
+ for(ii=1; ii<nArg; ii++){
+ sqlite3_create_module(p->db, azArg[ii], 0, 0);
+ }
}
}else
#endif
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index ed5e2922c..521ddffdb 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -6639,6 +6639,8 @@ struct sqlite3_index_info {
** ^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.
+**
+** See also: [sqlite3_drop_modules()]
*/
int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
@@ -6655,6 +6657,23 @@ int sqlite3_create_module_v2(
);
/*
+** CAPI3REF: Remove Unnecessary Virtual Table Implementations
+** METHOD: sqlite3
+**
+** ^The sqlite3_drop_modules(D,L) interface removes all virtual
+** table modules from database connection D except those named on list L.
+** The L parameter must be either NULL or a pointer to an array of pointers
+** to strings where the array is terminated by a single NULL pointer.
+** ^If the L parameter is NULL, then all virtual table modules are removed.
+**
+** See also: [sqlite3_create_module()]
+*/
+int sqlite3_drop_modules(
+ sqlite3 *db, /* Remove modules from this connection */
+ const char **azKeep /* Except, do not remove the ones named here */
+);
+
+/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
**
diff --git a/src/test1.c b/src/test1.c
index 6bc64e762..e238d31e8 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -1111,6 +1111,32 @@ static int SQLITE_TCLAPI test_create_function(
}
/*
+** Usage: sqlite3_drop_modules DB ?NAME ...?
+**
+** Invoke the sqlite3_drop_modules(D,L) interface on database
+** connection DB, in order to drop all modules except those named in
+** the argument.
+*/
+static int SQLITE_TCLAPI test_drop_modules(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ int rc;
+ sqlite3 *db;
+
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " DB\"", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+ sqlite3_drop_modules(db, argc>2 ? (const char**)(argv+2) : 0);
+ return TCL_OK;
+}
+
+/*
** Routines to implement the x_count() aggregate function.
**
** x_count() counts the number of non-null arguments. But there are
@@ -7860,6 +7886,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_close_v2", (Tcl_CmdProc*)sqlite_test_close_v2 },
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
{ "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
+ { "sqlite3_drop_modules", (Tcl_CmdProc*)test_drop_modules },
{ "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
{ "sqlite_abort", (Tcl_CmdProc*)sqlite_abort },
{ "sqlite_bind", (Tcl_CmdProc*)test_bind },
diff --git a/src/vtab.c b/src/vtab.c
index 8f6db9f47..dd8a755be 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -134,6 +134,28 @@ int sqlite3_create_module_v2(
}
/*
+** External API to drop all virtual-table modules, except those named
+** on the azNames list.
+*/
+int sqlite3_drop_modules(sqlite3 *db, const char** azNames){
+ HashElem *pThis, *pNext;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){
+ Module *pMod = (Module*)sqliteHashData(pThis);
+ pNext = sqliteHashNext(pThis);
+ if( azNames ){
+ int ii;
+ for(ii=0; azNames[ii]!=0 && strcmp(azNames[ii],pMod->zName)!=0; ii++){}
+ if( azNames[ii]!=0 ) continue;
+ }
+ createModule(db, pMod->zName, 0, 0, 0);
+ }
+ return SQLITE_OK;
+}
+
+/*
** Decrement the reference count on a Module object. Destroy the
** module when the reference count reaches zero.
*/