From: dan Date: Fri, 15 Feb 2019 19:00:41 +0000 (+0000) Subject: Fix a problem with eponymous virtual tables and SHARED_SCHEMA databases. Also, after... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6170a98cfa0899d6120f7c88a9835b14de94782e;p=thirdparty%2Fsqlite.git Fix a problem with eponymous virtual tables and SHARED_SCHEMA databases. Also, after preparing statements that require all database schemas (REINDEX, ANALYZE, CREATE, DROP and some PRAGMA statements), do not allow the database connection to return more than one schema to each schema-pool. FossilOrigin-Name: ecf6251ec0bb745a4ef9bad9f9ecd3babb687a3806fd96554b265313625270c5 --- diff --git a/manifest b/manifest index 4bbf649586..6b6cf0d76a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Revert\sthe\srearrangement\sof\sVDBE\scode\sin\s[219b39e14]\sso\sthat\svdbe.c\smatches\strunk.\sSince\sthe\snew\scall\sto\ssqlite3Init()\sin\sOP_ParseSchema\swas\sremoved,\sthe\srearrangement\sno\slonger\sprovides\sany\sperformance\sadvantage. -D 2019-02-15T11:54:57.779 +C Fix\sa\sproblem\swith\seponymous\svirtual\stables\sand\sSHARED_SCHEMA\sdatabases.\sAlso,\safter\spreparing\sstatements\sthat\srequire\sall\sdatabase\sschemas\s(REINDEX,\sANALYZE,\sCREATE,\sDROP\sand\ssome\sPRAGMA\sstatements),\sdo\snot\sallow\sthe\sdatabase\sconnection\sto\sreturn\smore\sthan\sone\sschema\sto\seach\sschema-pool. +D 2019-02-15T19:00:41.452 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 56456706c4da271309914c756c9c8ea537685f1c79f8785afa72f968d6810482 @@ -451,7 +451,7 @@ F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 995b37de876639f1b6c14fcf15f3ee1004e3cbea354ebb43d7f5c4de0d649a64 F src/analyze.c e75c3c1d6534265f74a4763282f17e9ad946606ef0a68c5517fcfb355cc243d0 -F src/attach.c 99c6496d244e2d43b96d8f22381e55236953cbd75273e40a072154ba0b23151c +F src/attach.c 06897ba0fa023ab6aea459afa813c767879c99c8cccedad41126369af455c254 F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 @@ -459,8 +459,8 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c 161b6a57b91d160065e512a4d0be180e402a16a059034a380cbdc2411924f8ac F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f -F src/build.c 364c8fa52cca6002be42c987e7421bd38c40e0f3afdf3198bc174fb92da4f4e8 -F src/callback.c e60a0c3928adb5b5c8dffa3df2d1b34c67177b7c149c9d109012c22a631fc20a +F src/build.c 9ee9a6d4dc5e8cddd0657fc9f2208849e83a59b9cd862bd828260ff28dd972a6 +F src/callback.c 434dc7a483d98cf02bda4a1306813a000b4620fe67f6dfea1635b519f1daf26b F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 @@ -510,7 +510,7 @@ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c a72804486dfa8e4b6bc30d666c97ecf1155f91a4351fc6e48ea4097e4eb304fb F src/pragma.c af67dedaad8bafe9a5f9adcec32a0da6dd118617dd8220ad1d118f5a6bf83a02 F src/pragma.h a776bb9c915207e9d1117b5754743ddf1bf6a39cc092a4a44e74e6cb5fab1177 -F src/prepare.c b7ef5c87a9a8f28999f1085c25c298558a936e561ffdccec1d629d1497a5616d +F src/prepare.c 8335bb97dea9af5a79dd19f87e35bc0c2624578a7a8a07346bb7cc67ad3dd8f6 F src/printf.c cbf27c320091a83279d1738f68a27a9fe01698c607ce80516ab6bdb5a9c36a1a F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 1588690ee4cc39b4b9ea3230d4e3543d5ec3b5e898c87521f1375af0f1934cd4 @@ -520,7 +520,7 @@ F src/shell.c.in d7d63fd1ecef44d19088adc188652252327eab782d59cf1958657943132b508 F src/sqlite.h.in cd9b7c397b942a4903c46ebbabee47f920a9916e96e70e0b4f793076d4b45e31 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683 -F src/sqliteInt.h 0238a621a7d054370b6700c2d1368870cd2282f38a74f3ddafb238a8ea3c181c +F src/sqliteInt.h 2e86c769cc0cca8e7f3324f33f2e1d59f75a861f279716f254b587dfe02de793 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 0361d78dabfd2a92c740911f42723d2f6775d619feb8f8910827f9c9fe8bc30f F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1228,8 +1228,8 @@ F test/releasetest.tcl 7712811e0f4e2f198ec786cb2e1352b3793d7395f48a3cceef0572d88 F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb F test/reuse1.test 31c312375ccfcc5c2abc1fca5e4a89d6309c57ea6b1fa3179a5eee68016f9c74 -F test/reuse2.test 51a4ba225c602bf19847c27c5f0156c3f273f2c8de2456c22b97c2a9a3824d87 -F test/reuse3.test b04e9b7115ece25b28ca57b42464e058cc0de35742b150840a5937c3ddb7ca8a +F test/reuse2.test c33a8973b2de3b4f8b4ffe5c5b455c00a2394b8d71996ee37ed7e861b9f19f1e +F test/reuse3.test b0f7c7236129fdf7ec51528b75fecaa609408a9fccff2ffed34bfa60d27e5881 F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6 F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a @@ -1809,7 +1809,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 d43b3c056cb13930865c504c9498b2c83e4bebce9bff01ee21293e7dc7a6711e -R 1f22cd83b4c1800027f7ed3169157ca0 +P 03c4f00317233a34f29e1218786166d17837d47206532a29d2713093f01adea5 +R fccecdff4cf8aba660dc6d3dc546a5dd U dan -Z 9acec97381a6b009ff18f8e8766d7723 +Z c88bba0b0856cf8c79509301a9c9f542 diff --git a/manifest.uuid b/manifest.uuid index 8ac0d2a097..c6ea043fbe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -03c4f00317233a34f29e1218786166d17837d47206532a29d2713093f01adea5 \ No newline at end of file +ecf6251ec0bb745a4ef9bad9f9ecd3babb687a3806fd96554b265313625270c5 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 47cf37ae26..1b136b2250 100644 --- a/src/attach.c +++ b/src/attach.c @@ -232,8 +232,8 @@ static void attachFunc( */ if( rc==SQLITE_OK ){ db->init.iDb = 0; - db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); if( !IsReuseSchema(db) ){ + db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); sqlite3BtreeEnterAll(db); rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); diff --git a/src/build.c b/src/build.c index c8642161bf..b12c16353e 100644 --- a/src/build.c +++ b/src/build.c @@ -400,7 +400,10 @@ Table *sqlite3LocateTable( if( pMod ){ sqlite3SchemaLoad(db, 0); if( sqlite3VtabEponymousTableInit(pParse, pMod) ){ - return pMod->pEpoTab; + Table *pEpoTab = pMod->pEpoTab; + assert( IsReuseSchema(db) || pEpoTab->pSchema==db->aDb[0].pSchema ); + pEpoTab->pSchema = db->aDb[0].pSchema; /* For SHARED_SCHEMA mode */ + return pEpoTab; } } } diff --git a/src/callback.c b/src/callback.c index 58c70afaf8..fcc14c9204 100644 --- a/src/callback.c +++ b/src/callback.c @@ -603,16 +603,33 @@ static void schemaDelete(Schema *pSchema){ ** This function returns the Schema object to the schema-pool and sets ** Db.pSchema to point to the schema-pool's static, empty, Schema object. */ -static void schemaRelease(Db *pDb){ - assert( pDb->pSPool && pDb->pSchema ); - assert( pDb->pSchema->schemaFlags & DB_SchemaLoaded ); - assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) ); +static void schemaRelease(sqlite3 *db, Db *pDb){ + Schema *pRelease = pDb->pSchema; + SchemaPool *pSPool = pDb->pSPool; - pDb->pSchema->pNext = pDb->pSPool->pSchema; - pDb->pSPool->pSchema = pDb->pSchema; - pDb->pSchema = &pDb->pSPool->sSchema; + pDb->pSchema = &pSPool->sSchema; + assert( pDb->pSPool && pRelease ); + assert( pRelease->schemaFlags & DB_SchemaLoaded ); assert( (pDb->pSchema->schemaFlags & DB_SchemaLoaded)==0 ); + assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) ); + + /* If the DBFLAG_FreeSchema flag is set and the database connection holds + ** at least one other copy of the schema being released, delete it instead + ** of returning it to the schema-pool. */ + if( db->mDbFlags & DBFLAG_FreeSchema ){ + int i; + for(i=0; inDb; i++){ + Db *p = &db->aDb[i]; + if( p!=pDb && p->pSchema!=&pSPool->sSchema && pDb->pSPool==p->pSPool ){ + schemaDelete(pRelease); + return; + } + } + } + + pRelease->pNext = pDb->pSPool->pSchema; + pDb->pSPool->pSchema = pRelease; } /* @@ -710,7 +727,7 @@ int sqlite3SchemaDisconnect(sqlite3 *db, int iDb, int bNew){ pDb->pVTable = 0; sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); if( DbHasProperty(db, iDb, DB_SchemaLoaded) ){ - schemaRelease(pDb); + schemaRelease(db, pDb); } if( bNew ){ Schema *pNew = sqlite3SchemaGet(db, 0); @@ -774,10 +791,11 @@ void sqlite3SchemaReleaseAll(sqlite3 *db){ if( i!=1 ){ Db *pDb = &db->aDb[i]; if( pDb->pSPool && DbHasProperty(db,i,DB_SchemaLoaded) ){ - schemaRelease(pDb); + schemaRelease(db, pDb); } } } + db->flags &= ~DBFLAG_FreeSchema; sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } @@ -792,7 +810,7 @@ void sqlite3SchemaRelease(sqlite3 *db, int iDb){ assert_schema_state_ok(db); sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); if( pDb->pSPool && DbHasProperty(db, iDb, DB_SchemaLoaded) ){ - schemaRelease(pDb); + schemaRelease(db, pDb); } sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } diff --git a/src/prepare.c b/src/prepare.c index ced7d0e922..b1f00184f6 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -481,6 +481,7 @@ int sqlite3ReadSchema(Parse *pParse){ sqlite3 *db = pParse->db; assert( sqlite3_mutex_held(db->mutex) ); if( !db->init.busy ){ + db->mDbFlags |= DBFLAG_FreeSchema; /* For sharable-schema mode */ rc = sqlite3Init(db, &pParse->zErrMsg); if( rc!=SQLITE_OK ){ pParse->rc = rc; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 30cd2fe5a2..7e6c8a1815 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1573,7 +1573,8 @@ struct sqlite3 { #define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ #define DBFLAG_SchemaKnownOk 0x0008 /* Schema is known to be valid */ -#define DBFLAG_SchemaInuse 0x0010 /* Do not free schemas */ +#define DBFLAG_SchemaInuse 0x0010 /* Do not release sharable schemas */ +#define DBFLAG_FreeSchema 0x0020 /* Free extra shared schemas on release */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the diff --git a/test/reuse2.test b/test/reuse2.test index 9e0fe1c743..3ca8bcb51f 100644 --- a/test/reuse2.test +++ b/test/reuse2.test @@ -298,5 +298,11 @@ do_execsql_test -db db2 5.2.3 { SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool ORDER BY 1; } {nref=6 nschema=1} +breakpoint +do_execsql_test -db db2 5.2.4 { + PRAGMA integrity_check; + SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool ORDER BY 1; +} {ok nref=6 nschema=1} + finish_test diff --git a/test/reuse3.test b/test/reuse3.test index 3a69942432..3647e6f907 100644 --- a/test/reuse3.test +++ b/test/reuse3.test @@ -109,7 +109,6 @@ do_test 3.1 { sqlite3 db2 test.db -shared-schema 1 do_test 3.2 { execsql { SELECT * FROM x1 } db2 - breakpoint set N2 [lindex [sqlite3_db_status db2 SCHEMA_USED 0] 1] expr $N2>($N/2) && $N2<($N/2)+400 } 1 @@ -124,5 +123,56 @@ do_test 3.3 { expr {$N4 == (($M / 4) + $N-$M)} } 1 +catch { db1 close } +catch { db2 close } +catch { db3 close } +catch { db4 close } + +#------------------------------------------------------------------------- +# Test the REINDEX command. +reset_db +do_execsql_test 4.1.0 { + CREATE TABLE x1(a, b, c); + CREATE INDEX x1a ON x1(a); + CREATE INDEX x1b ON x1(b); + CREATE INDEX x1c ON x1(c); +} +db close +sqlite3 db test.db -shared-schema 1 + +do_execsql_test 4.1.1 { + REINDEX x1; + REINDEX x1a; + REINDEX x1b; + REINDEX x1c; + REINDEX; +} + +do_test 4.1.2 { + for {set i 1} {$i < 5} {incr i} { + forcedelete test.db${i} test.db${i}-wal test.db${i}-journal + forcecopy test.db test.db${i} + execsql "ATTACH 'test.db${i}' AS db${i}" + } + register_schemapool_module db + set {} {} + execsql { SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool } +} {nref=5 nschema=1} + +do_execsql_test 4.1.3 { + REINDEX x1; + REINDEX x1a; + REINDEX x1b; + REINDEX x1c; + REINDEX db1.x1a; + REINDEX db2.x1b; + REINDEX db3.x1c; + REINDEX; +} + +do_execsql_test 4.1.4 { + SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool; +} {nref=5 nschema=1} + finish_test