From: drh Date: Mon, 5 Nov 2018 23:01:45 +0000 (+0000) Subject: Initial code to make shadow tables read-only to ordinary SQL. The now X-Git-Tag: version-3.26.0~47^2~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=84c501bac16576916840daffb671b72cf1f75625;p=thirdparty%2Fsqlite.git Initial code to make shadow tables read-only to ordinary SQL. The now xShadowName method is added to the sqlite3_module object and is used to identify potential shadow tables. The SQLITE_PREPARE_SHADOW argument to sqlite3_prepare_v3() is defined. It is designed to permit writing to shadow tables, but is currently an unused placeholder. FossilOrigin-Name: 31942b3dd3f66eb0d9977bf1cadc2f2d7be7967cce2b55784be0b939dfef1985 --- diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c index 695aaece8c..e88fb7e78c 100644 --- a/ext/expert/sqlite3expert.c +++ b/ext/expert/sqlite3expert.c @@ -644,6 +644,7 @@ static int idxRegisterVtab(sqlite3expert *p){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0, /* xShadowName */ }; return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p); diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 3897054c7c..5899d4f244 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -3846,8 +3846,23 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ return SQLITE_OK; } +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int fts3ShadowName(const char *zName){ + static const char *azName[] = { + "content", "docsize", "segdir", "segments", "stat", + }; + unsigned int i; + for(i=0; idb, zSql, -1, SQLITE_PREPARE_PERSISTENT, + rc = sqlite3_prepare_v3(p->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT | SQLITE_PREPARE_SHADOW, &pStmt, NULL); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index 394280b3f2..e4c13751f5 100644 --- a/ext/fts5/fts5_index.c +++ b/ext/fts5/fts5_index.c @@ -729,7 +729,8 @@ static int fts5IndexPrepareStmt( if( p->rc==SQLITE_OK ){ if( zSql ){ p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1, - SQLITE_PREPARE_PERSISTENT, ppStmt, 0); + SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_SHADOW, + ppStmt, 0); }else{ p->rc = SQLITE_NOMEM; } @@ -780,7 +781,8 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, - SQLITE_PREPARE_PERSISTENT, &p->pDeleter, 0); + SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_SHADOW, + &p->pDeleter, 0); sqlite3_free(zSql); } if( rc!=SQLITE_OK ){ diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c index e9ec2de3a4..41c1c45eb0 100644 --- a/ext/fts5/fts5_main.c +++ b/ext/fts5/fts5_main.c @@ -890,7 +890,8 @@ static int fts5PrepareStatement( rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, - SQLITE_PREPARE_PERSISTENT, &pRet, 0); + SQLITE_PREPARE_PERSISTENT |SQLITE_PREPARE_SHADOW, + &pRet, 0); if( rc!=SQLITE_OK ){ *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); } @@ -2645,9 +2646,24 @@ static void fts5SourceIdFunc( sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT); } +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int fts5ShadowName(const char *zName){ + static const char *azName[] = { + "config", "content", "data", "docsize", "idx" + }; + unsigned int i; + for(i=0; idb, zSql, -1, - SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0); + SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_SHADOW, + &p->aStmt[eStmt], 0); sqlite3_free(zSql); if( rc!=SQLITE_OK && pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); diff --git a/ext/fts5/fts5_test_tok.c b/ext/fts5/fts5_test_tok.c index 1818e16790..6f71e6534d 100644 --- a/ext/fts5/fts5_test_tok.c +++ b/ext/fts5/fts5_test_tok.c @@ -471,7 +471,8 @@ int sqlite3Fts5TestRegisterTok(sqlite3 *db, fts5_api *pApi){ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; int rc; /* Return code */ diff --git a/ext/fts5/fts5_vocab.c b/ext/fts5/fts5_vocab.c index 27f2ff3b2c..c1b64249a4 100644 --- a/ext/fts5/fts5_vocab.c +++ b/ext/fts5/fts5_vocab.c @@ -755,10 +755,9 @@ int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, + /* xShadowName */ 0 }; void *p = (void*)pGlobal; return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0); } - - diff --git a/ext/misc/amatch.c b/ext/misc/amatch.c index 914e2633d4..142e354f28 100644 --- a/ext/misc/amatch.c +++ b/ext/misc/amatch.c @@ -1473,7 +1473,8 @@ static sqlite3_module amatchModule = { 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/ext/misc/btreeinfo.c b/ext/misc/btreeinfo.c index 131b210a79..3d818f20c0 100644 --- a/ext/misc/btreeinfo.c +++ b/ext/misc/btreeinfo.c @@ -411,6 +411,7 @@ int sqlite3BinfoRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "sqlite_btreeinfo", &binfo_module, 0); } diff --git a/ext/misc/closure.c b/ext/misc/closure.c index 74bffc7708..03f13c0c79 100644 --- a/ext/misc/closure.c +++ b/ext/misc/closure.c @@ -938,7 +938,8 @@ static sqlite3_module closureModule = { 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/ext/misc/completion.c b/ext/misc/completion.c index 4a4b918a37..72ad23df93 100644 --- a/ext/misc/completion.c +++ b/ext/misc/completion.c @@ -468,7 +468,8 @@ static sqlite3_module completionModule = { 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/ext/misc/explain.c b/ext/misc/explain.c index b228440f58..dc0c9d7669 100644 --- a/ext/misc/explain.c +++ b/ext/misc/explain.c @@ -280,6 +280,7 @@ static sqlite3_module explainModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0, /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c index 816a353c6e..e3e22ea4b0 100644 --- a/ext/misc/fileio.c +++ b/ext/misc/fileio.c @@ -888,7 +888,8 @@ static int fsdirRegister(sqlite3 *db){ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0, /* xShadowName */ }; int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0); diff --git a/ext/misc/json1.c b/ext/misc/json1.c index 85b1143f83..7cff3d28d8 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -2388,7 +2388,8 @@ static sqlite3_module jsonEachModule = { 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; /* The methods of the json_tree virtual table. */ @@ -2415,7 +2416,8 @@ static sqlite3_module jsonTreeModule = { 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/ext/misc/memstat.c b/ext/misc/memstat.c index 3194e752cc..dcd5742fd2 100644 --- a/ext/misc/memstat.c +++ b/ext/misc/memstat.c @@ -395,6 +395,7 @@ static sqlite3_module memstatModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0, /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/ext/misc/stmt.c b/ext/misc/stmt.c index dbaa0bd64d..d2b33e7416 100644 --- a/ext/misc/stmt.c +++ b/ext/misc/stmt.c @@ -266,6 +266,7 @@ static sqlite3_module stmtModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0, /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/ext/misc/templatevtab.c b/ext/misc/templatevtab.c index 95b5f60cab..d7efa2b40e 100644 --- a/ext/misc/templatevtab.c +++ b/ext/misc/templatevtab.c @@ -248,7 +248,8 @@ static sqlite3_module templatevtabModule = { /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, - /* xRollbackTo */ 0 + /* xRollbackTo */ 0, + /* xShadowName */ 0 }; diff --git a/ext/misc/unionvtab.c b/ext/misc/unionvtab.c index 94a5c8f013..2d2053ce9a 100644 --- a/ext/misc/unionvtab.c +++ b/ext/misc/unionvtab.c @@ -1350,7 +1350,8 @@ static int createUnionVtab(sqlite3 *db){ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; int rc; diff --git a/ext/misc/vtablog.c b/ext/misc/vtablog.c index 9e03fd455d..424b3457ff 100644 --- a/ext/misc/vtablog.c +++ b/ext/misc/vtablog.c @@ -492,6 +492,7 @@ static sqlite3_module vtablogModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0, /* xShadowName */ }; #ifdef _WIN32 diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index be582a3e1b..4ac3b0aa2f 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -1725,7 +1725,7 @@ static int geopolyFindFunction( static sqlite3_module geopolyModule = { - 2, /* iVersion */ + 3, /* iVersion */ geopolyCreate, /* xCreate - create a table */ geopolyConnect, /* xConnect - connect to an existing table */ geopolyBestIndex, /* xBestIndex - Determine search strategy */ @@ -1748,6 +1748,7 @@ static sqlite3_module geopolyModule = { rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + rtreeShadowName /* xShadowName */ }; static int sqlite3_geopoly_init(sqlite3 *db){ diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index c00648f6a2..fd1abef1ec 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -3325,8 +3325,24 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ return rc; } + +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int rtreeShadowName(const char *zName){ + static const char *azName[] = { + "node", "parent", "rowid" + }; + unsigned int i; + for(i=0; ipMod==0 ) return 0; + pMod = pVTab->pMod->pModule; + assert( pMod!=0 ); + if( pMod->iVersion<3 ) return 0; + if( pMod->xShadowName==0 ) return 0; + return pMod->xShadowName(zTail+1); +} + /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. @@ -1933,6 +1962,10 @@ void sqlite3EndTable( p = pParse->pNewTable; if( p==0 ) return; + if( pSelect==0 && isShadowTableName(db, p->zName) ){ + p->tabFlags |= TF_Shadow; + } + /* If the db->init.busy is 1 it means we are reading the SQL off the ** "sqlite_master" or "sqlite_temp_master" table on the disk. ** So do not write to the disk again. Extract the root page number diff --git a/src/dbpage.c b/src/dbpage.c index a73ea01bdb..4f46659018 100644 --- a/src/dbpage.c +++ b/src/dbpage.c @@ -407,6 +407,7 @@ int sqlite3DbpageRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); } diff --git a/src/dbstat.c b/src/dbstat.c index ca0d541013..a2c6fe0894 100644 --- a/src/dbstat.c +++ b/src/dbstat.c @@ -720,6 +720,7 @@ int sqlite3DbstatRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } diff --git a/src/pragma.c b/src/pragma.c index 52d6338ca0..20656dc453 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -2477,7 +2477,8 @@ static const sqlite3_module pragmaVtabModule = { 0, /* xRename - rename the table */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; /* diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 18593a6440..02963f4542 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -3642,10 +3642,19 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** normalize a SQL statement are unspecified and subject to change. ** At a minimum, literal values will be replaced with suitable ** placeholders. +** +** [[SQLITE_PREPARE_SHADOW]] ^(
SQLITE_PREPARE_SHADOW
+**
When the SQLITE_PREPARE_SHADOW flag is set, writes to shadow +** tables are allowed. Shadow tables are ordinary tables associated +** with some virtual tables that serve as the storage for the virtual +** table. Shadow tables are normally read-only. Virtual table +** implementations use this flag so that they can write to their own +** shadow tables. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 +#define SQLITE_PREPARE_SHADOW 0x04 /* ** CAPI3REF: Compiling An SQL Statement @@ -6322,6 +6331,9 @@ struct sqlite3_module { int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. + ** Those below are for version 3 and greater. */ + int (*xShadowName)(const char*); }; /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 27caa1ace6..053ac01dc3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2001,6 +2001,7 @@ struct Table { #define TF_StatsUsed 0x0100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ #define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */ +#define TF_Shadow 0x0400 /* True for a shadow table */ /* ** Test to see whether or not a table is a virtual table. This is