aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c7
-rw-r--r--src/select.c4
-rw-r--r--src/shell.c.in19
-rw-r--r--src/sqlite.h.in18
-rw-r--r--src/sqliteInt.h16
-rw-r--r--src/tclsqlite.c112
-rw-r--r--src/vtab.c55
7 files changed, 184 insertions, 47 deletions
diff --git a/src/main.c b/src/main.c
index 969bd570c..a8c1d4dc6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -836,6 +836,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
} aFlagOp[] = {
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
+ { SQLITE_DBCONFIG_ENABLE_VIEW, SQLITE_EnableView },
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
{ SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
@@ -1235,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
@@ -3077,6 +3075,7 @@ static int openDatabase(
db->nMaxSorterMmap = 0x7FFFFFFF;
db->flags |= SQLITE_ShortColNames
| SQLITE_EnableTrigger
+ | SQLITE_EnableView
| SQLITE_CacheSpill
/* The SQLITE_DQS compile-time option determines the default settings
diff --git a/src/select.c b/src/select.c
index ca1256d16..bd8fee87e 100644
--- a/src/select.c
+++ b/src/select.c
@@ -4906,6 +4906,10 @@ static int selectExpander(Walker *pWalker, Select *p){
u8 eCodeOrig = pWalker->eCode;
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
assert( pFrom->pSelect==0 );
+ if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
+ sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
+ pTab->zName);
+ }
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
nCol = pTab->nCol;
pTab->nCol = -1;
diff --git a/src/shell.c.in b/src/shell.c.in
index 19280e318..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",
@@ -7135,6 +7138,7 @@ static int do_meta_command(char *zLine, ShellState *p){
} aDbConfig[] = {
{ "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
{ "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
+ { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
{ "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
{ "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
{ "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
@@ -9400,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 d50f44e6c..ed5e2922c 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2093,6 +2093,17 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
+** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
+** <dd> ^This option is used to enable or disable [CREATE VIEW | views].
+** There should be two additional arguments.
+** The first argument is an integer which is 0 to disable views,
+** positive to enable views or negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether views are disabled or enabled
+** following this call. The second parameter may be a NULL pointer, in
+** which case the view setting is not reported back. </dd>
+**
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
** <dd> ^This option is used to enable or disable the
@@ -2265,7 +2276,8 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1015 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -6623,6 +6635,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 47b4e749d..552a435c9 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1537,16 +1537,17 @@ struct sqlite3 {
#define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */
#define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/
#define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/
+#define SQLITE_EnableView 0x80000000 /* Enable the use of views */
/* Flags used only if debugging */
#define HI(X) ((u64)(X)<<32)
#ifdef SQLITE_DEBUG
-#define SQLITE_SqlTrace HI(0x0001) /* Debug print SQL as it executes */
-#define SQLITE_VdbeListing HI(0x0002) /* Debug listings of VDBE progs */
-#define SQLITE_VdbeTrace HI(0x0004) /* True to trace VDBE execution */
-#define SQLITE_VdbeAddopTrace HI(0x0008) /* Trace sqlite3VdbeAddOp() calls */
-#define SQLITE_VdbeEQP HI(0x0010) /* Debug EXPLAIN QUERY PLAN */
-#define SQLITE_ParserTrace HI(0x0020) /* PRAGMA parser_trace=ON */
+#define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */
+#define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */
+#define SQLITE_VdbeTrace HI(0x0400000) /* True to trace VDBE execution */
+#define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */
+#define SQLITE_VdbeEQP HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */
+#define SQLITE_ParserTrace HI(0x2000000) /* PRAGMA parser_trace=ON */
#endif
/*
@@ -1798,6 +1799,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 */
@@ -4440,6 +4442,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)
@@ -4451,6 +4454,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/tclsqlite.c b/src/tclsqlite.c
index 511a9c8a6..80a057262 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -1917,33 +1917,33 @@ static int SQLITE_TCLAPI DbObjCmd(
"authorizer", "backup", "bind_fallback",
"busy", "cache", "changes",
"close", "collate", "collation_needed",
- "commit_hook", "complete", "copy",
- "deserialize", "enable_load_extension", "errorcode",
- "eval", "exists", "function",
- "incrblob", "interrupt", "last_insert_rowid",
- "nullvalue", "onecolumn", "preupdate",
- "profile", "progress", "rekey",
- "restore", "rollback_hook", "serialize",
- "status", "timeout", "total_changes",
- "trace", "trace_v2", "transaction",
- "unlock_notify", "update_hook", "version",
- "wal_hook", 0
+ "commit_hook", "complete", "config",
+ "copy", "deserialize", "enable_load_extension",
+ "errorcode", "eval", "exists",
+ "function", "incrblob", "interrupt",
+ "last_insert_rowid", "nullvalue", "onecolumn",
+ "preupdate", "profile", "progress",
+ "rekey", "restore", "rollback_hook",
+ "serialize", "status", "timeout",
+ "total_changes", "trace", "trace_v2",
+ "transaction", "unlock_notify", "update_hook",
+ "version", "wal_hook", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
DB_BUSY, DB_CACHE, DB_CHANGES,
DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED,
- DB_COMMIT_HOOK, DB_COMPLETE, DB_COPY,
- DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,DB_ERRORCODE,
- DB_EVAL, DB_EXISTS, DB_FUNCTION,
- DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID,
- DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE,
- DB_PROFILE, DB_PROGRESS, DB_REKEY,
- DB_RESTORE, DB_ROLLBACK_HOOK, DB_SERIALIZE,
- DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
- DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
- DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
- DB_WAL_HOOK
+ DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG,
+ DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,
+ DB_ERRORCODE, DB_EVAL, DB_EXISTS,
+ DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT,
+ DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN,
+ DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
+ DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
+ DB_SERIALIZE, DB_STATUS, DB_TIMEOUT,
+ DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2,
+ DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
+ DB_VERSION, DB_WAL_HOOK
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -2331,6 +2331,74 @@ static int SQLITE_TCLAPI DbObjCmd(
break;
}
+ /* $db config ?OPTION? ?BOOLEAN?
+ **
+ ** Configure the database connection using the sqlite3_db_config()
+ ** interface.
+ */
+ case DB_CONFIG: {
+ static const struct DbConfigChoices {
+ const char *zName;
+ int op;
+ } aDbConfig[] = {
+ { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
+ { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
+ { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
+ { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
+ { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
+ { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
+ { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
+ { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
+ { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
+ { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
+ { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
+ { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
+ { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
+ { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
+ };
+ Tcl_Obj *pResult;
+ int ii;
+ if( objc>4 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?OPTION? ?BOOLEAN?");
+ return TCL_ERROR;
+ }
+ if( objc==2 ){
+ /* With no arguments, list all configuration options and with the
+ ** current value */
+ pResult = Tcl_NewListObj(0,0);
+ for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){
+ int v = 0;
+ sqlite3_db_config(pDb->db, aDbConfig[ii].op, -1, &v);
+ Tcl_ListObjAppendElement(interp, pResult,
+ Tcl_NewStringObj(aDbConfig[ii].zName,-1));
+ Tcl_ListObjAppendElement(interp, pResult,
+ Tcl_NewIntObj(v));
+ }
+ }else{
+ const char *zOpt = Tcl_GetString(objv[2]);
+ int onoff = -1;
+ int v = 0;
+ if( zOpt[0]=='-' ) zOpt++;
+ for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){
+ if( strcmp(aDbConfig[ii].zName, zOpt)==0 ) break;
+ }
+ if( ii>=sizeof(aDbConfig)/sizeof(aDbConfig[0]) ){
+ Tcl_AppendResult(interp, "unknown config option: \"", zOpt,
+ "\"", (void*)0);
+ return TCL_ERROR;
+ }
+ if( objc==4 ){
+ if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ){
+ return TCL_ERROR;
+ }
+ }
+ sqlite3_db_config(pDb->db, aDbConfig[ii].op, onoff, &v);
+ pResult = Tcl_NewIntObj(v);
+ }
+ Tcl_SetObjResult(interp, pResult);
+ break;
+ }
+
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
**
** Copy data into table from filename, optionally using SEPARATOR
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";