Index: src/btmutex.c ================================================================== --- src/btmutex.c +++ src/btmutex.c @@ -200,10 +200,18 @@ for(i=0; inDb; i++){ p = db->aDb[i].pBt; if( p ) sqlite3BtreeLeave(p); } } + +/* +** Return true if a particular Btree requires a lock. Return FALSE if +** no lock is ever required since it is not sharable. +*/ +int sqlite3BtreeSharable(Btree *p){ + return p->sharable; +} #ifndef NDEBUG /* ** Return true if the current thread holds the database connection ** mutex and all required BtShared mutexes. Index: src/btree.h ================================================================== --- src/btree.h +++ src/btree.h @@ -210,10 +210,11 @@ # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE + int sqlite3BtreeSharable(Btree*); void sqlite3BtreeLeave(Btree*); void sqlite3BtreeEnterCursor(BtCursor*); void sqlite3BtreeLeaveCursor(BtCursor*); void sqlite3BtreeLeaveAll(sqlite3*); #ifndef NDEBUG @@ -222,10 +223,11 @@ int sqlite3BtreeHoldsAllMutexes(sqlite3*); int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); #endif #else +# define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeLeave(X) # define sqlite3BtreeEnterCursor(X) # define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeLeaveAll(X) Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -4643,12 +4643,10 @@ #ifdef SQLITE_DEBUG for(iDb=0; iDbnDb; iDb++){ assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); } #endif - assert( p->btreeMask == ~(yDbMask)0 ); - iDb = pOp->p1; assert( iDb>=0 && iDbnDb ); assert( DbHasProperty(db, iDb, DB_SchemaLoaded) ); /* Used to be a conditional */ { Index: src/vdbeInt.h ================================================================== --- src/vdbeInt.h +++ src/vdbeInt.h @@ -301,10 +301,11 @@ u8 usesStmtJournal; /* True if uses a statement journal */ u8 readOnly; /* True for read-only statements */ u8 isPrepareV2; /* True if prepared with prepare_v2() */ int nChange; /* Number of db changes made since last reset */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ + yDbMask lockMask; /* Subset of btreeMask that requires a lock */ int iStatement; /* Statement number (or 0 if has not opened stmt) */ int aCounter[3]; /* Counters used by sqlite3_stmt_status() */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -158,11 +158,12 @@ pOp->p4type = P4_NOTUSED; p->expired = 0; if( op==OP_ParseSchema ){ /* Any program that uses the OP_ParseSchema opcode needs to lock ** all btrees. */ - p->btreeMask = ~(yDbMask)0; + int j; + for(j=0; jdb->nDb; j++) sqlite3VdbeUsesBtree(p, j); } #ifdef SQLITE_DEBUG pOp->zComment = 0; if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]); #endif @@ -956,10 +957,13 @@ */ void sqlite3VdbeUsesBtree(Vdbe *p, int i){ assert( i>=0 && idb->nDb && i<(int)sizeof(yDbMask)*8 ); assert( i<(int)sizeof(p->btreeMask)*8 ); p->btreeMask |= ((yDbMask)1)<db->aDb[i].pBt) ){ + p->lockMask |= ((yDbMask)1)<0 /* ** If SQLite is compiled to support shared-cache mode and to be threadsafe, @@ -983,15 +987,19 @@ ** be a problem. */ void sqlite3VdbeEnter(Vdbe *p){ int i; yDbMask mask; - sqlite3 *db = p->db; - Db *aDb = db->aDb; - int nDb = db->nDb; + sqlite3 *db; + Db *aDb; + int nDb; + if( p->lockMask==0 ) return; /* The common case */ + db = p->db; + aDb = db->aDb; + nDb = db->nDb; for(i=0, mask=1; ibtreeMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){ + if( i!=1 && (mask & p->lockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){ sqlite3BtreeEnter(aDb[i].pBt); } } } #endif @@ -1001,16 +1009,19 @@ ** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter(). */ void sqlite3VdbeLeave(Vdbe *p){ int i; yDbMask mask; - sqlite3 *db = p->db; - Db *aDb = db->aDb; - int nDb = db->nDb; - + sqlite3 *db; + Db *aDb; + int nDb; + if( p->lockMask==0 ) return; /* The common case */ + db = p->db; + aDb = db->aDb; + nDb = db->nDb; for(i=0, mask=1; ibtreeMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){ + if( i!=1 && (mask & p->lockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){ sqlite3BtreeLeave(aDb[i].pBt); } } } #endif