1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Merge the scheme-parse-refactor changes into trunk: (1) added

sqlite3SchemaMutexHeld() asserts, (2) Use -1 instead of 0 to mean
"all" in sqlite3ResetInternalSchema(), and other cosmetic changes.

FossilOrigin-Name: 5db4511d8a77b74be3503a7c34257ef6b07541f5
This commit is contained in:
drh
2011-04-05 13:12:28 +00:00
21 changed files with 175 additions and 71 deletions

View File

@@ -1,5 +1,5 @@
C Fix\sthe\sP4_TRANSIENT\sconstant\sso\sthat\sit\sworks\scorrect\s-\sso\sthat\sit\sreally\nmakes\sa\scopy\sof\sthe\sstring\sfor\sthe\sP4\sargument.\s\sUse\sP4_TRANSIENT\swherever\nappropriate.\s\sChange\sP4_STATICs\sof\sschema\snames\sto\sP4_TRANSIENT. C Merge\sthe\sscheme-parse-refactor\schanges\sinto\strunk:\s(1)\sadded\nsqlite3SchemaMutexHeld()\sasserts,\s(2)\sUse\s-1\sinstead\sof\s0\sto\smean\n"all"\sin\ssqlite3ResetInternalSchema(),\sand\sother\scosmetic\schanges.
D 2011-04-05T12:25:19.250 D 2011-04-05T13:12:28.885
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -115,35 +115,35 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c 280f5c04b11b492703a342222b3de0a999445280 F src/alter.c 280f5c04b11b492703a342222b3de0a999445280
F src/analyze.c d0a673d303f611690fc7a3293aaefed57cccc5c8 F src/analyze.c a1ad9f4d8aac055c4a4bbd99073e2e78fe66129c
F src/attach.c 438ea6f6b5d5961c1f49b737f2ce0f14ce7c6877 F src/attach.c 7cae2cf0c14762ce14c074a860ec52890a973a56
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 537f89c7ef5021cb580f31f782e556ffffcb2ed1 F src/backup.c b7529a6691f0fd534ae8ff622203c46a7f1b626b
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 3e595ee1bb99e3a1f16824137b435ffc97c98e5f F src/btmutex.c b81062220a4f91b0bd785d13d57205d68449be88
F src/btree.c 107723ed4f9bdb55213ba6164c30c49af75f4bf9 F src/btree.c 107723ed4f9bdb55213ba6164c30c49af75f4bf9
F src/btree.h a840a20c1969391f98ee06960d5ee2dc460186b3 F src/btree.h c0e0ff5c85effe9fc757e3085bbdded6d1cca000
F src/btreeInt.h 6714ce2f5e879eb9a904a6a4575dc4faa4f29991 F src/btreeInt.h 6714ce2f5e879eb9a904a6a4575dc4faa4f29991
F src/build.c 3a8c6c4b1e16798755d46e699b7fcc12b9f27b2b F src/build.c d809f57250b10e83586bc23921de02055890b239
F src/callback.c 5069f224882cbdccd559f591271d28d7f37745bc F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 52ff72f966cee3087e0138a3ec69371c22be3c01 F src/ctime.c 52ff72f966cee3087e0138a3ec69371c22be3c01
F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b
F src/delete.c 7a24fcc9a31664d145acb97ce56b6d9f249a25e4 F src/delete.c 7a24fcc9a31664d145acb97ce56b6d9f249a25e4
F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 8ab7ace42f9be515e97202fc942e87c35309c05e F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91
F src/func.c 3a8cb2fb2de3e3aed7f39106daf4878d9d17fcce F src/func.c 3a8cb2fb2de3e3aed7f39106daf4878d9d17fcce
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 4083e8af5c7ca6faa32a56f8f2f80bac346b13a4 F src/insert.c 6873a0b359e538d0568a8b459ca630edef8dde2c
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e
F src/main.c c23c62e53d120c5eee086c0e2cc96cc9a691c50e F src/main.c 83cb6a9f1404d59b4dc06ef58cf20401ac1f2261
F src/malloc.c 92d59a007d7a42857d4e9454aa25b6b703286be1 F src/malloc.c 92d59a007d7a42857d4e9454aa25b6b703286be1
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
@@ -170,8 +170,8 @@ F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050 F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
F src/pcache1.c d548e31beafa792d1994b663a29a5303569efc4e F src/pcache1.c d548e31beafa792d1994b663a29a5303569efc4e
F src/pragma.c 65698dc369567de328cac4aaf020e417e5b8745d F src/pragma.c 49c90ab27a4339d4b5bc0b03c08cbcf20ed8d454
F src/prepare.c eb4944d9f7bfa13eb42a7416ed9aaed4de4d0bf3 F src/prepare.c 206e1f06479fb5f756592bded468bd3ece3f41d4
F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1 F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
@@ -180,9 +180,9 @@ F src/select.c d24406c45dd2442eb2eeaac413439066b149c944
F src/shell.c 9dc0b4bb59290c0a35256d278cab0f314987ad6a F src/shell.c 9dc0b4bb59290c0a35256d278cab0f314987ad6a
F src/sqlite.h.in e047f69a61d604d4f8be6cf1d1bdfc68be9ba7e5 F src/sqlite.h.in e047f69a61d604d4f8be6cf1d1bdfc68be9ba7e5
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
F src/sqliteInt.h d45b0b1db417d5308e3bf9c8983aaf2d06e7cd36 F src/sqliteInt.h 7b0150bfdab049b11bb2d055d065051ff734d113
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 501c9a200fd998a268be475be5858febc90b725b F src/tclsqlite.c 501c9a200fd998a268be475be5858febc90b725b
F src/test1.c 9ca440e80e16e53920904a0a5ac7feffb9b2c9a1 F src/test1.c 9ca440e80e16e53920904a0a5ac7feffb9b2c9a1
@@ -230,20 +230,20 @@ F src/test_vfstrace.c 2265c9895f350c8d3c39b079998fbe7481505cc1
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290 F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080 F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
F src/trigger.c 4c1ed08b8dca272e16112c837c64848c56b323e6 F src/trigger.c d5bc8b9ffa2b54569ce635084765c6e41aa9d174
F src/update.c 81911be16ece3c3e7716aa18565b4814ec41f8b9 F src/update.c 81911be16ece3c3e7716aa18565b4814ec41f8b9
F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60 F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60
F src/util.c cd997077bad039efc0597eb027c929658f93c018 F src/util.c cd997077bad039efc0597eb027c929658f93c018
F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
F src/vdbe.c 6488f759929602cbc3acea5e9c7c10e2d2cd00ed F src/vdbe.c 0140a57f9cbd50351219bfc4e44ef3de64bd65b8
F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797 F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797
F src/vdbeInt.h 7e2f028ecc1a9faa6f253e7aa8d89cae03662bae F src/vdbeInt.h 7e2f028ecc1a9faa6f253e7aa8d89cae03662bae
F src/vdbeapi.c a09ad9164cafc505250d5dd6b69660c960f1308c F src/vdbeapi.c a09ad9164cafc505250d5dd6b69660c960f1308c
F src/vdbeaux.c 010e4e67a5a577451b0220ea8903c9e279a43248 F src/vdbeaux.c e1ea6edc07b4f33a339cc45a2fbe0a36067d2d8b
F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5 F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
F src/vtab.c e1edca38c4c4310710635bb91bb3c87fdf60f21d F src/vtab.c b0abc931f95af94c9ffdf9f747eb191cda953123
F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794
F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
@@ -926,7 +926,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P bcbc9ff568d1eb9f925574ebd22e5fdfa06daf6e P bf664b206bf6f5c1941da1986dfe2c0d1831d5e4 2aff1b0ca87a99b8ec80e696b9e8a48bb43db2c2
R 7427b4db22639678e80e85b7a7894dba R 22cfdab389baca0a36a30b474bcbf649
U drh U drh
Z 8ac4b3854411b1d7191f15313f585b57 Z d9847e96611c99287cdc62e449a97608

View File

@@ -1 +1 @@
bf664b206bf6f5c1941da1986dfe2c0d1831d5e4 5db4511d8a77b74be3503a7c34257ef6b07541f5

View File

@@ -149,6 +149,7 @@ static void analyzeOneTable(
assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3BtreeHoldsAllMutexes(db) );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema); iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb>=0 ); assert( iDb>=0 );
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
db->aDb[iDb].zName ) ){ db->aDb[iDb].zName ) ){
@@ -390,6 +391,7 @@ static void analyzeDatabase(Parse *pParse, int iDb){
pParse->nTab += 2; pParse->nTab += 2;
openStatTable(pParse, iDb, iStatCur, 0, 0); openStatTable(pParse, iDb, iStatCur, 0, 0);
iMem = pParse->nMem+1; iMem = pParse->nMem+1;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k); Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem); analyzeOneTable(pParse, pTab, 0, iStatCur, iMem);
@@ -600,9 +602,9 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 ); assert( db->aDb[iDb].pBt!=0 );
assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
/* Clear any prior statistics */ /* Clear any prior statistics */
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i); Index *pIdx = sqliteHashData(i);
sqlite3DefaultRowEst(pIdx); sqlite3DefaultRowEst(pIdx);

View File

@@ -200,7 +200,7 @@ static void attachFunc(
db->aDb[iDb].pBt = 0; db->aDb[iDb].pBt = 0;
db->aDb[iDb].pSchema = 0; db->aDb[iDb].pSchema = 0;
} }
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
db->nDb = iDb; db->nDb = iDb;
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
db->mallocFailed = 1; db->mallocFailed = 1;
@@ -272,7 +272,7 @@ static void detachFunc(
sqlite3BtreeClose(pDb->pBt); sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0; pDb->pBt = 0;
pDb->pSchema = 0; pDb->pSchema = 0;
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
return; return;
detach_error: detach_error:

View File

@@ -401,7 +401,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int nDestTruncate; int nDestTruncate;
if( p->pDestDb ){ if( p->pDestDb ){
sqlite3ResetInternalSchema(p->pDestDb, 0); sqlite3ResetInternalSchema(p->pDestDb, -1);
} }
/* Set nDestTruncate to the final number of pages in the destination /* Set nDestTruncate to the final number of pages in the destination

View File

@@ -288,6 +288,31 @@ int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
} }
#endif /* NDEBUG */ #endif /* NDEBUG */
#ifndef NDEBUG
/*
** Return true if the correct mutexes are held for accessing the
** db->aDb[iDb].pSchema structure. The mutexes required for schema
** access are:
**
** (1) The mutex on db
** (2) if iDb!=1, then the mutex on db->aDb[iDb].pBt.
**
** If pSchema is not NULL, then iDb is computed from pSchema and
** db using sqlite3SchemaToIndex().
*/
int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
Btree *p;
assert( db!=0 );
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
assert( iDb>=0 && iDb<db->nDb );
if( !sqlite3_mutex_held(db->mutex) ) return 0;
if( iDb==1 ) return 1;
p = db->aDb[iDb].pBt;
assert( p!=0 );
return p->sharable==0 || p->locked==1;
}
#endif /* NDEBUG */
#else /* SQLITE_THREADSAFE>0 above. SQLITE_THREADSAFE==0 below */ #else /* SQLITE_THREADSAFE>0 above. SQLITE_THREADSAFE==0 below */
/* /*
** The following are special cases for mutex enter routines for use ** The following are special cases for mutex enter routines for use

View File

@@ -220,6 +220,7 @@ void sqlite3BtreeCursorList(Btree*);
/* These routines are used inside assert() statements only. */ /* These routines are used inside assert() statements only. */
int sqlite3BtreeHoldsMutex(Btree*); int sqlite3BtreeHoldsMutex(Btree*);
int sqlite3BtreeHoldsAllMutexes(sqlite3*); int sqlite3BtreeHoldsAllMutexes(sqlite3*);
int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
u32 sqlite3BtreeMutexCounter(Btree*); u32 sqlite3BtreeMutexCounter(Btree*);
#endif #endif
#else #else
@@ -232,6 +233,7 @@ void sqlite3BtreeCursorList(Btree*);
# define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsMutex(X) 1
# define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1
# define sqlite3BtreeSchemaMutexHeld(X,Y) 1
#endif #endif

View File

@@ -156,6 +156,7 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
if( db->init.busy==0 ){ if( db->init.busy==0 ){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
sqlite3VdbeAddOp3(v, OP_VerifyCookie, sqlite3VdbeAddOp3(v, OP_VerifyCookie,
iDb, pParse->cookieValue[iDb], iDb, pParse->cookieValue[iDb],
db->aDb[iDb].pSchema->iGeneration); db->aDb[iDb].pSchema->iGeneration);
@@ -271,9 +272,12 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
int nName; int nName;
assert( zName!=0 ); assert( zName!=0 );
nName = sqlite3Strlen30(zName); nName = sqlite3Strlen30(zName);
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){ for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, nName); p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, nName);
if( p ) break; if( p ) break;
} }
@@ -333,11 +337,14 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
Index *p = 0; Index *p = 0;
int i; int i;
int nName = sqlite3Strlen30(zName); int nName = sqlite3Strlen30(zName);
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){ for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
Schema *pSchema = db->aDb[j].pSchema; Schema *pSchema = db->aDb[j].pSchema;
assert( pSchema ); assert( pSchema );
if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&pSchema->idxHash, zName, nName); p = sqlite3HashFind(&pSchema->idxHash, zName, nName);
if( p ) break; if( p ) break;
} }
@@ -364,8 +371,10 @@ static void freeIndex(sqlite3 *db, Index *p){
void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
Index *pIndex; Index *pIndex;
int len; int len;
Hash *pHash = &db->aDb[iDb].pSchema->idxHash; Hash *pHash;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pHash = &db->aDb[iDb].pSchema->idxHash;
len = sqlite3Strlen30(zIdxName); len = sqlite3Strlen30(zIdxName);
pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0); pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
if( ALWAYS(pIndex) ){ if( ALWAYS(pIndex) ){
@@ -393,26 +402,40 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
** if there were schema changes during the transaction or if a ** if there were schema changes during the transaction or if a
** schema-cookie mismatch occurs. ** schema-cookie mismatch occurs.
** **
** If iDb==0 then reset the internal schema tables for all database ** If iDb<0 then reset the internal schema tables for all database
** files. If iDb>=1 then reset the internal schema for only the ** files. If iDb>=0 then reset the internal schema for only the
** single file indicated. ** single file indicated.
*/ */
void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
int i, j; int i, j;
assert( iDb>=0 && iDb<db->nDb ); assert( iDb<db->nDb );
if( iDb==0 ){ if( iDb>=0 ){
sqlite3BtreeEnterAll(db); /* Case 1: Reset the single schema identified by iDb */
Db *pDb = &db->aDb[iDb];
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( ALWAYS(pDb->pSchema) ){
sqlite3SchemaClear(pDb->pSchema);
} }
for(i=iDb; i<db->nDb; i++){ /* If any database other than TEMP is reset, then also reset TEMP
** since TEMP might be holding triggers that reference tables in the
** other database.
*/
if( iDb!=1 && (pDb = &db->aDb[1])!=0 && ALWAYS(pDb->pSchema) ){
sqlite3SchemaClear(pDb->pSchema);
}
return;
}
/* Case 2 (from here to the end): Reset all schemas for all attached
** databases. */
assert( iDb<0 );
sqlite3BtreeEnterAll(db);
for(i=0; i<db->nDb; i++){
Db *pDb = &db->aDb[i]; Db *pDb = &db->aDb[i];
if( pDb->pSchema ){ if( pDb->pSchema ){
assert(i==1 || (pDb->pBt && sqlite3BtreeHoldsMutex(pDb->pBt))); sqlite3SchemaClear(pDb->pSchema);
sqlite3SchemaFree(pDb->pSchema);
} }
if( iDb>0 ) return;
} }
assert( iDb==0 );
db->flags &= ~SQLITE_InternChanges; db->flags &= ~SQLITE_InternChanges;
sqlite3VtabUnlockList(db); sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db); sqlite3BtreeLeaveAll(db);
@@ -498,6 +521,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
TESTONLY ( Index *pOld = ) sqlite3HashInsert( TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0 &pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0
); );
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
assert( pOld==pIndex || pOld==0 ); assert( pOld==pIndex || pOld==0 );
} }
freeIndex(db, pIndex); freeIndex(db, pIndex);
@@ -532,6 +556,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
assert( db!=0 ); assert( db!=0 );
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
assert( zTabName ); assert( zTabName );
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */
pDb = &db->aDb[iDb]; pDb = &db->aDb[iDb];
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName,
@@ -816,6 +841,7 @@ void sqlite3StartTable(
*/ */
#ifndef SQLITE_OMIT_AUTOINCREMENT #ifndef SQLITE_OMIT_AUTOINCREMENT
if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){ if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pTable->pSchema->pSeqTab = pTable; pTable->pSchema->pSeqTab = pTable;
} }
#endif #endif
@@ -1276,6 +1302,7 @@ void sqlite3ChangeCookie(Parse *pParse, int iDb){
int r1 = sqlite3GetTempReg(pParse); int r1 = sqlite3GetTempReg(pParse);
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1); sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1);
sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r1);
@@ -1578,6 +1605,7 @@ void sqlite3EndTable(
*/ */
if( p->tabFlags & TF_Autoincrement ){ if( p->tabFlags & TF_Autoincrement ){
Db *pDb = &db->aDb[iDb]; Db *pDb = &db->aDb[iDb];
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( pDb->pSchema->pSeqTab==0 ){ if( pDb->pSchema->pSeqTab==0 ){
sqlite3NestedParse(pParse, sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_sequence(name,seq)", "CREATE TABLE %Q.sqlite_sequence(name,seq)",
@@ -1598,6 +1626,7 @@ void sqlite3EndTable(
if( db->init.busy ){ if( db->init.busy ){
Table *pOld; Table *pOld;
Schema *pSchema = p->pSchema; Schema *pSchema = p->pSchema;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName,
sqlite3Strlen30(p->zName),p); sqlite3Strlen30(p->zName),p);
if( pOld ){ if( pOld ){
@@ -1782,6 +1811,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pSelTab->nCol = 0; pSelTab->nCol = 0;
pSelTab->aCol = 0; pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab); sqlite3DeleteTable(db, pSelTab);
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
pTable->pSchema->flags |= DB_UnresetViews; pTable->pSchema->flags |= DB_UnresetViews;
}else{ }else{
pTable->nCol = 0; pTable->nCol = 0;
@@ -1802,6 +1832,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
*/ */
static void sqliteViewResetAll(sqlite3 *db, int idx){ static void sqliteViewResetAll(sqlite3 *db, int idx){
HashElem *i; HashElem *i;
assert( sqlite3SchemaMutexHeld(db, idx, 0) );
if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i); Table *pTab = sqliteHashData(i);
@@ -1835,10 +1866,13 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
** in order to be certain that we got the right one. ** in order to be certain that we got the right one.
*/ */
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){ void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
HashElem *pElem; HashElem *pElem;
Hash *pHash; Hash *pHash;
Db *pDb;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pDb = &db->aDb[iDb];
pHash = &pDb->pSchema->tblHash; pHash = &pDb->pSchema->tblHash;
for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem); Table *pTab = sqliteHashData(pElem);
@@ -2212,6 +2246,7 @@ void sqlite3CreateForeignKey(
pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */ pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */
pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */ pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */
assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey
); );
@@ -2567,6 +2602,7 @@ Index *sqlite3CreateIndex(
pIndex->onError = (u8)onError; pIndex->onError = (u8)onError;
pIndex->autoIndex = (u8)(pName==0); pIndex->autoIndex = (u8)(pName==0);
pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->pSchema = db->aDb[iDb].pSchema;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
/* Check to see if we should honor DESC requests on index columns /* Check to see if we should honor DESC requests on index columns
*/ */
@@ -2696,6 +2732,7 @@ Index *sqlite3CreateIndex(
*/ */
if( db->init.busy ){ if( db->init.busy ){
Index *p; Index *p;
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
p = sqlite3HashInsert(&pIndex->pSchema->idxHash, p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
pIndex->zName, sqlite3Strlen30(pIndex->zName), pIndex->zName, sqlite3Strlen30(pIndex->zName),
pIndex); pIndex);
@@ -3449,6 +3486,7 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
assert( iDb<db->nDb ); assert( iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 || iDb==1 ); assert( db->aDb[iDb].pBt!=0 || iDb==1 );
assert( iDb<SQLITE_MAX_ATTACHED+2 ); assert( iDb<SQLITE_MAX_ATTACHED+2 );
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
mask = ((yDbMask)1)<<iDb; mask = ((yDbMask)1)<<iDb;
if( (pToplevel->cookieMask & mask)==0 ){ if( (pToplevel->cookieMask & mask)==0 ){
pToplevel->cookieMask |= mask; pToplevel->cookieMask |= mask;
@@ -3576,6 +3614,7 @@ static void reindexDatabases(Parse *pParse, char const *zColl){
HashElem *k; /* For looping over tables in pDb */ HashElem *k; /* For looping over tables in pDb */
Table *pTab; /* A table in the database */ Table *pTab; /* A table in the database */
assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){ for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
assert( pDb!=0 ); assert( pDb!=0 );
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){

View File

@@ -400,12 +400,12 @@ FuncDef *sqlite3FindFunction(
/* /*
** Free all resources held by the schema structure. The void* argument points ** Free all resources held by the schema structure. The void* argument points
** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the ** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
** pointer itself, it just cleans up subsiduary resources (i.e. the contents ** pointer itself, it just cleans up subsidiary resources (i.e. the contents
** of the schema hash tables). ** of the schema hash tables).
** **
** The Schema.cache_size variable is not cleared. ** The Schema.cache_size variable is not cleared.
*/ */
void sqlite3SchemaFree(void *p){ void sqlite3SchemaClear(void *p){
Hash temp1; Hash temp1;
Hash temp2; Hash temp2;
HashElem *pElem; HashElem *pElem;
@@ -440,7 +440,7 @@ void sqlite3SchemaFree(void *p){
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
Schema * p; Schema * p;
if( pBt ){ if( pBt ){
p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaFree); p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
}else{ }else{
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema)); p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
} }

View File

@@ -1154,6 +1154,7 @@ void sqlite3FkDelete(sqlite3 *db, Table *pTab){
FKey *pFKey; /* Iterator variable */ FKey *pFKey; /* Iterator variable */
FKey *pNext; /* Copy of pFKey->pNextFrom */ FKey *pNext; /* Copy of pFKey->pNextFrom */
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
/* Remove the FK from the fkeyHash hash table. */ /* Remove the FK from the fkeyHash hash table. */

View File

@@ -237,6 +237,7 @@ void sqlite3AutoincrementBegin(Parse *pParse){
for(p = pParse->pAinc; p; p = p->pNext){ for(p = pParse->pAinc; p; p = p->pNext){
pDb = &db->aDb[p->iDb]; pDb = &db->aDb[p->iDb];
memId = p->regCtr; memId = p->regCtr;
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
addr = sqlite3VdbeCurrentAddr(v); addr = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
@@ -287,6 +288,7 @@ void sqlite3AutoincrementEnd(Parse *pParse){
int memId = p->regCtr; int memId = p->regCtr;
iRec = sqlite3GetTempReg(pParse); iRec = sqlite3GetTempReg(pParse);
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1);
j2 = sqlite3VdbeAddOp0(v, OP_Rewind); j2 = sqlite3VdbeAddOp0(v, OP_Rewind);

View File

@@ -687,7 +687,8 @@ int sqlite3_close(sqlite3 *db){
} }
sqlite3_mutex_enter(db->mutex); sqlite3_mutex_enter(db->mutex);
sqlite3ResetInternalSchema(db, 0); /* Force xDestroy calls on all virtual tables */
sqlite3ResetInternalSchema(db, -1);
/* If a transaction is open, the ResetInternalSchema() call above /* If a transaction is open, the ResetInternalSchema() call above
** will not have called the xDisconnect() method on any virtual ** will not have called the xDisconnect() method on any virtual
@@ -730,7 +731,7 @@ int sqlite3_close(sqlite3 *db){
} }
} }
} }
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
/* Tell the code in notify.c that the connection no longer holds any /* Tell the code in notify.c that the connection no longer holds any
** locks and does not require any further unlock-notify callbacks. ** locks and does not require any further unlock-notify callbacks.
@@ -821,7 +822,7 @@ void sqlite3RollbackAll(sqlite3 *db){
if( db->flags&SQLITE_InternChanges ){ if( db->flags&SQLITE_InternChanges ){
sqlite3ExpirePreparedStatements(db); sqlite3ExpirePreparedStatements(db);
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
} }
/* Any deferred constraint violations have now been resolved. */ /* Any deferred constraint violations have now been resolved. */

View File

@@ -115,7 +115,7 @@ static int invalidateTempStorage(Parse *pParse){
} }
sqlite3BtreeClose(db->aDb[1].pBt); sqlite3BtreeClose(db->aDb[1].pBt);
db->aDb[1].pBt = 0; db->aDb[1].pBt = 0;
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
} }
return SQLITE_OK; return SQLITE_OK;
} }
@@ -388,6 +388,7 @@ void sqlite3Pragma(
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, size, 1); sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pDb->pSchema->cache_size = size; pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
} }
@@ -690,6 +691,7 @@ void sqlite3Pragma(
*/ */
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){ if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( sqlite3ReadSchema(pParse) ) goto pragma_out;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( !zRight ){ if( !zRight ){
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size); returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
}else{ }else{
@@ -1110,6 +1112,7 @@ void sqlite3Pragma(
** Begin by filling registers 2, 3, ... with the root pages numbers ** Begin by filling registers 2, 3, ... with the root pages numbers
** for all tables and indices in the database. ** for all tables and indices in the database.
*/ */
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pTbls = &db->aDb[i].pSchema->tblHash; pTbls = &db->aDb[i].pSchema->tblHash;
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x); Table *pTab = sqliteHashData(x);

View File

@@ -338,7 +338,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
} }
if( db->mallocFailed ){ if( db->mallocFailed ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
} }
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
/* Black magic: If the SQLITE_RecoveryMode flag is set, then consider /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
@@ -470,7 +470,9 @@ static void schemaIsValid(Parse *pParse){
** value stored as part of the in-memory schema representation, ** value stored as part of the in-memory schema representation,
** set Parse.rc to SQLITE_SCHEMA. */ ** set Parse.rc to SQLITE_SCHEMA. */
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie); sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){ if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
sqlite3ResetInternalSchema(db, iDb);
pParse->rc = SQLITE_SCHEMA; pParse->rc = SQLITE_SCHEMA;
} }
@@ -612,9 +614,6 @@ static int sqlite3Prepare(
if( pParse->checkSchema ){ if( pParse->checkSchema ){
schemaIsValid(pParse); schemaIsValid(pParse);
} }
if( pParse->rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(db, 0);
}
if( db->mallocFailed ){ if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM; pParse->rc = SQLITE_NOMEM;
} }

View File

@@ -668,6 +668,20 @@ struct Db {
/* /*
** An instance of the following structure stores a database schema. ** An instance of the following structure stores a database schema.
**
** Most Schema objects are associated with a Btree. The exception is
** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
** In shared cache mode, a single Schema object can be shared by multiple
** Btrees that refer to the same underlying BtShared object.
**
** Schema objects are automatically deallocated when the last Btree that
** references them is destroyed. The TEMP Schema is manually freed by
** sqlite3_close().
*
** A thread must be holding a mutex on the corresponding Btree in order
** to access Schema content. This implies that the thread must also be
** holding a mutex on the sqlite3 connection pointer that owns the Btree.
** For a TEMP Schema, on the connection mutex is required.
*/ */
struct Schema { struct Schema {
int schema_cookie; /* Database schema version number for this file */ int schema_cookie; /* Database schema version number for this file */
@@ -1184,7 +1198,7 @@ struct CollSeq {
** schema is shared, as the implementation often stores the database ** schema is shared, as the implementation often stores the database
** connection handle passed to it via the xConnect() or xCreate() method ** connection handle passed to it via the xConnect() or xCreate() method
** during initialization internally. This database connection handle may ** during initialization internally. This database connection handle may
** then used by the virtual table implementation to access real tables ** then be used by the virtual table implementation to access real tables
** within the database. So that they appear as part of the callers ** within the database. So that they appear as part of the callers
** transaction, these accesses need to be made via the same database ** transaction, these accesses need to be made via the same database
** connection as that used to execute SQL operations on the virtual table. ** connection as that used to execute SQL operations on the virtual table.
@@ -2942,7 +2956,7 @@ extern SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
extern int sqlite3PendingByte; extern int sqlite3PendingByte;
#endif #endif
#endif #endif
void sqlite3RootPageMoved(Db*, int, int); void sqlite3RootPageMoved(sqlite3*, int, int, int);
void sqlite3Reindex(Parse*, Token*, Token*); void sqlite3Reindex(Parse*, Token*, Token*);
void sqlite3AlterFunctions(void); void sqlite3AlterFunctions(void);
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
@@ -2969,7 +2983,7 @@ void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int); void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
void sqlite3MinimumFileFormat(Parse*, int, int); void sqlite3MinimumFileFormat(Parse*, int, int);
void sqlite3SchemaFree(void *); void sqlite3SchemaClear(void *);
Schema *sqlite3SchemaGet(sqlite3 *, Btree *); Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
int sqlite3SchemaToIndex(sqlite3 *db, Schema *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *); KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);

View File

@@ -163,6 +163,7 @@ int sqlite3_db_status(
int i; /* Used to iterate through schemas */ int i; /* Used to iterate through schemas */
int nByte = 0; /* Used to accumulate return value */ int nByte = 0; /* Used to accumulate return value */
sqlite3BtreeEnterAll(db);
db->pnBytesFreed = &nByte; db->pnBytesFreed = &nByte;
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema; Schema *pSchema = db->aDb[i].pSchema;
@@ -189,6 +190,7 @@ int sqlite3_db_status(
} }
} }
db->pnBytesFreed = 0; db->pnBytesFreed = 0;
sqlite3BtreeLeaveAll(db);
*pHighwater = 0; *pHighwater = 0;
*pCurrent = nByte; *pCurrent = nByte;

View File

@@ -54,6 +54,7 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
if( pTmpSchema!=pTab->pSchema ){ if( pTmpSchema!=pTab->pSchema ){
HashElem *p; HashElem *p;
assert( sqlite3SchemaMutexHeld(pParse->db, 0, pTmpSchema) );
for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){ for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
Trigger *pTrig = (Trigger *)sqliteHashData(p); Trigger *pTrig = (Trigger *)sqliteHashData(p);
if( pTrig->pTabSchema==pTab->pSchema if( pTrig->pTabSchema==pTab->pSchema
@@ -165,6 +166,7 @@ void sqlite3BeginTrigger(
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto trigger_cleanup; goto trigger_cleanup;
} }
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),
zName, sqlite3Strlen30(zName)) ){ zName, sqlite3Strlen30(zName)) ){
if( !noErr ){ if( !noErr ){
@@ -304,6 +306,7 @@ void sqlite3FinishTrigger(
if( db->init.busy ){ if( db->init.busy ){
Trigger *pLink = pTrig; Trigger *pLink = pTrig;
Hash *pHash = &db->aDb[iDb].pSchema->trigHash; Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig); pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig);
if( pTrig ){ if( pTrig ){
db->mallocFailed = 1; db->mallocFailed = 1;
@@ -485,9 +488,11 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
zDb = pName->a[0].zDatabase; zDb = pName->a[0].zDatabase;
zName = pName->a[0].zName; zName = pName->a[0].zName;
nName = sqlite3Strlen30(zName); nName = sqlite3Strlen30(zName);
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){ for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName); pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName);
if( pTrigger ) break; if( pTrigger ) break;
} }
@@ -576,8 +581,11 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
** Remove a trigger from the hash tables of the sqlite* pointer. ** Remove a trigger from the hash tables of the sqlite* pointer.
*/ */
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Hash *pHash = &(db->aDb[iDb].pSchema->trigHash);
Trigger *pTrigger; Trigger *pTrigger;
Hash *pHash;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pHash = &(db->aDb[iDb].pSchema->trigHash);
pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0); pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0);
if( ALWAYS(pTrigger) ){ if( ALWAYS(pTrigger) ){
if( pTrigger->pSchema==pTrigger->pTabSchema ){ if( pTrigger->pSchema==pTrigger->pTabSchema ){

View File

@@ -335,8 +335,11 @@ end_of_vacuum:
pDb->pSchema = 0; pDb->pSchema = 0;
} }
sqlite3ResetInternalSchema(db, 0); /* This both clears the schemas and reduces the size of the db->aDb[]
** array. */
sqlite3ResetInternalSchema(db, -1);
return rc; return rc;
} }
#endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */ #endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */

View File

@@ -551,7 +551,7 @@ int sqlite3VdbeExec(
Op *pOp; /* Current operation */ Op *pOp; /* Current operation */
int rc = SQLITE_OK; /* Value to return */ int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */ sqlite3 *db = p->db; /* The database */
u8 resetSchemaOnFault = 0; /* Reset schema after an error if true */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
u8 encoding = ENC(db); /* The database encoding */ u8 encoding = ENC(db); /* The database encoding */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
int checkProgress; /* True if progress callbacks are enabled */ int checkProgress; /* True if progress callbacks are enabled */
@@ -2659,7 +2659,7 @@ case OP_Savepoint: {
} }
if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
sqlite3ExpirePreparedStatements(db); sqlite3ExpirePreparedStatements(db);
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
sqlite3VdbeMutexResync(p); sqlite3VdbeMutexResync(p);
db->flags = (db->flags | SQLITE_InternChanges); db->flags = (db->flags | SQLITE_InternChanges);
} }
@@ -2880,6 +2880,7 @@ case OP_SetCookie: { /* in3 */
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
pDb = &db->aDb[pOp->p1]; pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 ); assert( pDb->pBt!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
pIn3 = &aMem[pOp->p3]; pIn3 = &aMem[pOp->p3];
sqlite3VdbeMemIntegerify(pIn3); sqlite3VdbeMemIntegerify(pIn3);
/* See note about index shifting on OP_ReadCookie */ /* See note about index shifting on OP_ReadCookie */
@@ -2926,6 +2927,7 @@ case OP_VerifyCookie: {
assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
pBt = db->aDb[pOp->p1].pBt; pBt = db->aDb[pOp->p1].pBt;
if( pBt ){ if( pBt ){
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
@@ -2951,7 +2953,6 @@ case OP_VerifyCookie: {
*/ */
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
sqlite3ResetInternalSchema(db, pOp->p1); sqlite3ResetInternalSchema(db, pOp->p1);
sqlite3VdbeMutexResync(p);
} }
p->expired = 1; p->expired = 1;
@@ -3036,6 +3037,7 @@ case OP_OpenWrite: {
assert( pX!=0 ); assert( pX!=0 );
if( pOp->opcode==OP_OpenWrite ){ if( pOp->opcode==OP_OpenWrite ){
wrFlag = 1; wrFlag = 1;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( pDb->pSchema->file_format < p->minWriteFileFormat ){ if( pDb->pSchema->file_format < p->minWriteFileFormat ){
p->minWriteFileFormat = pDb->pSchema->file_format; p->minWriteFileFormat = pDb->pSchema->file_format;
} }
@@ -4531,8 +4533,10 @@ case OP_Destroy: { /* out2-prerelease */
pOut->u.i = iMoved; pOut->u.i = iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
if( rc==SQLITE_OK && iMoved!=0 ){ if( rc==SQLITE_OK && iMoved!=0 ){
sqlite3RootPageMoved(&db->aDb[iDb], iMoved, pOp->p1); sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1);
resetSchemaOnFault = 1; /* All OP_Destroy operations occur on the same btree */
assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 );
resetSchemaOnFault = iDb+1;
} }
#endif #endif
} }
@@ -5966,9 +5970,8 @@ vdbe_error_halt:
sqlite3VdbeHalt(p); sqlite3VdbeHalt(p);
if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1; if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
if( resetSchemaOnFault ){ if( resetSchemaOnFault>0 ){
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, resetSchemaOnFault-1);
sqlite3VdbeMutexResync(p);
} }
/* This is the only way out of this procedure. We have to /* This is the only way out of this procedure. We have to

View File

@@ -2278,7 +2278,7 @@ int sqlite3VdbeHalt(Vdbe *p){
/* Rollback or commit any schema changes that occurred. */ /* Rollback or commit any schema changes that occurred. */
if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){ if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
db->flags = (db->flags | SQLITE_InternChanges); db->flags = (db->flags | SQLITE_InternChanges);
} }

View File

@@ -48,7 +48,7 @@ static int createModule(
if( pDel==pMod ){ if( pDel==pMod ){
db->mallocFailed = 1; db->mallocFailed = 1;
} }
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, -1);
}else if( xDestroy ){ }else if( xDestroy ){
xDestroy(pAux); xDestroy(pAux);
} }
@@ -145,10 +145,9 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
** that contains table p is held by the caller. See header comments ** that contains table p is held by the caller. See header comments
** above function sqlite3VtabUnlockList() for an explanation of why ** above function sqlite3VtabUnlockList() for an explanation of why
** this makes it safe to access the sqlite3.pDisconnect list of any ** this makes it safe to access the sqlite3.pDisconnect list of any
** database connection that may have an entry in the p->pVTable list. */ ** database connection that may have an entry in the p->pVTable list.
assert( db==0 || */
sqlite3BtreeHoldsMutex(db->aDb[sqlite3SchemaToIndex(db, p->pSchema)].pBt) assert( db==0 || sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
);
while( pVTable ){ while( pVTable ){
sqlite3 *db2 = pVTable->db; sqlite3 *db2 = pVTable->db;
@@ -387,6 +386,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
Schema *pSchema = pTab->pSchema; Schema *pSchema = pTab->pSchema;
const char *zName = pTab->zName; const char *zName = pTab->zName;
int nName = sqlite3Strlen30(zName); int nName = sqlite3Strlen30(zName);
assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
if( pOld ){ if( pOld ){
db->mallocFailed = 1; db->mallocFailed = 1;