Use a global variable protected by a mutex instead of thread-specific-data to record malloc() failures. (CVS 2972)

FossilOrigin-Name: ac090f2ab3b5a792c2fdf897e10060f263e0d408
diff --git a/src/alter.c b/src/alter.c
index 378c128..b33b0e7 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.17 2006/01/17 13:21:40 danielk1977 Exp $
+** $Id: alter.c,v 1.18 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -267,7 +267,7 @@
   char *zWhere = 0;         /* Where clause to locate temp triggers */
 #endif
   
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_rename_table;
+  if( sqlite3MallocFailed() ) goto exit_rename_table;
   assert( pSrc->nSrc==1 );
 
   pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
@@ -501,7 +501,7 @@
 
   /* Look up the table being altered. */
   assert( pParse->pNewTable==0 );
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_begin_add_column;
+  if( sqlite3MallocFailed() ) goto exit_begin_add_column;
   pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
   if( !pTab ) goto exit_begin_add_column;
 
diff --git a/src/attach.c b/src/attach.c
index 65628f5..26fc531 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the ATTACH and DETACH commands.
 **
-** $Id: attach.c,v 1.47 2006/01/17 13:21:40 danielk1977 Exp $
+** $Id: attach.c,v 1.48 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -272,7 +272,7 @@
   sqlite3* db = pParse->db;
 
 #ifndef SQLITE_OMIT_AUTHORIZATION
-  assert( sqlite3ThreadDataReadOnly()->mallocFailed || pAuthArg );
+  assert( sqlite3MallocFailed() || pAuthArg );
   if( pAuthArg ){
     char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span);
     if( !zAuthArg ){
@@ -303,7 +303,7 @@
   sqlite3ExprCode(pParse, pDbname);
   sqlite3ExprCode(pParse, pKey);
 
-  assert(v || sqlite3ThreadDataReadOnly()->mallocFailed);
+  assert( v || sqlite3MallocFailed() );
   if( v ){
     sqlite3VdbeAddOp(v, OP_Function, 0, nFunc);
     pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
diff --git a/src/build.c b/src/build.c
index f54c8d9..56be58d 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.381 2006/01/16 15:14:28 danielk1977 Exp $
+** $Id: build.c,v 1.382 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -130,7 +130,7 @@
   sqlite3 *db;
   Vdbe *v;
 
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ) return;
+  if( sqlite3MallocFailed() ) return;
   if( pParse->nested ) return;
   if( !pParse->pVdbe ){
     if( pParse->rc==SQLITE_OK && pParse->nErr ){
@@ -1364,8 +1364,7 @@
   sqlite3 *db = pParse->db;
   int iDb;
 
-  if( (pEnd==0 && pSelect==0) || 
-      pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) {
+  if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3MallocFailed() ) {
     return;
   }
   p = pParse->pNewTable;
@@ -1607,7 +1606,7 @@
   */
   p->pSelect = sqlite3SelectDup(pSelect);
   sqlite3SelectDelete(pSelect);
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     return;
   }
   if( !pParse->db->init.busy ){
@@ -1849,7 +1848,7 @@
   sqlite3 *db = pParse->db;
   int iDb;
 
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( pParse->nErr || sqlite3MallocFailed() ){
     goto exit_drop_table;
   }
   assert( pName->nSrc==1 );
@@ -2210,7 +2209,7 @@
   int nExtra = 0;
   char *zExtra;
 
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( pParse->nErr || sqlite3MallocFailed() ){
     goto exit_create_index;
   }
 
@@ -2364,7 +2363,7 @@
       nName + 1 +                  /* Index.zName      */
       nExtra                       /* Collation sequence names */
   );
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_create_index;
+  if( sqlite3MallocFailed() ) goto exit_create_index;
   pIndex->aiColumn = (int *)(&pIndex[1]);
   pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]);
   pIndex->azColl = (char **)(&pIndex->aiRowEst[nCol+1]);
@@ -2651,7 +2650,7 @@
   sqlite3 *db = pParse->db;
   int iDb;
 
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( pParse->nErr || sqlite3MallocFailed() ){
     goto exit_drop_index;
   }
   assert( pName->nSrc==1 );
@@ -2860,7 +2859,7 @@
 void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
   int i;
   struct SrcList_item *pItem;
-  assert(pList || sqlite3ThreadDataReadOnly()->mallocFailed);
+  assert(pList || sqlite3MallocFailed() );
   if( pList ){
     for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
       if( pItem->iCursor>=0 ) break;
@@ -2909,7 +2908,7 @@
   int i;
 
   if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return;
+  if( pParse->nErr || sqlite3MallocFailed() ) return;
   if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
 
   v = sqlite3GetVdbe(pParse);
@@ -2930,7 +2929,7 @@
   Vdbe *v;
 
   if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return;
+  if( pParse->nErr || sqlite3MallocFailed() ) return;
   if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
 
   v = sqlite3GetVdbe(pParse);
@@ -2947,7 +2946,7 @@
   Vdbe *v;
 
   if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return;
+  if( pParse->nErr || sqlite3MallocFailed() ) return;
   if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
 
   v = sqlite3GetVdbe(pParse);
diff --git a/src/callback.c b/src/callback.c
index c63b588..5847b66 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.11 2006/01/11 21:41:22 drh Exp $
+** $Id: callback.c,v 1.12 2006/01/18 16:51:35 danielk1977 Exp $
 */
 
 #include "sqliteInt.h"
@@ -179,7 +179,7 @@
       ** to the hash table).
       */
       assert( !pDel ||
-              (sqlite3ThreadDataReadOnly()->mallocFailed && pDel==pColl) );
+              (sqlite3MallocFailed() && pDel==pColl) );
       sqliteFree(pDel);
     }
   }
diff --git a/src/delete.c b/src/delete.c
index 1c85c47..c742bc4 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** in order to generate code for DELETE FROM statements.
 **
-** $Id: delete.c,v 1.118 2006/01/11 21:41:22 drh Exp $
+** $Id: delete.c,v 1.119 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -108,7 +108,7 @@
 #endif
 
   sContext.pParse = 0;
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( pParse->nErr || sqlite3MallocFailed() ){
     goto delete_from_cleanup;
   }
   db = pParse->db;
diff --git a/src/expr.c b/src/expr.c
index e8a89f4..724cee9 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.249 2006/01/13 06:33:24 danielk1977 Exp $
+** $Id: expr.c,v 1.250 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -263,7 +263,7 @@
 void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
   assert( pRight!=0 );
   assert( pLeft!=0 );
-  if( !sqlite3ThreadDataReadOnly()->mallocFailed && pRight->z && pLeft->z ){
+  if( !sqlite3MallocFailed() && pRight->z && pLeft->z ){
     assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 );
     if( pLeft->dyn==0 && pRight->dyn==0 ){
       pExpr->span.z = pLeft->z;
@@ -358,7 +358,7 @@
         sqliteReallocOrFree((void**)&pParse->apVarExpr,
                        pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
       }
-      if( !sqlite3ThreadDataReadOnly()->mallocFailed ){
+      if( !sqlite3MallocFailed() ){
         assert( pParse->apVarExpr!=0 );
         pParse->apVarExpr[pParse->nVarExpr++] = pExpr;
       }
@@ -463,7 +463,7 @@
     }
     assert( pNewExpr==0 || pNewExpr->span.z!=0 
             || pOldExpr->span.z==0
-            || sqlite3ThreadDataReadOnly()->mallocFailed );
+            || sqlite3MallocFailed() );
     pItem->zName = sqliteStrDup(pOldItem->zName);
     pItem->sortOrder = pOldItem->sortOrder;
     pItem->isAgg = pOldItem->isAgg;
@@ -832,7 +832,7 @@
   zDb = sqlite3NameFromToken(pDbToken);
   zTab = sqlite3NameFromToken(pTableToken);
   zCol = sqlite3NameFromToken(pColumnToken);
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     goto lookupname_end;
   }
 
@@ -1309,7 +1309,7 @@
     int mem = pParse->nMem++;
     sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
     testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
-    assert( testAddr>0 || sqlite3ThreadDataReadOnly()->mallocFailed );
+    assert( testAddr>0 || sqlite3MallocFailed() );
     sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
   }
 
diff --git a/src/insert.c b/src/insert.c
index e249686..d38e24f 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.157 2006/01/11 21:41:22 drh Exp $
+** $Id: insert.c,v 1.158 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -225,7 +225,7 @@
   int counterRowid;     /* Memory cell holding rowid of autoinc counter */
 #endif
 
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( pParse->nErr || sqlite3MallocFailed() ){
     goto insert_cleanup;
   }
   db = pParse->db;
@@ -333,7 +333,7 @@
 
     /* Resolve the expressions in the SELECT statement and execute it. */
     rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0);
-    if( rc || pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){
+    if( rc || pParse->nErr || sqlite3MallocFailed() ){
       goto insert_cleanup;
     }
 
diff --git a/src/main.c b/src/main.c
index c2822a7..504e1ff 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.327 2006/01/18 15:25:17 danielk1977 Exp $
+** $Id: main.c,v 1.328 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -450,7 +450,7 @@
     if( db->activeVdbeCnt ){
       sqlite3Error(db, SQLITE_BUSY, 
         "Unable to delete/modify user-function due to active statements");
-      assert( !sqlite3ThreadDataReadOnly()->mallocFailed );
+      assert( !sqlite3MallocFailed() );
       return SQLITE_BUSY;
     }else{
       sqlite3ExpirePreparedStatements(db);
@@ -482,7 +482,7 @@
   void (*xFinal)(sqlite3_context*)
 ){
   int rc;
-  assert( !sqlite3ThreadDataReadOnly()->mallocFailed );
+  assert( !sqlite3MallocFailed() );
   rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
 
   return sqlite3ApiExit(db, rc);
@@ -501,7 +501,7 @@
 ){
   int rc;
   char *zFunc8;
-  assert( !sqlite3ThreadDataReadOnly()->mallocFailed );
+  assert( !sqlite3MallocFailed() );
 
   zFunc8 = sqlite3utf16to8(zFunctionName, -1);
   rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
@@ -666,7 +666,7 @@
 */
 const char *sqlite3_errmsg(sqlite3 *db){
   const char *z;
-  if( !db || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( !db || sqlite3MallocFailed() ){
     return sqlite3ErrStr(SQLITE_NOMEM);
   }
   if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
@@ -705,7 +705,7 @@
   };
 
   const void *z;
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
   }
   if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
@@ -727,7 +727,7 @@
 ** passed to this function, we assume a malloc() failed during sqlite3_open().
 */
 int sqlite3_errcode(sqlite3 *db){
-  if( !db || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( !db || sqlite3MallocFailed() ){
     return SQLITE_NOMEM;
   }
   if( sqlite3SafetyCheck(db) ){
@@ -803,7 +803,7 @@
   int rc;
   CollSeq *pColl;
 
-  assert( !sqlite3ThreadDataReadOnly()->mallocFailed );
+  assert( !sqlite3MallocFailed() );
 
   /* Allocate the sqlite data structure */
   db = sqliteMalloc( sizeof(sqlite3) );
@@ -825,7 +825,7 @@
       createCollation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
       (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0 
   ){
-    assert( sqlite3ThreadDataReadOnly()->mallocFailed );
+    assert( sqlite3MallocFailed() );
     db->magic = SQLITE_MAGIC_CLOSED;
     goto opendb_out;
   }
@@ -870,7 +870,7 @@
   ** database schema yet. This is delayed until the first time the database
   ** is accessed.
   */
-  if( !sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( !sqlite3MallocFailed() ){
     sqlite3RegisterBuiltinFunctions(db);
     sqlite3Error(db, SQLITE_OK, 0);
   }
@@ -978,7 +978,7 @@
   int(*xCompare)(void*,int,const void*,int,const void*)
 ){
   int rc;
-  assert( !sqlite3ThreadDataReadOnly()->mallocFailed );
+  assert( !sqlite3MallocFailed() );
   rc = createCollation(db, zName, enc, pCtx, xCompare);
   return sqlite3ApiExit(db, rc);
 }
@@ -996,7 +996,7 @@
 ){
   int rc = SQLITE_OK;
   char *zName8; 
-  assert( !sqlite3ThreadDataReadOnly()->mallocFailed );
+  assert( !sqlite3MallocFailed() );
   zName8 = sqlite3utf16to8(zName, -1);
   if( zName8 ){
     rc = createCollation(db, zName8, enc, pCtx, xCompare);
diff --git a/src/os_unix.c b/src/os_unix.c
index 5257bfd..eb57067 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -1739,20 +1739,6 @@
 # define TSD_COUNTER(N)  /* no-op */
 #endif
 
-#if 0 && defined(SQLITE_MEMDEBUG)
-static void *mallocThreadData(size_t nBytes){
-  if( sqlite3_iMallocFail>=0 ){
-    sqlite3_iMallocFail--;
-    if( sqlite3_iMallocFail==0 ){
-      return 0;
-    }
-  }
-  return sqlite3OsMalloc(nBytes);
-}
-#else
-  #define mallocThreadData(x) sqlite3OsMalloc(x)
-#endif
-
 /*
 ** If called with allocateFlag>0, then return a pointer to thread
 ** specific data for the current thread.  Allocate and zero the
@@ -1791,7 +1777,7 @@
   pTsd = pthread_getspecific(key);
   if( allocateFlag>0 ){
     if( pTsd==0 ){
-      pTsd = mallocThreadData(sizeof(zeroData));
+      pTsd = sqlite3OsMalloc(sizeof(zeroData));
       if( pTsd ){
         *pTsd = zeroData;
         pthread_setspecific(key, pTsd);
@@ -1799,7 +1785,7 @@
       }
     }
   }else if( pTsd!=0 && allocateFlag<0 
-            && memcmp(pTsd, &zeroData, THREADDATASIZE)==0 ){
+            && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
     sqlite3OsFree(pTsd);
     pthread_setspecific(key, 0);
     TSD_COUNTER(-1);
@@ -1810,14 +1796,14 @@
   static ThreadData *pTsd = 0;
   if( allocateFlag>0 ){
     if( pTsd==0 ){
-      pTsd = mallocThreadData( sizeof(zeroData) );
+      pTsd = sqlite3OsMalloc( sizeof(zeroData) );
       if( pTsd ){
         *pTsd = zeroData;
         TSD_COUNTER(+1);
       }
     }
   }else if( pTsd!=0 && allocateFlag<0
-            && memcmp(pTsd, &zeroData, THREADDATASIZE)==0 ){
+            && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
     sqlite3OsFree(pTsd);
     TSD_COUNTER(-1);
     pTsd = 0;
diff --git a/src/os_win.c b/src/os_win.c
index 2d2341a..ae0c254 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -1212,7 +1212,7 @@
       }
     }
   }else if( pTsd!=0 && allocateFlag<0 
-              && memcmp(pTsd, &zeroData, THREADDATASIZE)==0 ){
+              && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
     sqlite3OsFree(pTsd);
     TlsSetValue(key, 0);
     TSD_COUNTER_DECR;
diff --git a/src/pager.c b/src/pager.c
index 0425a44..de39123 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.242 2006/01/18 15:25:17 danielk1977 Exp $
+** @(#) $Id: pager.c,v 1.243 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -1593,7 +1593,7 @@
   ** structure was never allocated. 
   */
   *ppPager = 0;
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     return SQLITE_NOMEM;
   }
   memset(&fd, 0, sizeof(fd));
diff --git a/src/prepare.c b/src/prepare.c
index cd82f1a..b607783 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.25 2006/01/18 15:25:18 danielk1977 Exp $
+** $Id: prepare.c,v 1.26 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -24,7 +24,7 @@
 ** that the database is corrupt.
 */
 static void corruptSchema(InitData *pData, const char *zExtra){
-  if( !sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( !sqlite3MallocFailed() ){
     sqlite3SetString(pData->pzErrMsg, "malformed database schema",
        zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
   }
@@ -49,7 +49,7 @@
   sqlite3 *db = pData->db;
   int iDb;
 
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     return SQLITE_NOMEM;
   }
 
@@ -76,9 +76,9 @@
     db->init.iDb = 0;
     if( SQLITE_OK!=rc ){
       if( rc==SQLITE_NOMEM ){
-          sqlite3ThreadData()->mallocFailed = 1;
+        sqlite3FailedMalloc();
       }else{
-          corruptSchema(pData, zErr);
+        corruptSchema(pData, zErr);
       }
       sqlite3_free(zErr);
       return rc;
@@ -303,8 +303,8 @@
 #endif
     sqlite3BtreeCloseCursor(curMain);
   }
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
-    sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
+  if( sqlite3MallocFailed() ){
+    /* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */
     rc = SQLITE_NOMEM;
     sqlite3ResetInternalSchema(db, 0);
   }
@@ -496,7 +496,7 @@
   int i;
 
   /* Assert that malloc() has not failed */
-  assert( !sqlite3ThreadDataReadOnly()->mallocFailed );
+  assert( !sqlite3MallocFailed() );
 
   assert( ppStmt );
   *ppStmt = 0;
@@ -523,7 +523,7 @@
   sParse.pTsd->nRef++;
   sqlite3RunParser(&sParse, zSql, &zErrMsg);
 
-  if( sParse.pTsd->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     sParse.rc = SQLITE_NOMEM;
   }
   if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
diff --git a/src/select.c b/src/select.c
index 4bfe81d..4a50c65 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.294 2006/01/13 06:33:24 danielk1977 Exp $
+** $Id: select.c,v 1.295 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -872,8 +872,7 @@
 #endif
 
   assert( v!=0 );
-  if( pParse->colNamesSet || v==0
-     || sqlite3ThreadDataReadOnly()->mallocFailed ) return;
+  if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return;
   pParse->colNamesSet = 1;
   fullNames = (db->flags & SQLITE_FullColNames)!=0;
   shortNames = (db->flags & SQLITE_ShortColNames)!=0;
@@ -1002,7 +1001,7 @@
       zName = sqlite3MPrintf("column%d", i+1);
     }
     sqlite3Dequote(zName);
-    if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+    if( sqlite3MallocFailed() ){
       sqliteFree(zName);
       sqlite3DeleteTable(0, pTab);
       return 0;
@@ -1074,7 +1073,7 @@
   Table *pTab;
   struct SrcList_item *pFrom;
 
-  if( p==0 || p->pSrc==0 || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( p==0 || p->pSrc==0 || sqlite3MallocFailed() ){
     return 1;
   }
   pTabList = p->pSrc;
@@ -2693,7 +2692,7 @@
   AggInfo sAggInfo;      /* Information used by aggregate queries */
   int iEnd;              /* Address of the end of the query */
 
-  if( p==0 || sqlite3ThreadDataReadOnly()->mallocFailed || pParse->nErr ){
+  if( p==0 || sqlite3MallocFailed() || pParse->nErr ){
     return 1;
   }
   if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
@@ -2949,7 +2948,7 @@
         goto select_end;
       }
     }
-    if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto select_end;
+    if( sqlite3MallocFailed() ) goto select_end;
 
     /* Processing for aggregates with GROUP BY is very different and
     ** much more complex tha aggregates without a GROUP BY.
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 4bb2c14..45854dc 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.473 2006/01/18 15:25:18 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.474 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -261,9 +261,16 @@
 extern int sqlite3_nFree;        /* Number of sqliteFree() calls */
 extern int sqlite3_iMallocFail;  /* Fail sqliteMalloc() after this many calls */
 extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
-#define ENTER_MALLOC (\
-  sqlite3ThreadData()->zFile = __FILE__, sqlite3ThreadData()->iLine = __LINE__ \
-)
+
+
+extern void *sqlite3_pFirst;         /* Pointer to linked list of allocations */
+extern int sqlite3_nMaxAlloc;        /* High water mark of ThreadData.nAlloc */
+extern int sqlite3_mallocDisallowed; /* assert() in sqlite3Malloc() if set */
+extern int sqlite3_isFail;           /* True if all malloc calls should fail */
+extern const char *sqlite3_zFile;    /* Filename to associate debug info with */
+extern int sqlite3_iLine;            /* Line number for debug info */
+
+#define ENTER_MALLOC (sqlite3_zFile = __FILE__, sqlite3_iLine = __LINE__)
 #define sqliteMalloc(x)          (ENTER_MALLOC, sqlite3Malloc(x))
 #define sqliteMallocRaw(x)       (ENTER_MALLOC, sqlite3MallocRaw(x))
 #define sqliteRealloc(x,y)       (ENTER_MALLOC, sqlite3Realloc(x,y))
@@ -295,7 +302,6 @@
 ** is deallocated.
 */
 struct ThreadData {
-  int mallocFailed;        /* True after a malloc() has failed */
   int nRef;                /* Number of users */
 
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
@@ -308,34 +314,9 @@
   u8 useSharedData;        /* True if shared pagers and schemas are enabled */
   BtShared *pBtree;        /* Linked list of all currently open BTrees */
 #endif
-
-#ifdef SQLITE_MEMDEBUG
-  void *pFirst;            /* Pointer to linked list of allocations */
-  int nMaxAlloc;           /* High water mark of ThreadData.nAlloc */
-  int mallocDisallowed;    /* assert() in sqlite3Malloc() if set */
-  int isFail;              /* True if all malloc() calls should fail */
-  const char *zFile;       /* Filename to associate debugging info with */
-  int iLine;               /* Line number to associate debugging info with */
-#endif
 };
 
 /*
-** The THREADDATASIZE macro is used by the system that automatically 
-** deallocates ThreadData structures. If the first THREADDATASIZE bytes
-** of a ThreadData structure are all zero, then the structure is eligible
-** for deallocation.
-**
-** Usually, THREADDATASIZE is set to the size of the structure. However
-** if SQLITE_MEMDEBUG is defined, all variables declared after the 
-** ThreadData.pFirst variable are excluded.
-*/
-#ifdef SQLITE_MEMDEBUG
-  #define THREADDATASIZE (int)(&(((ThreadData *)0)->nMaxAlloc))
-#else
-  #define THREADDATASIZE sizeof(ThreadData)
-#endif
-
-/*
 ** Name of the master database table.  The master database table
 ** is a special table that holds the names and attributes of all
 ** user tables and indices.
@@ -1766,6 +1747,8 @@
   void (*)(sqlite3_context*,int,sqlite3_value **),
   void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*));
 int sqlite3ApiExit(sqlite3 *db, int);
+int sqlite3MallocFailed();
+void sqlite3FailedMalloc();
 
 #ifndef SQLITE_OMIT_SHARED_CACHE
   void sqlite3TableLock(Parse *, int, int, u8, const char *);
diff --git a/src/test1.c b/src/test1.c
index ba2467f..018b173 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.195 2006/01/18 05:51:58 danielk1977 Exp $
+** $Id: test1.c,v 1.196 2006/01/18 16:51:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -834,7 +834,8 @@
 ** first failure will continue to fail on every call.  If REPEAT-INTERVAL is
 ** 2 then every other malloc will fail.  And so forth.
 **
-** Turn off this mechanism and reset the sqlite3ThreadData()->mallocFailed variable is N==0.
+** Turn off this mechanism and reset the sqlite3ThreadData()->mallocFailed 
+** variable if N==0.
 */
 #ifdef SQLITE_MEMDEBUG
 static int sqlite_malloc_fail(
@@ -915,9 +916,9 @@
     if( 0==strcmp(zArg, "-bytes") ){
       Tcl_SetObjResult(interp, Tcl_NewIntObj(pTd->nAlloc));
     }else if( 0==strcmp(zArg, "-maxbytes") ){
-      Tcl_SetObjResult(interp, Tcl_NewWideIntObj(pTd->nMaxAlloc));
+      Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_nMaxAlloc));
     }else if( 0==strcmp(zArg, "-clearmaxbytes") ){
-      pTd->nMaxAlloc = pTd->nAlloc;
+      sqlite3_nMaxAlloc = pTd->nAlloc;
     }else{
       Tcl_AppendResult(interp, "bad option \"", zArg, 
         "\": must be -bytes, -maxbytes or -clearmaxbytes", 0
@@ -3031,12 +3032,6 @@
   int objc,
   Tcl_Obj *CONST objv[]
 ){
-#if defined(SQLITE_MEMDEBUG)
-  ThreadData *pTd = sqlite3ThreadData();
-  pTd->nMaxAlloc = 0;
-  pTd->zFile = 0;
-  pTd->iLine = 0;
-#endif
   return TCL_OK;
 }
 
diff --git a/src/tokenize.c b/src/tokenize.c
index 86e526a..339979d 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.114 2006/01/12 12:43:36 drh Exp $
+** $Id: tokenize.c,v 1.115 2006/01/18 16:51:36 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -359,7 +359,7 @@
   assert( pParse->nVarExprAlloc==0 );
   assert( pParse->apVarExpr==0 );
   pParse->zTail = pParse->zSql = zSql;
-  while( pTsd->mallocFailed==0 && zSql[i]!=0 ){
+  while( !sqlite3MallocFailed() && zSql[i]!=0 ){
     assert( i>=0 );
     pParse->sLastToken.z = (u8*)&zSql[i];
     assert( pParse->sLastToken.dyn==0 );
@@ -407,7 +407,7 @@
     sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
   }
   sqlite3ParserFree(pEngine, sqlite3FreeX);
-  if( pTsd->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     pParse->rc = SQLITE_NOMEM;
   }
   if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
diff --git a/src/trigger.c b/src/trigger.c
index 6a031c0..15bbc99 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -81,7 +81,7 @@
   ** If sqlite3SrcListLookup() returns 0, indicating the table does not
   ** exist, the error is caught by the block below.
   */
-  if( !pTableName || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( !pTableName || sqlite3MallocFailed() ){
     goto trigger_cleanup;
   }
   pTab = sqlite3SrcListLookup(pParse, pTableName);
@@ -90,7 +90,7 @@
   }
 
   /* Ensure the table name matches database name and that the table exists */
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto trigger_cleanup;
+  if( sqlite3MallocFailed() ) goto trigger_cleanup;
   assert( pTableName->nSrc==1 );
   if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && 
       sqlite3FixSrcList(&sFix, pTableName) ){
@@ -257,7 +257,7 @@
     pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, 
                      pTrig->name, strlen(pTrig->name)+1, pTrig);
     if( pDel ){
-      assert( sqlite3ThreadDataReadOnly()->mallocFailed && pDel==pTrig );
+      assert( sqlite3MallocFailed() && pDel==pTrig );
       goto triggerfinish_cleanup;
     }
     n = strlen(pTrig->table) + 1;
@@ -441,7 +441,7 @@
   int nName;
   sqlite3 *db = pParse->db;
 
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto drop_trigger_cleanup;
+  if( sqlite3MallocFailed() ) goto drop_trigger_cleanup;
   if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
     goto drop_trigger_cleanup;
   }
diff --git a/src/update.c b/src/update.c
index 944ac03..83084d7 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.120 2006/01/11 21:41:22 drh Exp $
+** $Id: update.c,v 1.121 2006/01/18 16:51:36 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -100,7 +100,7 @@
   int oldIdx      = -1;  /* index of trigger "old" temp table       */
 
   sContext.pParse = 0;
-  if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( pParse->nErr || sqlite3MallocFailed() ){
     goto update_cleanup;
   }
   db = pParse->db;
diff --git a/src/util.c b/src/util.c
index 1670d19..3f88da8 100644
--- a/src/util.c
+++ b/src/util.c
@@ -14,7 +14,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.175 2006/01/18 15:39:26 danielk1977 Exp $
+** $Id: util.c,v 1.176 2006/01/18 16:51:36 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -196,20 +196,27 @@
 int sqlite3_iMallocFail;     /* Fail sqliteMalloc() after this many calls */
 int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
 
+void *sqlite3_pFirst = 0;         /* Pointer to linked list of allocations */
+int sqlite3_nMaxAlloc = 0;        /* High water mark of ThreadData.nAlloc */
+int sqlite3_mallocDisallowed = 0; /* assert() in sqlite3Malloc() if set */
+int sqlite3_isFail = 0;           /* True if all malloc calls should fail */
+const char *sqlite3_zFile = 0;    /* Filename to associate debug info with */
+int sqlite3_iLine = 0;            /* Line number for debug info */
+
 /*
 ** Check for a simulated memory allocation failure.  Return true if
 ** the failure should be simulated.  Return false to proceed as normal.
 */
 static int failMalloc(){
   ThreadData *pTsd = sqlite3ThreadData();
-  if( pTsd->isFail ){
+  if( sqlite3_isFail ){
     return 1;
   }
   if( sqlite3_iMallocFail>=0 ){
     sqlite3_iMallocFail--;
     if( sqlite3_iMallocFail==0 ){
       sqlite3_iMallocFail = sqlite3_iMallocReset;
-      pTsd->isFail = 1;
+      sqlite3_isFail = 1;
       return 1;
     }
   }
@@ -269,11 +276,11 @@
   /* Line number */
   z = &((char *)z)[TESTALLOC_NGUARD*sizeof(u32)];             /* Guard words */
   z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
-  memcpy(z, &sqlite3ThreadData()->iLine, sizeof(u32));
+  memcpy(z, &sqlite3_iLine, sizeof(u32));
 
   /* File name */
   z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
-  strncpy(z, sqlite3ThreadData()->zFile, TESTALLOC_FILESIZE);
+  strncpy(z, sqlite3_zFile, TESTALLOC_FILESIZE);
   z[TESTALLOC_FILESIZE - 1] = '\0';
 
   /* User string */
@@ -312,11 +319,11 @@
   ThreadData *pTsd = sqlite3ThreadData();
   void **pp = (void **)p;
   pp[0] = 0;
-  pp[1] = pTsd->pFirst;
-  if( pTsd->pFirst ){
-    ((void **)pTsd->pFirst)[0] = p;
+  pp[1] = sqlite3_pFirst;
+  if( sqlite3_pFirst ){
+    ((void **)sqlite3_pFirst)[0] = p;
   }
-  pTsd->pFirst = p;
+  sqlite3_pFirst = p;
 }
 
 /*
@@ -327,12 +334,12 @@
 {
   ThreadData *pTsd = sqlite3ThreadData();
   void **pp = (void **)p;
-  if( p==pTsd->pFirst ){
+  if( p==sqlite3_pFirst ){
     assert(!pp[0]);
     assert(!pp[1] || ((void **)(pp[1]))[0]==p);
-    pTsd->pFirst = pp[1];
-    if( pTsd->pFirst ){
-      ((void **)pTsd->pFirst)[0] = 0;
+    sqlite3_pFirst = pp[1];
+    if( sqlite3_pFirst ){
+      ((void **)sqlite3_pFirst)[0] = 0;
     }
   }else{
     void **pprev = pp[0];
@@ -359,7 +366,7 @@
     ((void **)(pp[0]))[1] = p;
   }else{
     ThreadData *pTsd = sqlite3ThreadData();
-    pTsd->pFirst = p;
+    sqlite3_pFirst = p;
   }
   if( pp[1] ){
     ((void **)(pp[1]))[0] = p;
@@ -394,7 +401,7 @@
   Tcl_Obj *pRes = Tcl_NewObj();
   Tcl_IncrRefCount(pRes);
 
-  for(p=pTsd->pFirst; p; p=((void **)p)[1]){
+  for(p=sqlite3_pFirst; p; p=((void **)p)[1]){
     Tcl_Obj *pEntry = Tcl_NewObj();
     Tcl_Obj *pStack = Tcl_NewObj();
     char *z;
@@ -439,9 +446,9 @@
 static void * OSMALLOC(int n){
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
   ThreadData *pTsd = sqlite3ThreadData();
-  pTsd->nMaxAlloc = MAX(pTsd->nMaxAlloc, pTsd->nAlloc);
+  sqlite3_nMaxAlloc = MAX(sqlite3_nMaxAlloc, pTsd->nAlloc);
 #endif
-  assert( !sqlite3ThreadData()->mallocDisallowed );
+  assert( !sqlite3_mallocDisallowed );
   if( !failMalloc() ){
     u32 *p;
     p = (u32 *)sqlite3OsMalloc(n + TESTALLOC_OVERHEAD);
@@ -481,9 +488,9 @@
 static void * OSREALLOC(void *pRealloc, int n){
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
   ThreadData *pTsd = sqlite3ThreadData();
-  pTsd->nMaxAlloc = MAX(pTsd->nMaxAlloc, pTsd->nAlloc);
+  sqlite3_nMaxAlloc = MAX(sqlite3_nMaxAlloc, pTsd->nAlloc);
 #endif
-  assert( !sqlite3ThreadData()->mallocDisallowed );
+  assert( !sqlite3_mallocDisallowed );
   if( !failMalloc() ){
     u32 *p = (u32 *)getOsPointer(pRealloc);
     checkGuards(p);
@@ -496,7 +503,7 @@
 }
 
 static void OSMALLOC_FAILED(){
-  sqlite3ThreadData()->isFail = 0;
+  sqlite3_isFail = 0;
 }
 
 #else
@@ -549,7 +556,7 @@
 */
 void *sqlite3MallocRaw(int n){
   void *p = 0;
-  if( n>0 && !sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( n>0 && !sqlite3MallocFailed() ){
     handleSoftLimit(n);
     while( !(p = OSMALLOC(n)) && sqlite3_release_memory(n) );
     if( !p ){
@@ -559,7 +566,7 @@
       ** still correct after a malloc() failure. 
       */
       handleSoftLimit(n * -1);
-      sqlite3ThreadData()->mallocFailed = 1;
+      sqlite3FailedMalloc();
       OSMALLOC_FAILED();
     }
   }
@@ -572,7 +579,7 @@
 ** attempt to free memory by calling sqlite3_release_memory().
 */
 void *sqlite3Realloc(void *p, int n){
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     return 0;
   }
 
@@ -589,7 +596,7 @@
       ** still correct after a malloc() failure. 
       */
       handleSoftLimit(OSSIZEOF(p) - n);
-      sqlite3ThreadData()->mallocFailed = 1;
+      sqlite3FailedMalloc();
       OSMALLOC_FAILED();
     }
     return np;
@@ -1350,26 +1357,42 @@
 ** then the connection error-code (the value returned by sqlite3_errcode())
 ** is set to SQLITE_NOMEM.
 */
+static int mallocHasFailed = 0;
 int sqlite3ApiExit(sqlite3* db, int rc){
-  ThreadData *pTd = sqlite3OsThreadSpecificData(0);
-  if( pTd && pTd->mallocFailed ){
-    pTd->mallocFailed = 0;
-    if( db ){
-      sqlite3Error(db, SQLITE_NOMEM, 0);
-    }
-    return SQLITE_NOMEM;
+  if( sqlite3MallocFailed() ){
+    mallocHasFailed = 0;
+    sqlite3OsLeaveMutex();
+    sqlite3Error(db, SQLITE_NOMEM, 0);
+    rc = SQLITE_NOMEM;
   }
   return rc;
 }
 
+/* 
+** Return true is a malloc has failed in this thread since the last call
+** to sqlite3ApiExit(), or false otherwise.
+*/
+int sqlite3MallocFailed(){
+  return (mallocHasFailed && sqlite3OsInMutex());
+}
+
+/* 
+** Set the "malloc has failed" condition to true for this thread.
+*/
+void sqlite3FailedMalloc(){
+  sqlite3OsEnterMutex();
+  assert( mallocHasFailed==0 );
+  mallocHasFailed = 1;
+}
+
 #ifdef SQLITE_MEMDEBUG
 /*
 ** This function sets a flag in the thread-specific-data structure that will
 ** cause an assert to fail if sqliteMalloc() or sqliteRealloc() is called.
 */
 void sqlite3MallocDisallow(){
-  assert( sqlite3ThreadData()->mallocDisallowed>=0 );
-  sqlite3ThreadData()->mallocDisallowed++;
+  assert( sqlite3_mallocDisallowed>=0 );
+  sqlite3_mallocDisallowed++;
 }
 
 /*
@@ -1377,7 +1400,7 @@
 ** by sqlite3MallocDisallow().
 */
 void sqlite3MallocAllow(){
-  assert( sqlite3ThreadData()->mallocDisallowed>0 );
-  sqlite3ThreadData()->mallocDisallowed--;
+  assert( sqlite3_mallocDisallowed>0 );
+  sqlite3_mallocDisallowed--;
 }
 #endif
diff --git a/src/vacuum.c b/src/vacuum.c
index 7584554..e1ffc63 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -14,7 +14,7 @@
 ** Most of the code in this file may be omitted by defining the
 ** SQLITE_OMIT_VACUUM macro.
 **
-** $Id: vacuum.c,v 1.57 2006/01/13 01:48:59 drh Exp $
+** $Id: vacuum.c,v 1.58 2006/01/18 16:51:36 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "vdbeInt.h"
@@ -314,7 +314,7 @@
   ** Fix this so the flag and return code match.
   */
   if( rc==SQLITE_NOMEM ){
-    sqlite3ThreadData()->mallocFailed = 1;
+    sqlite3MallocFailed();
   }
 
   if( zTemp ){
diff --git a/src/vdbe.c b/src/vdbe.c
index 148783b..a99f335 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.531 2006/01/16 15:14:28 danielk1977 Exp $
+** $Id: vdbe.c,v 1.532 2006/01/18 16:51:36 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -431,7 +431,7 @@
   for(pc=p->pc; rc==SQLITE_OK; pc++){
     assert( pc>=0 && pc<p->nOp );
     assert( pTos<=&p->aStack[pc] );
-    if( pTsd->mallocFailed ) goto no_mem;
+    if( sqlite3MallocFailed() ) goto no_mem;
 #ifdef VDBE_PROFILE
     origPc = pc;
     start = hwtime();
@@ -1187,7 +1187,7 @@
   if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
   (*ctx.pFunc->xFunc)(&ctx, n, apVal);
   if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
-  if( pTsd->mallocFailed ) goto no_mem;
+  if( sqlite3MallocFailed() ) goto no_mem;
   popStack(&pTos, n);
 
   /* If any auxilary data functions have been called by this user function,
@@ -4040,13 +4040,13 @@
   sqlite3SafetyOff(db);
   assert( db->init.busy==0 );
   db->init.busy = 1;
-  assert(0==pTsd->mallocFailed);
+  assert( !sqlite3MallocFailed() );
   rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
   sqliteFree(zSql);
   db->init.busy = 0;
   sqlite3SafetyOn(db);
   if( rc==SQLITE_NOMEM ){
-    pTsd->mallocFailed = 1;
+    sqlite3FailedMalloc();
     goto no_mem;
   }
   break;  
@@ -4637,7 +4637,7 @@
   */
 abort_due_to_error:
   if( p->zErrMsg==0 ){
-    if( pTsd->mallocFailed ) rc = SQLITE_NOMEM;
+    if( sqlite3MallocFailed() ) rc = SQLITE_NOMEM;
     sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
   }
   goto vdbe_halt;
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index c1ae480..19ab347 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -157,7 +157,7 @@
   int rc;
 
   /* Assert that malloc() has not failed */
-  assert( !sqlite3ThreadDataReadOnly()->mallocFailed );
+  assert( !sqlite3MallocFailed() );
 
   if( p==0 || p->magic!=VDBE_MAGIC_RUN ){
     return SQLITE_MISUSE;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index aadb4f7..710c3e4 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -301,7 +301,7 @@
   int addr;
   assert( p->magic==VDBE_MAGIC_INIT );
   resizeOpArray(p, p->nOp + nOp);
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     return 0;
   }
   addr = p->nOp;
@@ -415,7 +415,7 @@
 void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
   Op *pOp;
   assert( p->magic==VDBE_MAGIC_INIT );
-  if( p==0 || p->aOp==0 || sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){
     if (n != P3_KEYINFO) {
       freeP3(n, (void*)*(char**)&zP3);
     }
@@ -473,7 +473,7 @@
   va_list ap;
   assert( p->nOp>0 );
   assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 
-          || sqlite3ThreadDataReadOnly()->mallocFailed );
+          || sqlite3MallocFailed() );
   va_start(ap, zFormat);
   sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
   va_end(ap);
@@ -739,7 +739,7 @@
       + nMem*sizeof(Mem)               /* aMem */
       + nCursor*sizeof(Cursor*)        /* apCsr */
     );
-    if( !sqlite3ThreadDataReadOnly()->mallocFailed ){
+    if( !sqlite3MallocFailed() ){
       p->aMem = &p->aStack[nStack];
       p->nMem = nMem;
       p->aVar = &p->aMem[nMem];
@@ -891,7 +891,7 @@
   int rc;
   Mem *pColName;
   assert( idx<(2*p->nResColumn) );
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ) return SQLITE_NOMEM;
+  if( sqlite3MallocFailed() ) return SQLITE_NOMEM;
   assert( p->aColName!=0 );
   pColName = &(p->aColName[idx]);
   if( N==P3_DYNAMIC || N==P3_STATIC ){
@@ -1154,7 +1154,7 @@
   int i;
   int (*xFunc)(Btree *pBt) = 0;  /* Function to call on each btree backend */
 
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     p->rc = SQLITE_NOMEM;
   }
 
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 37ef497..2596418 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -758,7 +758,7 @@
   }else if( !(pVal->flags&MEM_Blob) ){
     sqlite3VdbeMemStringify(pVal, enc);
   }
-  assert(pVal->enc==enc || sqlite3ThreadDataReadOnly()->mallocFailed);
+  assert(pVal->enc==enc || sqlite3MallocFailed() );
   return (const void *)(pVal->enc==enc ? (pVal->z) : 0);
 }
 
diff --git a/src/where.c b/src/where.c
index 9a7e590..84cf3d1 100644
--- a/src/where.c
+++ b/src/where.c
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.198 2006/01/14 08:02:28 danielk1977 Exp $
+** $Id: where.c,v 1.199 2006/01/18 16:51:36 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -567,7 +567,7 @@
   int nPattern;
   int isComplete;
 
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ) return;
+  if( sqlite3MallocFailed() ) return;
   prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
   if( pExpr->op==TK_IN ){
     assert( pExpr->pRight==0 );
@@ -1451,7 +1451,7 @@
   ** return value.
   */
   pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     goto whereBeginNoMem;
   }
   pWInfo->pParse = pParse;
@@ -1475,7 +1475,7 @@
     createMask(&maskSet, pTabList->a[i].iCursor);
   }
   exprAnalyzeAll(pTabList, &maskSet, &wc);
-  if( sqlite3ThreadDataReadOnly()->mallocFailed ){
+  if( sqlite3MallocFailed() ){
     goto whereBeginNoMem;
   }