Changes to insure that lookaside memory allocations are never used to hold
schema content.
Ticket #3743. (CVS 6377)

FossilOrigin-Name: ea74d8dc62f5784089aa8ef098e97c505a79b176
diff --git a/src/alter.c b/src/alter.c
index 2a1b18e..d89b433 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that used to generate VDBE code
 ** that implements the ALTER TABLE command.
 **
-** $Id: alter.c,v 1.54 2009/02/28 10:47:42 danielk1977 Exp $
+** $Id: alter.c,v 1.55 2009/03/24 15:08:10 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -593,7 +593,7 @@
   if( !pNew ) goto exit_begin_add_column;
   pParse->pNewTable = pNew;
   pNew->nRef = 1;
-  pNew->db = db;
+  pNew->dbMem = pTab->dbMem;
   pNew->nCol = pTab->nCol;
   assert( pNew->nCol>0 );
   nAlloc = (((pNew->nCol-1)/8)*8)+8;
diff --git a/src/build.c b/src/build.c
index e9fcb27..f226334 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.525 2009/03/21 16:19:26 drh Exp $
+** $Id: build.c,v 1.526 2009/03/24 15:08:10 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -339,7 +339,7 @@
 ** Reclaim the memory used by an index
 */
 static void freeIndex(Index *p){
-  sqlite3 *db = p->pTable->db;
+  sqlite3 *db = p->pTable->dbMem;
   sqlite3DbFree(db, p->zColAff);
   sqlite3DbFree(db, p);
 }
@@ -467,7 +467,7 @@
 static void sqliteResetColumnNames(Table *pTable){
   int i;
   Column *pCol;
-  sqlite3 *db = pTable->db;
+  sqlite3 *db = pTable->dbMem;
   assert( pTable!=0 );
   if( (pCol = pTable->aCol)!=0 ){
     for(i=0; i<pTable->nCol; i++, pCol++){
@@ -498,7 +498,7 @@
   sqlite3 *db;
 
   if( pTable==0 ) return;
-  db = pTable->db;
+  db = pTable->dbMem;
 
   /* Do not delete the table until the reference count reaches zero. */
   pTable->nRef--;
@@ -836,7 +836,7 @@
   pTable->iPKey = -1;
   pTable->pSchema = db->aDb[iDb].pSchema;
   pTable->nRef = 1;
-  pTable->db = db;
+  pTable->dbMem = db->lookaside.bEnabled ? db : 0;
   if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable);
   pParse->pNewTable = pTable;
 
@@ -1855,9 +1855,11 @@
   assert( pTable->pSelect );
   pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
   if( pSel ){
+    int enableLookaside = db->lookaside.bEnabled;
     n = pParse->nTab;
     sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
     pTable->nCol = -1;
+    db->lookaside.bEnabled = 0;
 #ifndef SQLITE_OMIT_AUTHORIZATION
     xAuth = db->xAuth;
     db->xAuth = 0;
@@ -1866,6 +1868,7 @@
 #else
     pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
 #endif
+    db->lookaside.bEnabled = enableLookaside;
     pParse->nTab = n;
     if( pSelTab ){
       assert( pTable->aCol==0 );
diff --git a/src/callback.c b/src/callback.c
index ca41c08..c4a5280 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -13,7 +13,7 @@
 ** This file contains functions used to access the internal hash tables
 ** of user defined functions and collation sequences.
 **
-** $Id: callback.c,v 1.36 2009/03/05 04:20:32 shane Exp $
+** $Id: callback.c,v 1.37 2009/03/24 15:08:10 drh Exp $
 */
 
 #include "sqliteInt.h"
@@ -423,6 +423,7 @@
   sqlite3HashInit(&pSchema->tblHash, 0);
   for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
     Table *pTab = sqliteHashData(pElem);
+    assert( pTab->dbMem==0 );
     sqlite3DeleteTable(pTab);
   }
   sqlite3HashClear(&temp1);
diff --git a/src/expr.c b/src/expr.c
index edea922..01e151e 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.421 2009/03/23 04:33:32 danielk1977 Exp $
+** $Id: expr.c,v 1.422 2009/03/24 15:08:10 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -404,8 +404,22 @@
   pNew->iAgg = -1;
   pNew->span.z = (u8*)"";
   if( pToken ){
+    int c;
     assert( pToken->dyn==0 );
-    pNew->span = pNew->token = *pToken;
+    pNew->span = *pToken;
+ 
+    /* The pToken->z value is constant and must not change.  But
+    ** this expression might be passed to sqlite3DequoteExpr() which
+    ** will attempt to modify pNew->token.z.  Hence, if the token
+    ** is quoted, make a copy now so that DequoteExpr() will change
+    ** the copy rather than the original (read-only) text.
+    */
+    if( pToken->n>=2 
+         && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
+      sqlite3TokenCopy(db, &pNew->token, pToken);
+    }else{
+      pNew->token = *pToken;
+    }
   }else if( pLeft ){
     if( pRight ){
       if( pRight->span.dyn==0 && pLeft->span.dyn==0 ){
@@ -511,16 +525,15 @@
   assert( pToken );
   pNew = sqlite3DbMallocZero(db, sizeof(Expr) );
   if( pNew==0 ){
-    sqlite3ExprListDelete(db, pList); /* Avoid leaking memory when malloc fails */
+    sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
     return 0;
   }
   pNew->op = TK_FUNCTION;
   pNew->x.pList = pList;
   assert( !ExprHasProperty(pNew, EP_xIsSelect) );
   assert( pToken->dyn==0 );
-  pNew->token = *pToken;
-  pNew->span = pNew->token;
-
+  pNew->span = *pToken;
+  sqlite3TokenCopy(db, &pNew->token, pToken);
   sqlite3ExprSetHeight(pParse, pNew);
   return pNew;
 }
@@ -645,27 +658,10 @@
 ** If so, remove the quotation marks.
 */
 void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
-  if( ExprHasAnyProperty(p, EP_Dequoted) ){
-    return;
+  if( !ExprHasAnyProperty(p, EP_Dequoted) ){
+    ExprSetProperty(p, EP_Dequoted);
+    sqlite3Dequote((char*)p->token.z);
   }
-  ExprSetProperty(p, EP_Dequoted);
-
-  /* If p->token.dyn==0 and none of EP_Reduced, EP_TokenOnly, or
-  ** EP_SpanOnly are set, that means that the p->token.z string points
-  ** back to the original SQL statement text.  In that case, we need
-  ** to make a copy before modifying the string, otherwise we would
-  ** corrupt the original SQL statement text.
-  */
-  testcase( p->token.dyn==0 && ExprHasProperty(p, EP_Reduced) );
-  testcase( p->token.dyn==0 && ExprHasProperty(p, EP_TokenOnly) );
-  testcase( p->token.dyn==0 && ExprHasProperty(p, EP_SpanOnly) );
-  if( p->token.dyn==0
-   && !ExprHasAnyProperty(p, EP_Reduced|EP_TokenOnly|EP_SpanOnly) 
-  ){
-    sqlite3TokenCopy(db, &p->token, &p->token);
-  }
-
-  sqlite3Dequote((char*)p->token.z);
 }
 
 /*
@@ -876,7 +872,7 @@
 Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
   return exprDup(db, p, flags, 0);
 }
-void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
+void sqlite3TokenCopy(sqlite3 *db, Token *pTo, const Token *pFrom){
   if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z);
   if( pFrom->z ){
     pTo->n = pFrom->n;
diff --git a/src/malloc.c b/src/malloc.c
index a995e2c..92e5639 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -12,7 +12,7 @@
 **
 ** Memory allocation functions used throughout sqlite.
 **
-** $Id: malloc.c,v 1.60 2009/03/23 17:49:15 drh Exp $
+** $Id: malloc.c,v 1.61 2009/03/24 15:08:10 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -565,10 +565,10 @@
 */
 void *sqlite3DbMallocRaw(sqlite3 *db, int n){
   void *p;
+  assert( db==0 || sqlite3_mutex_held(db->mutex) );
 #ifndef SQLITE_OMIT_LOOKASIDE
   if( db ){
     LookasideSlot *pBuf;
-    assert( sqlite3_mutex_held(db->mutex) );
     if( db->mallocFailed ){
       return 0;
     }
@@ -600,6 +600,7 @@
 */
 void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
   void *pNew = 0;
+  assert( db!=0 );
   assert( sqlite3_mutex_held(db->mutex) );
   if( db->mallocFailed==0 ){
     if( p==0 ){
diff --git a/src/parse.y b/src/parse.y
index 63c68ac..1f14b41 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.271 2009/03/22 20:36:19 drh Exp $
+** @(#) $Id: parse.y,v 1.272 2009/03/24 15:08:10 drh Exp $
 */
 
 // All token codes are small integers with #defines that begin with "TK_"
@@ -133,9 +133,13 @@
 ///////////////////// The CREATE TABLE statement ////////////////////////////
 //
 cmd ::= create_table create_table_args.
-create_table ::= CREATE temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
+create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
    sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
 }
+createkw(A) ::= CREATE(X).  {
+  pParse->db->lookaside.bEnabled = 0;
+  A = X;
+}
 %type ifnotexists {int}
 ifnotexists(A) ::= .              {A = 0;}
 ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
@@ -365,7 +369,7 @@
 ///////////////////// The CREATE VIEW statement /////////////////////////////
 //
 %ifndef SQLITE_OMIT_VIEW
-cmd ::= CREATE(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
+cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
   sqlite3CreateView(pParse, &X, &Y, &Z, S, T, E);
 }
 cmd ::= DROP VIEW ifexists(E) fullname(X). {
@@ -941,7 +945,7 @@
 
 ///////////////////////////// The CREATE INDEX command ///////////////////////
 //
-cmd ::= CREATE(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
+cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
         ON nm(Y) LP idxlist(Z) RP(E). {
   sqlite3CreateIndex(pParse, &X, &D, 
                      sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
@@ -1024,7 +1028,7 @@
 
 %ifndef SQLITE_OMIT_TRIGGER
 
-cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
+cmd ::= createkw trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
   Token all;
   all.z = A.z;
   all.n = (int)(Z.z - A.z) + Z.n;
@@ -1170,6 +1174,7 @@
   sqlite3AlterFinishAddColumn(pParse, &Y);
 }
 add_column_fullname ::= fullname(X). {
+  pParse->db->lookaside.bEnabled = 0;
   sqlite3AlterBeginAddColumn(pParse, X);
 }
 kwcolumn_opt ::= .
@@ -1180,7 +1185,7 @@
 %ifndef SQLITE_OMIT_VIRTUALTABLE
 cmd ::= create_vtab.                       {sqlite3VtabFinishParse(pParse,0);}
 cmd ::= create_vtab LP vtabarglist RP(X).  {sqlite3VtabFinishParse(pParse,&X);}
-create_vtab ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). {
+create_vtab ::= createkw VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). {
     sqlite3VtabBeginParse(pParse, &X, &Y, &Z);
 }
 vtabarglist ::= vtabarg.
diff --git a/src/prepare.c b/src/prepare.c
index 1f58538..dc57695 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -13,7 +13,7 @@
 ** interface, and routines that contribute to loading the database schema
 ** from disk.
 **
-** $Id: prepare.c,v 1.113 2009/03/24 04:46:08 danielk1977 Exp $
+** $Id: prepare.c,v 1.114 2009/03/24 15:08:10 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -74,33 +74,14 @@
     ** But because db->init.busy is set to 1, no VDBE code is generated
     ** or executed.  All the parser does is build the internal data
     ** structures that describe the table, index, or view.
-    **
-    ** While the CREATE XXX statement is being processed, the lookaside 
-    ** buffer is disabled. One reason for this is that when running in
-    ** shared cache mode, the objects allocated for the in-memory schema
-    ** might be freed from within a call made on a different database
-    ** connection to db (e.g. if the second connection executes a DROP
-    ** TABLE statement). If the objects that make up the Table structure
-    ** are allocated from within db's lookaside buffer, then db->mutex
-    ** would have to be obtained before they could be freed. This would
-    ** open the door to deadlock in a multi-threaded application.
-    **
-    ** Another reason to disable the lookaside buffer is that lookaside
-    ** gives the greatest performance boost when it is used to allocate
-    ** and free small transient objects. The schema objects, which tend
-    ** to have long lifetimes, are better allocated from the heap.
     */
     char *zErr;
     int rc;
-    u8 lookasideEnabled;
     assert( db->init.busy );
     db->init.iDb = iDb;
     db->init.newTnum = atoi(argv[1]);
-    lookasideEnabled = db->lookaside.bEnabled;
-    db->lookaside.bEnabled = 0;
     rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
     db->init.iDb = 0;
-    db->lookaside.bEnabled = lookasideEnabled;
     assert( rc!=SQLITE_OK || zErr==0 );
     if( SQLITE_OK!=rc ){
       pData->rc = rc;
diff --git a/src/select.c b/src/select.c
index 6c5c232..86c0c8c 100644
--- a/src/select.c
+++ b/src/select.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.504 2009/02/25 08:56:47 danielk1977 Exp $
+** $Id: select.c,v 1.505 2009/03/24 15:08:10 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -1284,7 +1284,7 @@
   if( pTab==0 ){
     return 0;
   }
-  pTab->db = db;
+  pTab->dbMem = db->lookaside.bEnabled ? db : 0;
   pTab->nRef = 1;
   pTab->zName = 0;
   selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
@@ -3080,7 +3080,7 @@
       sqlite3WalkSelect(pWalker, pSel);
       pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
       if( pTab==0 ) return WRC_Abort;
-      pTab->db = db;
+      pTab->dbMem = db->lookaside.bEnabled ? db : 0;
       pTab->nRef = 1;
       pTab->zName = sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pTab);
       while( pSel->pPrior ){ pSel = pSel->pPrior; }
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 67836d1..bb79aaa 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.845 2009/03/23 04:33:33 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.846 2009/03/24 15:08:10 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -686,10 +686,17 @@
 ** lookaside malloc subsystem.  Each available memory allocation in
 ** the lookaside subsystem is stored on a linked list of LookasideSlot
 ** objects.
+**
+** Lookaside allocations are only allowed for objects that are associated
+** with a particular database connection.  Hence, schema information cannot
+** be stored in lookaside because in shared cache mode the schema information
+** is shared by multiple database connections.  Therefore, while parsing
+** schema information, the Lookaside.bEnabled flag is cleared so that
+** lookaside allocations are not used to construct the schema objects.
 */
 struct Lookaside {
   u16 sz;                 /* Size of each buffer in bytes */
-  u8 bEnabled;            /* True if use lookaside.  False to ignore it */
+  u8 bEnabled;            /* False to disable new lookaside allocations */
   u8 bMalloced;           /* True if pStart obtained from sqlite3_malloc() */
   int nOut;               /* Number of buffers currently checked out */
   int mxOut;              /* Highwater mark for nOut */
@@ -1105,7 +1112,7 @@
 ** of a SELECT statement.
 */
 struct Table {
-  sqlite3 *db;         /* Associated database connection.  Might be NULL. */
+  sqlite3 *dbMem;      /* DB connection used for lookaside allocations. */
   char *zName;         /* Name of the table or view */
   int iPKey;           /* If not negative, use aCol[iPKey] as the primary key */
   int nCol;            /* Number of columns in this table */
@@ -2466,7 +2473,7 @@
 int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
 void sqlite3BeginWriteOperation(Parse*, int, int);
 Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
-void sqlite3TokenCopy(sqlite3*,Token*, Token*);
+void sqlite3TokenCopy(sqlite3*,Token*,const Token*);
 ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
 SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
 IdList *sqlite3IdListDup(sqlite3*,IdList*);
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index a429662..8959e60 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -12,7 +12,7 @@
 ** A TCL Interface to SQLite.  Append this file to sqlite3.c and
 ** compile the whole thing to build a TCL-enabled version of SQLite.
 **
-** $Id: tclsqlite.c,v 1.238 2009/03/16 13:19:36 danielk1977 Exp $
+** $Id: tclsqlite.c,v 1.239 2009/03/24 15:08:10 drh Exp $
 */
 #include "tcl.h"
 #include <errno.h>
@@ -2593,8 +2593,21 @@
   int i;
   const char *zFile;
   const char *zVfs = 0;
-  int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
+  int flags;
   Tcl_DString translatedFilename;
+
+  /* In normal use, each TCL interpreter runs in a single thread.  So
+  ** by default, we can turn of mutexing on SQLite database connections.
+  ** However, for testing purposes it is useful to have mutexes turned
+  ** on.  So, by default, mutexes default off.  But if compiled with
+  ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
+  */
+#ifdef SQLITE_TCL_DEFAULT_FULLMUTEX
+  flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
+#else
+  flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
+#endif
+
   if( objc==2 ){
     zArg = Tcl_GetStringFromObj(objv[1], 0);
     if( strcmp(zArg,"-version")==0 ){
diff --git a/src/tokenize.c b/src/tokenize.c
index afc3dd6..60313ae 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -15,7 +15,7 @@
 ** individual tokens and sends those tokens one-by-one over to the
 ** parser for analysis.
 **
-** $Id: tokenize.c,v 1.153 2009/01/20 16:53:41 danielk1977 Exp $
+** $Id: tokenize.c,v 1.154 2009/03/24 15:08:10 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdlib.h>
@@ -381,14 +381,17 @@
 ** error message.
 */
 int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
-  int nErr = 0;
-  int i;
-  void *pEngine;
-  int tokenType;
-  int lastTokenParsed = -1;
-  sqlite3 *db = pParse->db;
-  int mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
+  int nErr = 0;                   /* Number of errors encountered */
+  int i;                          /* Loop counter */
+  void *pEngine;                  /* The LEMON-generated LALR(1) parser */
+  int tokenType;                  /* type of the next token */
+  int lastTokenParsed = -1;       /* type of the previous token */
+  int enableLookaside;            /* Saved value of db->lookaside.bEnabled */
+  sqlite3 *db = pParse->db;       /* The database connection */
+  int mxSqlLen;                   /* Max length of an SQL string */
 
+
+  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
   if( db->activeVdbeCnt==0 ){
     db->u1.isInterrupted = 0;
   }
@@ -408,6 +411,8 @@
   assert( pParse->nVarExpr==0 );
   assert( pParse->nVarExprAlloc==0 );
   assert( pParse->apVarExpr==0 );
+  enableLookaside = db->lookaside.bEnabled;
+  if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
   while( !db->mallocFailed && zSql[i]!=0 ){
     assert( i>=0 );
     pParse->sLastToken.z = (u8*)&zSql[i];
@@ -462,6 +467,7 @@
   );
 #endif /* YYDEBUG */
   sqlite3ParserFree(pEngine, sqlite3_free);
+  db->lookaside.bEnabled = enableLookaside;
   if( db->mallocFailed ){
     pParse->rc = SQLITE_NOMEM;
   }
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index 8284467..de051e1 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -12,7 +12,7 @@
 **
 ** This file contains code used to implement incremental BLOB I/O.
 **
-** $Id: vdbeblob.c,v 1.30 2009/03/19 18:51:07 danielk1977 Exp $
+** $Id: vdbeblob.c,v 1.31 2009/03/24 15:08:10 drh Exp $
 */
 
 #include "sqliteInt.h"
@@ -264,9 +264,13 @@
 int sqlite3_blob_close(sqlite3_blob *pBlob){
   Incrblob *p = (Incrblob *)pBlob;
   int rc;
+  sqlite3 *db;
 
+  db = p->db;
+  sqlite3_mutex_enter(db->mutex);
   rc = sqlite3_finalize(p->pStmt);
-  sqlite3DbFree(p->db, p);
+  sqlite3DbFree(db, p);
+  sqlite3_mutex_leave(db->mutex);
   return rc;
 }
 
diff --git a/src/vtab.c b/src/vtab.c
index a5865d8..bfa88e9 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to help implement virtual tables.
 **
-** $Id: vtab.c,v 1.83 2009/03/19 18:51:07 danielk1977 Exp $
+** $Id: vtab.c,v 1.84 2009/03/24 15:08:10 drh Exp $
 */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 #include "sqliteInt.h"
@@ -118,7 +118,8 @@
 */
 void sqlite3VtabClear(Table *p){
   sqlite3_vtab *pVtab = p->pVtab;
-  sqlite3 *db = p->db;
+  Schema *pSchema = p->pSchema;
+  sqlite3 *db = pSchema ? pSchema->db : 0;
   if( pVtab ){
     assert( p->pMod && p->pMod->pModule );
     sqlite3VtabUnlock(db, pVtab);