diff options
author | drh <drh@noemail.net> | 2006-01-11 21:41:20 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2006-01-11 21:41:20 +0000 |
commit | 6f7adc8a8036ec2d30ba4cd12610e0cba5834640 (patch) | |
tree | da5457aef1a8cb9194acffdf80b19f512aea3823 | |
parent | 0203bde908cb15eecef3a03c9761827e165d71db (diff) | |
download | sqlite-6f7adc8a8036ec2d30ba4cd12610e0cba5834640.tar.gz sqlite-6f7adc8a8036ec2d30ba4cd12610e0cba5834640.zip |
Automatically deallocate thread-specific data when it is no longer
being used. Ticket #1601. Also implemented the suggestion of
ticket #1603. Memory management is now off by default at compile-time.
The sqlite3_enable_memory_management() API has been removed. (CVS 2919)
FossilOrigin-Name: 5d9c6aa964305c3f36741ff0058da5b5f3ce0d24
-rw-r--r-- | manifest | 70 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | sqlite3.def | 1 | ||||
-rw-r--r-- | src/alter.c | 6 | ||||
-rw-r--r-- | src/attach.c | 6 | ||||
-rw-r--r-- | src/btree.c | 40 | ||||
-rw-r--r-- | src/build.c | 32 | ||||
-rw-r--r-- | src/callback.c | 5 | ||||
-rw-r--r-- | src/delete.c | 4 | ||||
-rw-r--r-- | src/expr.c | 13 | ||||
-rw-r--r-- | src/insert.c | 10 | ||||
-rw-r--r-- | src/legacy.c | 4 | ||||
-rw-r--r-- | src/main.c | 25 | ||||
-rw-r--r-- | src/os.h | 4 | ||||
-rw-r--r-- | src/os_unix.c | 64 | ||||
-rw-r--r-- | src/os_win.c | 33 | ||||
-rw-r--r-- | src/pager.c | 29 | ||||
-rw-r--r-- | src/prepare.c | 14 | ||||
-rw-r--r-- | src/select.c | 17 | ||||
-rw-r--r-- | src/sqlite.h.in | 31 | ||||
-rw-r--r-- | src/sqliteInt.h | 19 | ||||
-rw-r--r-- | src/test1.c | 45 | ||||
-rw-r--r-- | src/tokenize.c | 6 | ||||
-rw-r--r-- | src/trigger.c | 10 | ||||
-rw-r--r-- | src/update.c | 6 | ||||
-rw-r--r-- | src/util.c | 94 | ||||
-rw-r--r-- | src/vdbe.c | 10 | ||||
-rw-r--r-- | src/vdbeapi.c | 4 | ||||
-rw-r--r-- | src/vdbeaux.c | 15 | ||||
-rw-r--r-- | src/vdbemem.c | 2 | ||||
-rw-r--r-- | src/where.c | 8 |
31 files changed, 332 insertions, 297 deletions
@@ -1,5 +1,5 @@ -C Ensure\sthe\sdatabase\sattached\sas\spart\sof\sVACUUM\scan\sbe\sdetached\ssuccessfully\safter\sa\smalloc()\sfailure.\s(CVS\s2918) -D 2006-01-11T16:10:20 +C Automatically\sdeallocate\sthread-specific\sdata\swhen\sit\sis\sno\slonger\nbeing\sused.\s\sTicket\s#1601.\s\sAlso\simplemented\sthe\ssuggestion\sof\nticket\s#1603.\sMemory\smanagement\sis\snow\soff\sby\sdefault\sat\scompile-time.\nThe\ssqlite3_enable_memory_management()\sAPI\shas\sbeen\sremoved.\s(CVS\s2919) +D 2006-01-11T21:41:21 F Makefile.in ab3ffd8d469cef4477257169b82810030a6bb967 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -28,52 +28,52 @@ F publish.sh ed0aba4ffdfadb36597d03ce8efdae96efc038cb F spec.template b2f6c4e488cbc3b993a57deba22cbc36203c4da3 F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc -F sqlite3.def ccf06c86eaa2c123271db41352d2b3c9e4ec42a5 +F sqlite3.def 99ac9728b515bb49d1af29153d64c8e7aad7bcc3 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a -F src/alter.c d0dd079b9ef0d551ff4a4ce09ee270c07b307bbb +F src/alter.c 4139c8f1d0f12b1759e767b1d09dd594e2b5ac1d F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a -F src/attach.c fb93d00ab7cb392579ea7db0a1247196d7220788 +F src/attach.c d4b9d8bd71d72409720946355be41cafb6c09079 F src/auth.c cdec356a5cd8b217c346f816c5912221537fe87f -F src/btree.c e1f6b2e22484d754b79b7c9b43e7a09af259f0f6 +F src/btree.c b407273cb22f39606acc27b8a4a74c6272c7a9d2 F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184 -F src/build.c c7847f299ded7fec899bfda74d4d31ba9f80aa75 -F src/callback.c 51fe813309f7cf69d3d19a2e7be2103130186efd +F src/build.c 652a3932292c2b8d1900219f537f1b5e21490afa +F src/callback.c ba3e6cc7a6beb562e7a66f92e26fabcb21aab1e2 F src/complete.c df1681cef40dec33a286006981845f87b194e7a4 F src/date.c a927bdbb51296ac398d2f667086a7072c099e5ab -F src/delete.c b242a0d9462d2b7054e38c5250bdbe94d6772a8e +F src/delete.c c7bd5708a629585e073ce34cf3b1fcb52c2fef38 F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d -F src/expr.c b90fa835a2216edd6808b4bb5da6bbf3b8ee29b9 +F src/expr.c 3b6acdb4e254027fe72ce70054ea6b71c7d423a3 F src/func.c e013c3b6c607c6a1654f5260eab59f5609a5ce4a F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 -F src/insert.c 337785137430a012ff0f1c181d4a4d55d2a942d3 -F src/legacy.c f651ccd3700f99fa05766ac53506bf9a0694761b -F src/main.c 3fe4b606db7d269d7a57c7b51ab3d9ff488e4b98 +F src/insert.c a5595cf8d1d8ba087b676a63f1f7277ea44b5ac1 +F src/legacy.c 9bf7ee1b63c99aac6669533986a5240b16101458 +F src/main.c 39d073fb1f95f874ee0c98366e99005cf14742dd F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/os.c 1d1a61cdf150e9f9520a3bc787c8465148ea2e78 -F src/os.h 8710c0068f3386a73a37f8ad242b92c7580464df +F src/os.h 9debc3d3ca4cdafde222a0ea74a4c8415aef4f22 F src/os_common.h 78bcc34dded9b625b3c16d072b7e5b76d075a674 F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3 -F src/os_unix.c 8943febbedc79649d21ec1ed14de14ad8214c899 +F src/os_unix.c 557a21c563496a1ccef32b1d57376d135884eac5 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e -F src/os_win.c 8ef250a0965a55dbcd8ef785e03f9f3292e6ade2 +F src/os_win.c b67dd34bf1ae796851910a229bd94026b42d942f F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 0a59a320b0da6b22d2dd4411d16e300ff1b947c8 +F src/pager.c a96b9c43664670576e41eac699277c7862d604d8 F src/pager.h e0acb095b3ad0bca48f2ab00c87346665643f64f F src/parse.y 83df51fea35f68f7e07384d75dce83d1ed30434c F src/pragma.c d439d257c1bcacbc09d38820ac578749df900562 -F src/prepare.c 65b166b806e4af6e0035acdd5f6a24e2ec02b66d +F src/prepare.c 60c1f5e3d2901d651f8ca9f06e39e2ff3f335844 F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812 F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261 -F src/select.c 579cfdd250c5598de7c867134f7d35a2099b1dcc +F src/select.c 7b19d350cb2a18ae4a59d6b87049aa2ce9c671ae F src/server.c 519e308651e30102dd3d1f4053ac64c14267e44c F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da -F src/sqlite.h.in 821b93f918d126c54d9a91fc928434945655edc3 -F src/sqliteInt.h 829f8c22767ceaed717042087e7fb4d599a3c44c +F src/sqlite.h.in 4320cff369e37897d2839d526c2b8917a2756d60 +F src/sqliteInt.h bd3fba6d7163ef402b5633191ee5d7de5b7f6e80 F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316 F src/tclsqlite.c d650bea0248fc0a310ddc2cb94273a3a5021fddf -F src/test1.c b2923fd22ec44cf05d6d51dc460e8ed8e0d5f241 +F src/test1.c d38c9f4da2136c5e1747517d7b564ba88a91fbee F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b F src/test3.c 9742aa146eb750cab81c1d5605286c3a0eb88054 F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f @@ -81,20 +81,20 @@ F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f F src/test6.c 74d91b487c68154156eded457925d96aa2a3fdbb F src/test7.c bfe36c62cae189509660acfeeb891ffb9da8ef0c F src/test_async.c 6776f5027ca6378c116ff5ccc2fe41b908e33772 -F src/tokenize.c 196486012c871cdcad6cc84a820cc988603f1b9d -F src/trigger.c 883b5f3b97137fbe417e3337c3fa20ac8e9c1ae5 -F src/update.c cd8ad5bb1a29f2056347481308fca4a59f2f4764 +F src/tokenize.c b75d24cbb419eef9ae7be286dd66723a2ee49f4f +F src/trigger.c 694b247476d2fc0dce003af564f79e8752fc1158 +F src/update.c 261d75c702c2852d1a64274d7c414485e6f2d177 F src/utf.c b7bffac4260177ae7f83c01d025fe0f5ed70ce71 -F src/util.c 3616a0a1f1b89cfb376240c75434431b8028681e +F src/util.c 8a147f96099ce716e4ee750142a8f53f1aed3286 F src/vacuum.c cd56995ecea281b3ac306ef88128ebc8a2117f84 -F src/vdbe.c aa4360d28c4476e435c84e92ad3fbd65a8944156 +F src/vdbe.c db592ade9a0e381f5e6a7a35a67e81c2722480b5 F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13 F src/vdbeInt.h 5451cf71f229e366ac543607c0a17f36e5737ea9 -F src/vdbeapi.c 6d20e92de62b90ae27aeea3a7b18653734b0b1cb -F src/vdbeaux.c e4b8f492e41e3b8ecee8f66045e897dae92d1356 +F src/vdbeapi.c afd3837cea0dec93dcb4724d073c84fa0da68e23 +F src/vdbeaux.c fca3a799a1e9d5b595a4e5d140f182601258287a F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 -F src/vdbemem.c 2ada7cae76da9c840cd0d3c01d2b3987d97141c6 -F src/where.c 4fecfccf8f35ec7b325d666f0cd2fb016a53da43 +F src/vdbemem.c 66e05857c3bd52436161d6bf96a95725f03225a5 +F src/where.c a8ba7f4aa2f38166e9f89ecc5dafbdbf41942031 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/all.test a23fcbbf1f53515bde840d78732a6d94c673b327 F test/alter.test b94b640063e725d062b2997bd2810ac39195c718 @@ -340,7 +340,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 3970eb875d1830d35b3a70a7583a8ab6b238cad6 -R 5d634fd31ace904b5b4a4cd1fc441144 -U danielk1977 -Z 11d0cd52f201ef748e551ed33dbe55f7 +P 8c26893c65574b0667bb84bde3ca49751079cc8d +R a464a0f33259fc5b6aae2e3199e401a7 +U drh +Z 7760f8b5862256854e201380c09a40e6 diff --git a/manifest.uuid b/manifest.uuid index 9ed2e2044..527e175ef 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8c26893c65574b0667bb84bde3ca49751079cc8d
\ No newline at end of file +5d9c6aa964305c3f36741ff0058da5b5f3ce0d24
\ No newline at end of file diff --git a/sqlite3.def b/sqlite3.def index 2921494b9..41dae4260 100644 --- a/sqlite3.def +++ b/sqlite3.def @@ -84,6 +84,7 @@ sqlite3_set_auxdata sqlite3_snprintf sqlite3_soft_heap_limit sqlite3_step +sqlite3_thread_cleanup sqlite3_total_changes sqlite3_trace sqlite3_transfer_bindings diff --git a/src/alter.c b/src/alter.c index c9fa9deed..f1809f4c8 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.15 2006/01/09 06:29:48 danielk1977 Exp $ +** $Id: alter.c,v 1.16 2006/01/11 21:41:21 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -267,7 +267,7 @@ void sqlite3AlterRenameTable( char *zWhere = 0; /* Where clause to locate temp triggers */ #endif - if( sqlite3ThreadData()->mallocFailed ) goto exit_rename_table; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_rename_table; assert( pSrc->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); @@ -501,7 +501,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); - if( sqlite3ThreadData()->mallocFailed ) goto exit_begin_add_column; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) 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 f1f1bbbd9..290596a95 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.45 2006/01/11 14:09:31 danielk1977 Exp $ +** $Id: attach.c,v 1.46 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" @@ -272,7 +272,7 @@ static void codeAttach( sqlite3* db = pParse->db; #ifndef SQLITE_OMIT_AUTHORIZATION - assert( sqlite3ThreadData()->mallocFailed || pAuthArg ); + assert( sqlite3ThreadDataReadOnly()->mallocFailed || pAuthArg ); if( pAuthArg ){ char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span); if( !zAuthArg ){ @@ -303,7 +303,7 @@ static void codeAttach( sqlite3ExprCode(pParse, pDbname); sqlite3ExprCode(pParse, pKey); - assert(v || sqlite3ThreadData()->mallocFailed); + assert(v || sqlite3ThreadDataReadOnly()->mallocFailed); if( v ){ sqlite3VdbeAddOp(v, OP_Function, 0, nFunc); pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); diff --git a/src/btree.c b/src/btree.c index b1bd141ed..064b3d301 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.290 2006/01/11 14:09:31 danielk1977 Exp $ +** $Id: btree.c,v 1.291 2006/01/11 21:41:22 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -557,7 +557,7 @@ static int saveCursorPosition(BtCursor *pCur){ */ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ BtCursor *p; - if( sqlite3ThreadData()->useSharedData ){ + if( sqlite3ThreadDataReadOnly()->useSharedData ){ for(p=pBt->pCursor; p; p=p->pNext){ if( p!=pExcept && p->pgnoRoot==iRoot && p->eState==CURSOR_VALID ){ int rc = saveCursorPosition(p); @@ -584,7 +584,7 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ static int restoreCursorPosition(BtCursor *pCur, int doSeek){ int rc = SQLITE_OK; if( pCur->eState==CURSOR_REQUIRESEEK ){ - assert( sqlite3ThreadData()->useSharedData ); + assert( sqlite3ThreadDataReadOnly()->useSharedData ); if( doSeek ){ rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip); }else{ @@ -610,7 +610,7 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ BtLock *pIter; /* This is a no-op if the shared-cache is not enabled */ - if( 0==sqlite3ThreadData()->useSharedData ){ + if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){ return SQLITE_OK; } @@ -658,7 +658,7 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){ BtLock *pIter; /* This is a no-op if the shared-cache is not enabled */ - if( 0==sqlite3ThreadData()->useSharedData ){ + if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){ return SQLITE_OK; } @@ -723,7 +723,7 @@ static void unlockAllTables(Btree *p){ ** locks in the BtShared.pLock list, making this procedure a no-op. Assert ** that this is the case. */ - assert( sqlite3ThreadData()->useSharedData || 0==*ppIter ); + assert( sqlite3ThreadDataReadOnly()->useSharedData || 0==*ppIter ); while( *ppIter ){ BtLock *pLock = *ppIter; @@ -1546,8 +1546,8 @@ int sqlite3BtreeOpen( int rc; int nReserve; unsigned char zDbHeader[100]; -#ifndef SQLITE_OMIT_SHARED_CACHE - ThreadData *pTsd = sqlite3ThreadData(); +#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) + const ThreadData *pTsdro; #endif /* Set the variable isMemdb to true for an in-memory database, or @@ -1572,13 +1572,14 @@ int sqlite3BtreeOpen( /* Try to find an existing Btree structure opened on zFilename. */ #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) - if( pTsd->useSharedData && zFilename && !isMemdb ){ + pTsdro = sqlite3ThreadDataReadOnly(); + if( pTsdro->useSharedData && zFilename && !isMemdb ){ char *zFullPathname = sqlite3OsFullPathname(zFilename); if( !zFullPathname ){ sqliteFree(p); return SQLITE_NOMEM; } - for(pBt=pTsd->pBtree; pBt; pBt=pBt->pNext){ + for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){ assert( pBt->nRef>0 ); if( 0==strcmp(zFullPathname, sqlite3pager_filename(pBt->pPager)) ){ p->pBt = pBt; @@ -1660,9 +1661,9 @@ int sqlite3BtreeOpen( #ifndef SQLITE_OMIT_SHARED_CACHE /* Add the new btree to the linked list starting at ThreadData.pBtree */ - if( pTsd->useSharedData && zFilename && !isMemdb ){ - pBt->pNext = pTsd->pBtree; - pTsd->pBtree = pBt; + if( pTsdro->useSharedData && zFilename && !isMemdb ){ + pBt->pNext = pTsdro->pBtree; + sqlite3ThreadData()->pBtree = pBt; } #endif pBt->nRef = 1; @@ -1678,7 +1679,7 @@ int sqlite3BtreeClose(Btree *p){ BtCursor *pCur; #ifndef SQLITE_OMIT_SHARED_CACHE - ThreadData *pTsd = sqlite3ThreadData(); + ThreadData *pTsd; #endif /* Drop any table-locks */ @@ -1708,6 +1709,7 @@ int sqlite3BtreeClose(Btree *p){ } /* Remove the shared-btree from the thread wide list */ + pTsd = sqlite3ThreadData(); if( pTsd->pBtree==pBt ){ pTsd->pBtree = pBt->pNext; }else{ @@ -6500,7 +6502,12 @@ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ return rc; } -#if defined(SQLITE_TEST) && !defined(NO_TCL) +/* +** The following debugging interface has to be in this file (rather +** than in, for example, test1.c) so that it can get access to +** the definition of BtShared. +*/ +#if defined(SQLITE_TEST) && defined(TCLSH) #include <tcl.h> int sqlite3_shared_cache_report( void * clientData, @@ -6508,7 +6515,7 @@ int sqlite3_shared_cache_report( int objc, Tcl_Obj *CONST objv[] ){ - ThreadData *pTd = sqlite3ThreadData(); + const ThreadData *pTd = sqlite3ThreadDataReadOnly(); if( pTd->useSharedData ){ BtShared *pBt; Tcl_Obj *pRet = Tcl_NewObj(); @@ -6522,4 +6529,3 @@ int sqlite3_shared_cache_report( return TCL_OK; } #endif - diff --git a/src/build.c b/src/build.c index 65ce2e533..ee3991018 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.376 2006/01/11 14:09:32 danielk1977 Exp $ +** $Id: build.c,v 1.377 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -66,9 +66,8 @@ void sqlite3TableLock( int i; int nBytes; TableLock *p; - ThreadData *pTsd = sqlite3ThreadData(); - if( 0==pTsd->useSharedData || iDb<0 ){ + if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){ return; } @@ -98,7 +97,7 @@ void sqlite3TableLock( static void codeTableLocks(Parse *pParse){ int i; Vdbe *pVdbe; - assert( sqlite3ThreadData()->useSharedData || pParse->nTableLock==0 ); + assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 ); if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){ return; @@ -131,7 +130,7 @@ void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; - if( sqlite3ThreadData()->mallocFailed ) return; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) return; if( pParse->nested ) return; if( !pParse->pVdbe ){ if( pParse->rc==SQLITE_OK && pParse->nErr ){ @@ -1363,7 +1362,7 @@ void sqlite3EndTable( int iDb; if( (pEnd==0 && pSelect==0) || - pParse->nErr || sqlite3ThreadData()->mallocFailed ) { + pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) { return; } p = pParse->pNewTable; @@ -1600,7 +1599,7 @@ void sqlite3CreateView( */ p->pSelect = sqlite3SelectDup(pSelect); sqlite3SelectDelete(pSelect); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ return; } if( !pParse->db->init.busy ){ @@ -1842,7 +1841,9 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ sqlite3 *db = pParse->db; int iDb; - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) goto exit_drop_table; + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + goto exit_drop_table; + } assert( pName->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase); @@ -2201,7 +2202,7 @@ void sqlite3CreateIndex( int nExtra = 0; char *zExtra; - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ){ + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ goto exit_create_index; } @@ -2355,7 +2356,7 @@ void sqlite3CreateIndex( nName + 1 + /* Index.zName */ nExtra /* Collation sequence names */ ); - if( sqlite3ThreadData()->mallocFailed ) goto exit_create_index; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_create_index; pIndex->aiColumn = (int *)(&pIndex[1]); pIndex->aiRowEst = (int *)(&pIndex->aiColumn[nCol]); pIndex->azColl = (char **)(&pIndex->aiRowEst[nCol+1]); @@ -2642,7 +2643,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ sqlite3 *db = pParse->db; int iDb; - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ){ + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ goto exit_drop_index; } assert( pName->nSrc==1 ); @@ -2851,7 +2852,7 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; struct SrcList_item *pItem; - assert(pList || sqlite3ThreadData()->mallocFailed); + assert(pList || sqlite3ThreadDataReadOnly()->mallocFailed); if( pList ){ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ if( pItem->iCursor>=0 ) break; @@ -2900,7 +2901,7 @@ void sqlite3BeginTransaction(Parse *pParse, int type){ int i; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) return; + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return; v = sqlite3GetVdbe(pParse); @@ -2921,7 +2922,7 @@ void sqlite3CommitTransaction(Parse *pParse){ Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) return; + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return; v = sqlite3GetVdbe(pParse); @@ -2938,7 +2939,7 @@ void sqlite3RollbackTransaction(Parse *pParse){ Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) return; + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return; v = sqlite3GetVdbe(pParse); @@ -3212,4 +3213,3 @@ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){ } return pKey; } - diff --git a/src/callback.c b/src/callback.c index a1bf57789..c63b588aa 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.10 2006/01/10 17:58:23 danielk1977 Exp $ +** $Id: callback.c,v 1.11 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" @@ -178,7 +178,8 @@ static CollSeq *findCollSeqEntry( ** return the pColl pointer to be deleted (because it wasn't added ** to the hash table). */ - assert( !pDel || (sqlite3ThreadData()->mallocFailed && pDel==pColl) ); + assert( !pDel || + (sqlite3ThreadDataReadOnly()->mallocFailed && pDel==pColl) ); sqliteFree(pDel); } } diff --git a/src/delete.c b/src/delete.c index c1bc52998..1c85c4777 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.117 2006/01/10 17:58:23 danielk1977 Exp $ +** $Id: delete.c,v 1.118 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" @@ -108,7 +108,7 @@ void sqlite3DeleteFrom( #endif sContext.pParse = 0; - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ){ + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ goto delete_from_cleanup; } db = pParse->db; diff --git a/src/expr.c b/src/expr.c index fa7be8c35..108f69db0 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.247 2006/01/10 17:58:23 danielk1977 Exp $ +** $Id: expr.c,v 1.248 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -263,7 +263,7 @@ Expr *sqlite3ExprAnd(Expr *pLeft, Expr *pRight){ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ assert( pRight!=0 ); assert( pLeft!=0 ); - if( !sqlite3ThreadData()->mallocFailed && pRight->z && pLeft->z ){ + if( !sqlite3ThreadDataReadOnly()->mallocFailed && 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 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ sqlite3ReallocOrFree((void**)&pParse->apVarExpr, pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) ); } - if( !sqlite3ThreadData()->mallocFailed ){ + if( !sqlite3ThreadDataReadOnly()->mallocFailed ){ assert( pParse->apVarExpr!=0 ); pParse->apVarExpr[pParse->nVarExpr++] = pExpr; } @@ -462,7 +462,8 @@ ExprList *sqlite3ExprListDup(ExprList *p){ sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span); } assert( pNewExpr==0 || pNewExpr->span.z!=0 - || pOldExpr->span.z==0 || sqlite3ThreadData()->mallocFailed ); + || pOldExpr->span.z==0 + || sqlite3ThreadDataReadOnly()->mallocFailed ); pItem->zName = sqliteStrDup(pOldItem->zName); pItem->sortOrder = pOldItem->sortOrder; pItem->isAgg = pOldItem->isAgg; @@ -831,7 +832,7 @@ static int lookupName( zDb = sqlite3NameFromToken(pDbToken); zTab = sqlite3NameFromToken(pTableToken); zCol = sqlite3NameFromToken(pColumnToken); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ goto lookupname_end; } @@ -1308,7 +1309,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int mem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); - assert( testAddr>0 || sqlite3ThreadData()->mallocFailed ); + assert( testAddr>0 || sqlite3ThreadDataReadOnly()->mallocFailed ); sqlite3VdbeAddOp(v, OP_MemInt, 1, mem); } diff --git a/src/insert.c b/src/insert.c index 3d4c460b6..e24968690 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.156 2006/01/10 17:58:23 danielk1977 Exp $ +** $Id: insert.c,v 1.157 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" @@ -225,7 +225,9 @@ void sqlite3Insert( int counterRowid; /* Memory cell holding rowid of autoinc counter */ #endif - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) goto insert_cleanup; + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + goto insert_cleanup; + } db = pParse->db; /* Locate the table into which we will be inserting new information. @@ -331,7 +333,9 @@ void sqlite3Insert( /* 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 || sqlite3ThreadData()->mallocFailed ) goto insert_cleanup; + if( rc || pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + goto insert_cleanup; + } iCleanup = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup); diff --git a/src/legacy.c b/src/legacy.c index 2d928aeac..b149f5b29 100644 --- a/src/legacy.c +++ b/src/legacy.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: legacy.c,v 1.10 2006/01/09 06:29:49 danielk1977 Exp $ +** $Id: legacy.c,v 1.11 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" @@ -121,7 +121,7 @@ exec_out: if( pStmt ) sqlite3_finalize(pStmt); if( azCols ) sqliteFree(azCols); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ rc = SQLITE_NOMEM; sqlite3MallocClearFailed(); } diff --git a/src/main.c b/src/main.c index 1b4c04900..3ea1fc32c 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.322 2006/01/10 13:58:48 drh Exp $ +** $Id: main.c,v 1.323 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -176,9 +176,9 @@ int sqlite3_close(sqlite3 *db){ ** structure? */ sqliteFree(db->aDb[1].pSchema); - sqliteFree(db); sqlite3MallocAllow(); + sqlite3ReleaseThreadData(); return SQLITE_OK; } @@ -645,7 +645,7 @@ int sqlite3BtreeFactory( */ const char *sqlite3_errmsg(sqlite3 *db){ const char *z; - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ return sqlite3ErrStr(SQLITE_NOMEM); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ @@ -684,7 +684,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){ }; const void *z; - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ @@ -705,7 +705,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){ ** passed to this function, we assume a malloc() failed during sqlite3_open(). */ int sqlite3_errcode(sqlite3 *db){ - if( !db || sqlite3ThreadData()->mallocFailed ){ + if( !db || sqlite3ThreadDataReadOnly()->mallocFailed ){ return SQLITE_NOMEM; } if( sqlite3SafetyCheck(db) ){ @@ -727,7 +727,7 @@ static int openDatabase( int rc; CollSeq *pColl; - assert( !sqlite3ThreadData()->mallocFailed ); + assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); /* Allocate the sqlite data structure */ db = sqliteMalloc( sizeof(sqlite3) ); @@ -854,7 +854,7 @@ int sqlite3_open16( rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); } }else{ - assert( sqlite3ThreadData()->mallocFailed ); + assert( sqlite3ThreadDataReadOnly()->mallocFailed ); sqlite3MallocClearFailed(); } sqlite3ValueFree(pVal); @@ -1077,6 +1077,17 @@ int sqlite3_enable_shared_cache(int enable){ } pTd->useSharedData = enable; + sqlite3ReleaseThreadData(); return SQLITE_OK; } #endif + +/* +** This is a convenience routine that makes sure that all thread-specific +** data for this thread has been deallocated. +*/ +void sqlite3_thread_cleanup(void){ + ThreadData *pTd = sqlite3ThreadData(); + memset(pTd, 0, sizeof(*pTd)); + sqlite3ReleaseThreadData(); +} @@ -292,7 +292,7 @@ int sqlite3OsCurrentTime(double*); void sqlite3OsEnterMutex(void); void sqlite3OsLeaveMutex(void); int sqlite3OsInMutex(void); -void *sqlite3OsThreadSpecificData(int); +ThreadData *sqlite3OsThreadSpecificData(int); void *sqlite3OsMalloc(int); void *sqlite3OsRealloc(void *, int); void sqlite3OsFree(void *); @@ -335,7 +335,7 @@ struct sqlite3OsVtbl { void (*xEnterMutex)(void); void (*xLeaveMutex)(void); int (*xInMutex)(void); - void *(*xThreadSpecificData)(int); + ThreadData *(*xThreadSpecificData)(int); void *(*xMalloc)(int); void *(*xRealloc)(void *, int); diff --git a/src/os_unix.c b/src/os_unix.c index 42570c6ae..e603151a9 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1627,38 +1627,27 @@ int sqlite3UnixInMutex(){ } /* -** This function is called automatically when a thread exists to delete -** the threads ThreadData structure. +** If called with allocateFlag==1, then return a pointer to thread +** specific data for the current thread. Allocate and zero the +** thread-specific data if it does not already exist necessary. ** -** Because the ThreadData structure is required by higher level routines -** such as sqliteMalloc() we use OsFree() and OsMalloc() directly to -** allocate the thread specific data. +** If called with allocateFlag==0, then check the current thread +** specific data. If it exists and is all zeros, then deallocate it. +** Return a pointer to the thread specific data or NULL if it is +** unallocated. */ -#ifdef SQLITE_UNIX_THREADS -static void deleteTsd(void *pTsd){ - sqlite3OsFree(pTsd); -} -#endif - -/* -** The first time this function is called from a specific thread, nByte -** bytes of data area are allocated and zeroed. A pointer to the new -** allocation is returned to the caller. -** -** Each subsequent call to this function from the thread returns the same -** pointer. The argument is ignored in this case. -*/ -void *sqlite3UnixThreadSpecificData(int nByte){ +ThreadData *sqlite3UnixThreadSpecificData(int allocateFlag){ + static const ThreadData zeroData; #ifdef SQLITE_UNIX_THREADS static pthread_key_t key; static int keyInit = 0; - void *pTsd; + ThreadData *pTsd; if( !keyInit ){ sqlite3OsEnterMutex(); if( !keyInit ){ int rc; - rc = pthread_key_create(&key, deleteTsd); + rc = pthread_key_create(&key, 0); if( rc ){ sqlite3OsLeaveMutex(); return 0; @@ -1669,21 +1658,32 @@ void *sqlite3UnixThreadSpecificData(int nByte){ } pTsd = pthread_getspecific(key); - if( !pTsd ){ - pTsd = sqlite3OsMalloc(nByte); - if( pTsd ){ - memset(pTsd, 0, nByte); - pthread_setspecific(key, pTsd); + if( allocateFlag ){ + if( pTsd==0 ){ + pTsd = sqlite3OsMalloc(sizeof(zeroData)); + if( pTsd ){ + *pTsd = zeroData; + pthread_setspecific(key, pTsd); + } } + }else if( pTsd!=0 && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){ + sqlite3OsFree(pTsd); + pthread_setspecific(key, 0); + pTsd = 0; } return pTsd; #else - static void *pTsd = 0; - if( !pTsd ){ - pTsd = sqlite3OsMalloc(nByte); - if( pTsd ){ - memset(pTsd, 0, nByte); + static ThreadData *pTsd = 0; + if( allocateFlag ){ + if( pTsd==0 ){ + pTsd = sqlite3OsMalloc( sizeof(zeroData) ); + if( pTsd ){ + *pTsd = zeroData; + } } + }else if( pTsd!=0 && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){ + sqlite3OsFree(pTsd); + pTsd = 0; } return pTsd; #endif diff --git a/src/os_win.c b/src/os_win.c index 38a1a3b7a..4675c4888 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -1148,18 +1148,21 @@ int sqlite3WinCurrentTime(double *prNow){ return 0; } -/* -** The first time this function is called from a specific thread, nByte -** bytes of data area are allocated and zeroed. A pointer to the new -** allocation is returned to the caller. +/* +** If called with allocateFlag==1, then return a pointer to thread +** specific data for the current thread. Allocate and zero the +** thread-specific data if it does not already exist necessary. ** -** Each subsequent call to this function from the thread returns the same -** pointer. The argument is ignored in this case. +** If called with allocateFlag==0, then check the current thread +** specific data. If it exists and is all zeros, then deallocate it. +** Return a pointer to the thread specific data or NULL if it is +** unallocated. */ -void *sqlite3WinThreadSpecificData(int nByte){ +void *sqlite3WinThreadSpecificData(int allocateFlag){ static void *pTsd = 0; static int key; static int keyInit = 0; + static const ThreadData zeroData; if( !keyInit ){ sqlite3OsEnterMutex(); @@ -1174,12 +1177,18 @@ void *sqlite3WinThreadSpecificData(int nByte){ sqlite3OsLeaveMutex(); } pTsd = TlsGetValue(key); - if( !pTsd ){ - pTsd = sqlite3OsMalloc(nByte); - if( pTsd ){ - memset(pTsd, 0, nByte); - TlsSetValue(key, pTsd); + if( allocateFlag ){ + if( !pTsd ){ + pTsd = sqlite3OsMalloc(nByte); + if( pTsd ){ + *pTsd = zeroData; + TlsSetValue(key, pTsd); + } } + }else if( pTsd!=0 && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){ + sqlite3OsFree(pTsd); + TlsSetValue(key, 0); + pTsd = 0; } return pTsd; } diff --git a/src/pager.c b/src/pager.c index a8d601e52..7bf505494 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.235 2006/01/10 20:32:32 drh Exp $ +** @(#) $Id: pager.c,v 1.236 2006/01/11 21:41:22 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -284,7 +284,7 @@ struct Pager { void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void *pCodecArg; /* First argument to xCodec() */ PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */ -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Pager *pNext; /* Linked list of pagers in this thread */ #endif }; @@ -1618,8 +1618,8 @@ int sqlite3pager_open( int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; int noReadlock = (flags & PAGER_NO_READLOCK)!=0; char zTemp[SQLITE_TEMPNAME_SIZE]; -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT - ThreadData *pTsd = sqlite3ThreadData(); +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + const ThreadData *pTsdro = sqlite3ThreadDataReadOnly(); #endif /* If malloc() has already failed return SQLITE_NOMEM. Before even @@ -1627,7 +1627,7 @@ int sqlite3pager_open( ** structure was never allocated. */ *ppPager = 0; - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ return SQLITE_NOMEM; } memset(&fd, 0, sizeof(fd)); @@ -1720,8 +1720,9 @@ int sqlite3pager_open( pPager->pBusyHandler = 0; memset(pPager->aHash, 0, sizeof(pPager->aHash)); *ppPager = pPager; -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT - if( pTsd->useMemoryManagement ){ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + if( pTsdro->useMemoryManagement ){ + ThreadData *pTsd = sqlite3ThreadData(); pPager->pNext = pTsd->pPager; pTsd->pPager = pPager; } @@ -2027,8 +2028,8 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){ */ int sqlite3pager_close(Pager *pPager){ PgHdr *pPg, *pNext; -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT - ThreadData *pTsd = sqlite3ThreadData(); +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + const ThreadData *pTsd = sqlite3ThreadDataReadOnly(); #endif switch( pPager->state ){ @@ -2087,7 +2088,7 @@ int sqlite3pager_close(Pager *pPager){ ** } */ -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* Remove the pager from the linked list of pagers starting at ** ThreadData.pPager if memory-management is enabled. */ @@ -2456,9 +2457,9 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){ ** free as much memory as possible. The return value is the total number ** of bytes of memory released. */ -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT int sqlite3pager_release_memory(int nReq){ - ThreadData *pTsd = sqlite3ThreadData(); + const ThreadData *pTsdro = sqlite3ThreadDataReadOnly(); Pager *p; int nReleased = 0; int i; @@ -2481,7 +2482,7 @@ int sqlite3pager_release_memory(int nReq){ for(i=0; i<=1; i++){ /* Loop through all the SQLite pagers opened by the current thread. */ - for(p=pTsd->pPager; p && (nReq<0 || nReleased<nReq); p=p->pNext){ + for(p=pTsdro->pPager; p && (nReq<0 || nReleased<nReq); p=p->pNext){ PgHdr *pPg; int rc; @@ -2527,7 +2528,7 @@ int sqlite3pager_release_memory(int nReq){ return nReleased; } -#endif /* SQLITE_OMIT_MEMORY_MANAGEMENT */ +#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ /* ** Acquire a page. diff --git a/src/prepare.c b/src/prepare.c index fcd0d19bd..d8d151094 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.19 2006/01/11 14:09:32 danielk1977 Exp $ +** $Id: prepare.c,v 1.20 2006/01/11 21:41:22 drh 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( !sqlite3ThreadData()->mallocFailed ){ + if( !sqlite3ThreadDataReadOnly()->mallocFailed ){ sqlite3SetString(pData->pzErrMsg, "malformed database schema", zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); } @@ -49,7 +49,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ sqlite3 *db = pData->db; int iDb; - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ return SQLITE_NOMEM; } @@ -303,7 +303,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ #endif sqlite3BtreeCloseCursor(curMain); } - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ sqlite3SetString(pzErrMsg, "out of memory", (char*)0); rc = SQLITE_NOMEM; sqlite3ResetInternalSchema(db, 0); @@ -494,7 +494,7 @@ int sqlite3_prepare( int rc = SQLITE_OK; int i; - assert( !sqlite3ThreadData()->mallocFailed ); + assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); assert( ppStmt ); *ppStmt = 0; @@ -519,7 +519,7 @@ int sqlite3_prepare( sParse.db = db; sqlite3RunParser(&sParse, zSql, &zErrMsg); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ sParse.rc = SQLITE_NOMEM; } if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; @@ -569,7 +569,7 @@ int sqlite3_prepare( /* We must check for malloc failure last of all, in case malloc() failed ** inside of the sqlite3Error() call above or something. */ - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ rc = SQLITE_NOMEM; sqlite3Error(db, rc, 0); } diff --git a/src/select.c b/src/select.c index 145f319b0..d0fff323c 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.292 2006/01/10 17:58:23 danielk1977 Exp $ +** $Id: select.c,v 1.293 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" @@ -872,7 +872,8 @@ static void generateColumnNames( #endif assert( v!=0 ); - if( pParse->colNamesSet || v==0 || sqlite3ThreadData()->mallocFailed ) return; + if( pParse->colNamesSet || v==0 + || sqlite3ThreadDataReadOnly()->mallocFailed ) return; pParse->colNamesSet = 1; fullNames = (db->flags & SQLITE_FullColNames)!=0; shortNames = (db->flags & SQLITE_ShortColNames)!=0; @@ -1001,7 +1002,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ zName = sqlite3MPrintf("column%d", i+1); } sqlite3Dequote(zName); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ sqliteFree(zName); sqlite3DeleteTable(0, pTab); return 0; @@ -1073,7 +1074,9 @@ static int prepSelectStmt(Parse *pParse, Select *p){ Table *pTab; struct SrcList_item *pFrom; - if( p==0 || p->pSrc==0 || sqlite3ThreadData()->mallocFailed ) return 1; + if( p==0 || p->pSrc==0 || sqlite3ThreadDataReadOnly()->mallocFailed ){ + return 1; + } pTabList = p->pSrc; pEList = p->pEList; @@ -2690,7 +2693,9 @@ int sqlite3Select( AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ - if( sqlite3ThreadData()->mallocFailed || pParse->nErr || p==0 ) return 1; + if( p==0 || sqlite3ThreadDataReadOnly()->mallocFailed || pParse->nErr ){ + return 1; + } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); @@ -2944,7 +2949,7 @@ int sqlite3Select( goto select_end; } } - if( sqlite3ThreadData()->mallocFailed ) goto select_end; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) 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/sqlite.h.in b/src/sqlite.h.in index c43b7cd0d..92caceedd 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.154 2006/01/10 15:18:28 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.155 2006/01/11 21:41:22 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -1330,20 +1330,12 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); int sqlite3_enable_shared_cache(int); /* -** This function is only available if the library is compiled without -** the SQLITE_OMIT_MEMORY_MANAGEMENT macro defined. It is used to enable or -** disable (if the argument is true or false, respectively) the -** "memory management" features (accessed via the sqlite3_soft_heap_limit() -** and sqlite3_release_memory() APIs). -*/ -int sqlite3_enable_memory_management(int); - -/* ** Attempt to free N bytes of heap memory by deallocating non-essential ** memory allocations held by the database library (example: memory ** used to cache database pages to improve performance). ** -** This function is a no-op unless memory-management has been enabled. +** This function is not a part of standard builds. It is only created +** if SQLite is compiled with the SQLITE_ENABLE_MEMORY_MANAGEMENT macro. */ int sqlite3_release_memory(int); @@ -1357,13 +1349,26 @@ int sqlite3_release_memory(int); ** sufficient memory to prevent the limit from being exceeded, the memory is ** allocated anyway and the current operation proceeds. ** -** This function is only available if the library was compiled without the -** SQLITE_OMIT_MEMORY_MANAGEMENT option set. It is a no-op unless +** This function is only available if the library was compiled with the +** SQLITE_ENABLE_MEMORY_MANAGEMENT option set. ** memory-management has been enabled. */ void sqlite3_soft_heap_limit(int); /* +** This routine makes sure that all thread-local storage has been +** deallocated for the current thread. +** +** This routine is not technically necessary. All thread-local storage +** will be automatically deallocated once memory-management and +** shared-cache are disabled and the soft heap limit has been set +** to zero. This routine is provided as a convenience for users who +** want to make absolutely sure they have not forgotten something +** prior to killing off a thread. +*/ +void sqlite3_thread_cleanup(void); + +/* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1710f9293..9f5591faf 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.461 2006/01/11 14:09:32 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.462 2006/01/11 21:41:22 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -286,14 +286,17 @@ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */ #define sqliteAllocSize(x) sqlite3AllocSize(x) /* -** An instance of this structure is allocated for each thread that uses SQLite. +** An instance of this structure might be allocated to store information +** specific to a single thread. +** +** To avoid a memory leak on windows, the content of this structure is +** checked at the conclusion of each API call. If it is all zero, it +** is deallocated. */ struct ThreadData { - u8 isInit; /* True if structure has been initialised */ u8 mallocFailed; /* True after a malloc() has failed */ -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT - u8 useMemoryManagement; /* True if memory-management is enabled */ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT int nSoftHeapLimit; /* Suggested max mem allocation. No limit if <0 */ int nAlloc; /* Number of bytes currently allocated */ Pager *pPager; /* Linked list of all pagers in this thread */ @@ -306,7 +309,7 @@ struct ThreadData { #ifdef SQLITE_MEMDEBUG int nMaxAlloc; /* High water mark of ThreadData.nAlloc */ - int mallocAllowed; /* assert() in sqlite3Malloc() if not set */ + 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 */ @@ -1730,7 +1733,9 @@ void sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); -ThreadData *sqlite3ThreadData(); +ThreadData *sqlite3ThreadData(void); +const ThreadData *sqlite3ThreadDataReadOnly(void); +void sqlite3ReleaseThreadData(void); void sqlite3AttachFunctions(sqlite3 *); void sqlite3MinimumFileFormat(Parse*, int, int); void sqlite3SchemaFree(void *); diff --git a/src/test1.c b/src/test1.c index d98640b4c..891b5b4e2 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.187 2006/01/11 14:09:32 danielk1977 Exp $ +** $Id: test1.c,v 1.188 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -903,9 +903,9 @@ static int sqlite_malloc_outstanding( ){ extern int sqlite3OutstandingMallocs(Tcl_Interp *interp); -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( objc==2 ){ - ThreadData *pTd = sqlite3ThreadData(); + const ThreadData *pTd = sqlite3ThreadDataReadOnly(); const char *zArg = Tcl_GetString(objv[1]); if( 0==strcmp(zArg, "-bytes") ){ Tcl_SetObjResult(interp, Tcl_NewIntObj(pTd->nAlloc)); @@ -935,11 +935,10 @@ static int sqlite_malloc_outstanding( /* ** Usage: sqlite3_enable_shared_cache BOOLEAN -** Usage: sqlite3_enable_memory_management BOOLEAN ** */ -#if !defined(SQLITE_OMIT_SHARED_CACHE)||!defined(SQLITE_OMIT_MEMORY_MANAGEMENT) -static int test_enable( +#if !defined(SQLITE_OMIT_SHARED_CACHE) +static int test_enable_shared( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ @@ -948,20 +947,7 @@ static int test_enable( int rc; int enable; int ret = 0; - int (*xFunc)(int) = (int(*)(int))clientData; - ThreadData *pTsd = sqlite3ThreadData(); -#ifndef SQLITE_OMIT_SHARED_CACHE - if( xFunc==sqlite3_enable_shared_cache ){ - ret = pTsd->useSharedData; - }else -#endif -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT - { - assert( xFunc==sqlite3_enable_memory_management ); - ret = pTsd->useMemoryManagement; - } -#endif if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); return TCL_ERROR; @@ -969,7 +955,8 @@ static int test_enable( if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){ return TCL_ERROR; } - rc = xFunc(enable); + ret = sqlite3ThreadDataReadOnly()->useSharedData; + rc = sqlite3_enable_shared_cache(enable); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC); return TCL_ERROR; @@ -2966,7 +2953,7 @@ static int test_release_memory( int objc, Tcl_Obj *CONST objv[] ){ -#if !defined(SQLITE_OMIT_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) +#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) int N; int amt; if( objc!=1 && objc!=2 ){ @@ -2997,13 +2984,13 @@ static int test_soft_heap_limit( int objc, Tcl_Obj *CONST objv[] ){ -#if !defined(SQLITE_OMIT_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) +#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) int amt; if( objc!=1 && objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "?N?"); return TCL_ERROR; } - amt = sqlite3ThreadData()->nSoftHeapLimit; + amt = sqlite3ThreadDataReadOnly()->nSoftHeapLimit; if( objc==2 ){ int N; if( Tcl_GetIntFromObj(interp, objv[1], &N) ) return TCL_ERROR; @@ -3181,10 +3168,10 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "memorydb", "1", TCL_GLOBAL_ONLY); #endif -#ifdef SQLITE_OMIT_MEMORY_MANAGEMENT - Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY); -#else +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_OR_OPTIMIZATION @@ -3429,11 +3416,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_test_errstr", test_errstr, 0 }, { "tcl_variable_type", tcl_variable_type, 0 }, #ifndef SQLITE_OMIT_SHARED_CACHE - { "sqlite3_enable_shared_cache", test_enable, sqlite3_enable_shared_cache}, -#endif -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT - { "sqlite3_enable_memory_management", test_enable, - sqlite3_enable_memory_management}, + { "sqlite3_enable_shared_cache", test_enable_shared, 0 }, #endif }; static int bitmask_size = sizeof(Bitmask)*8; diff --git a/src/tokenize.c b/src/tokenize.c index 5645317ba..ec2efbe78 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.112 2006/01/09 06:29:49 danielk1977 Exp $ +** $Id: tokenize.c,v 1.113 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -358,7 +358,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ assert( pParse->nVarExprAlloc==0 ); assert( pParse->apVarExpr==0 ); pParse->zTail = pParse->zSql = zSql; - while( sqlite3ThreadData()->mallocFailed==0 && zSql[i]!=0 ){ + while( sqlite3ThreadDataReadOnly()->mallocFailed==0 && zSql[i]!=0 ){ assert( i>=0 ); pParse->sLastToken.z = (u8*)&zSql[i]; assert( pParse->sLastToken.dyn==0 ); @@ -406,7 +406,7 @@ abort_parse: sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); } sqlite3ParserFree(pEngine, sqlite3FreeX); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ 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 fbe8951bb..6a031c0bd 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -81,14 +81,16 @@ void sqlite3BeginTrigger( ** If sqlite3SrcListLookup() returns 0, indicating the table does not ** exist, the error is caught by the block below. */ - if( !pTableName || sqlite3ThreadData()->mallocFailed ) goto trigger_cleanup; + if( !pTableName || sqlite3ThreadDataReadOnly()->mallocFailed ){ + goto trigger_cleanup; + } pTab = sqlite3SrcListLookup(pParse, pTableName); if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ iDb = 1; } /* Ensure the table name matches database name and that the table exists */ - if( sqlite3ThreadData()->mallocFailed ) goto trigger_cleanup; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto trigger_cleanup; assert( pTableName->nSrc==1 ); if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && sqlite3FixSrcList(&sFix, pTableName) ){ @@ -255,7 +257,7 @@ void sqlite3FinishTrigger( pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, pTrig->name, strlen(pTrig->name)+1, pTrig); if( pDel ){ - assert( sqlite3ThreadData()->mallocFailed && pDel==pTrig ); + assert( sqlite3ThreadDataReadOnly()->mallocFailed && pDel==pTrig ); goto triggerfinish_cleanup; } n = strlen(pTrig->table) + 1; @@ -439,7 +441,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){ int nName; sqlite3 *db = pParse->db; - if( sqlite3ThreadData()->mallocFailed ) goto drop_trigger_cleanup; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto drop_trigger_cleanup; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto drop_trigger_cleanup; } diff --git a/src/update.c b/src/update.c index c44e24e1e..944ac039b 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.119 2006/01/10 17:58:23 danielk1977 Exp $ +** $Id: update.c,v 1.120 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" @@ -100,7 +100,9 @@ void sqlite3Update( int oldIdx = -1; /* index of trigger "old" temp table */ sContext.pParse = 0; - if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) goto update_cleanup; + if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + goto update_cleanup; + } db = pParse->db; assert( pTabList->nSrc==1 ); diff --git a/src/util.c b/src/util.c index 4064dadc9..846e9db16 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.167 2006/01/11 16:10:20 danielk1977 Exp $ +** $Id: util.c,v 1.168 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -66,13 +66,14 @@ #define MAX(x,y) ((x)>(y)?(x):(y)) -#if !defined(SQLITE_OMIT_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) +#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) /* ** Set the soft heap-size limit for the current thread. Passing a negative ** value indicates no limit. */ void sqlite3_soft_heap_limit(int n){ sqlite3ThreadData()->nSoftHeapLimit = n; + sqlite3ReleaseThreadData(); } /* @@ -82,7 +83,7 @@ int sqlite3_release_memory(int n){ return sqlite3pager_release_memory(n); } #else -/* If SQLITE_OMIT_MEMORY_MANAGEMENT is defined, then define a version +/* If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, then define a version ** of sqlite3_release_memory() to be used by other code in this file. ** This is done for no better reason than to reduce the number of ** pre-processor #ifndef statements. @@ -121,7 +122,9 @@ int sqlite3_release_memory(int n){ ** 2 since on 64-bit machines we want the value returned by sqliteMalloc() ** to be 8-byte aligned. */ -#define TESTALLOC_NGUARD 2 +#ifndef TESTALLOC_NGUARD +# define TESTALLOC_NGUARD 2 +#endif /* ** Size reserved for storing file-name along with each malloc()ed blob. @@ -434,11 +437,11 @@ int sqlite3OutstandingMallocs(Tcl_Interp *interp){ ** This is the test layer's wrapper around sqlite3OsMalloc(). */ static void * OSMALLOC(int n){ -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT ThreadData *pTsd = sqlite3ThreadData(); pTsd->nMaxAlloc = MAX(pTsd->nMaxAlloc, pTsd->nAlloc); #endif - assert( sqlite3ThreadData()->mallocAllowed ); + assert( !sqlite3ThreadData()->mallocDisallowed ); if( !failMalloc() ){ u32 *p; p = (u32 *)sqlite3OsMalloc(n + TESTALLOC_OVERHEAD); @@ -476,11 +479,11 @@ static void OSFREE(void *pFree){ ** This is the test layer's wrapper around sqlite3OsRealloc(). */ static void * OSREALLOC(void *pRealloc, int n){ -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT ThreadData *pTsd = sqlite3ThreadData(); pTsd->nMaxAlloc = MAX(pTsd->nMaxAlloc, pTsd->nAlloc); #endif - assert( sqlite3ThreadData()->mallocAllowed ); + assert( !sqlite3ThreadData()->mallocDisallowed ); if( !failMalloc() ){ u32 *p = (u32 *)getOsPointer(pRealloc); checkGuards(p); @@ -521,14 +524,18 @@ static void OSMALLOC_FAILED(){ ** called to try to avoid this. No indication of whether or not this is ** successful is returned to the caller. ** -** If SQLITE_OMIT_MEMORY_MANAGEMENT is defined, this function is a no-op. +** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is +** a no-op */ -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT static void handleSoftLimit(int n){ ThreadData *pTsd = sqlite3ThreadData(); pTsd->nAlloc += n; + assert( pTsd->nAlloc>=0 ); if( n>0 && pTsd->nSoftHeapLimit>0 ){ while( pTsd->nAlloc>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) ); + }else if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){ + sqlite3ReleaseThreadData(); } } #else @@ -541,9 +548,8 @@ static void handleSoftLimit(int n){ ** by calling sqlite3_release_memory(). */ void *sqlite3MallocRaw(int n){ - ThreadData *pTsd = sqlite3ThreadData(); void *p = 0; - if( n>0 && !pTsd->mallocFailed ){ + if( n>0 && !sqlite3ThreadDataReadOnly()->mallocFailed ){ handleSoftLimit(n); while( !(p = OSMALLOC(n)) && sqlite3_release_memory(n) ); if( !p ){ @@ -566,8 +572,7 @@ void *sqlite3MallocRaw(int n){ ** attempt to free memory by calling sqlite3_release_memory(). */ void *sqlite3Realloc(void *p, int n){ - ThreadData *pTsd = sqlite3ThreadData(); - if( pTsd->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ return 0; } @@ -584,7 +589,7 @@ void *sqlite3Realloc(void *p, int n){ ** still correct after a malloc() failure. */ handleSoftLimit(OSSIZEOF(p) - n); - pTsd->mallocFailed = 1; + sqlite3ThreadData()->mallocFailed = 1; OSMALLOC_FAILED(); } return np; @@ -1308,46 +1313,39 @@ void *sqlite3TextToPtr(const char *z){ ** Return a pointer to the ThreadData associated with the calling thread. */ ThreadData *sqlite3ThreadData(){ - ThreadData *pTsd = sqlite3OsThreadSpecificData(sizeof(ThreadData)); - if( pTsd && !pTsd->isInit ){ -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT - pTsd->nSoftHeapLimit = -1; -#endif -#ifndef NDEBUG - pTsd->mallocAllowed = 1; -#endif - pTsd->isInit = 1; - } - return pTsd; + return (ThreadData*)sqlite3OsThreadSpecificData(1); } /* -** Clear the "mallocFailed" flag. This should be invoked before exiting any -** entry points that may have called sqliteMalloc(). +** Return a pointer to the ThreadData associated with the calling thread. +** If no ThreadData has been allocated to this thread yet, return a pointer +** to a substitute ThreadData structure that is all zeros. */ -void sqlite3MallocClearFailed(){ - sqlite3ThreadData()->mallocFailed = 0; +const ThreadData *sqlite3ThreadDataReadOnly(){ + static const ThreadData zeroData; + const ThreadData *pTd = sqlite3OsThreadSpecificData(0); + return pTd ? pTd : &zeroData; } -#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT /* -** Enable the shared pager and schema features. +** Check to see if the ThreadData for this thread is all zero. If it +** is, then deallocate it. */ -int sqlite3_enable_memory_management(int enable){ - ThreadData *pTsd = sqlite3ThreadData(); +void sqlite3ReleaseThreadData(){ + sqlite3OsThreadSpecificData(0); +} - /* It is only legal to call sqlite3_enable_memory_management() when there - ** are no currently open connections that were opened by the calling - ** thread. This condition is only easy to detect if the feature were - ** previously enabled (and is being disabled). - */ - if( pTsd->pPager && !enable ){ - return SQLITE_MISUSE; +/* +** Clear the "mallocFailed" flag. This should be invoked before exiting any +** entry points that may have called sqliteMalloc(). +*/ +void sqlite3MallocClearFailed(){ + ThreadData *pTd = sqlite3OsThreadSpecificData(0); + if( pTd && pTd->mallocFailed ){ + pTd->mallocFailed = 0; + sqlite3OsThreadSpecificData(0); } - pTsd->useMemoryManagement = enable; - return SQLITE_OK; } -#endif #ifndef NDEBUG /* @@ -1355,8 +1353,8 @@ int sqlite3_enable_memory_management(int enable){ ** cause an assert to fail if sqliteMalloc() or sqliteRealloc() is called. */ void sqlite3MallocDisallow(){ - assert(sqlite3ThreadData()->mallocAllowed); - sqlite3ThreadData()->mallocAllowed = 0; + assert(!sqlite3ThreadData()->mallocDisallowed); + sqlite3ThreadData()->mallocDisallowed = 1; } /* @@ -1364,7 +1362,7 @@ void sqlite3MallocDisallow(){ ** by sqlite3MallocDisallow(). */ void sqlite3MallocAllow(){ - assert(!sqlite3ThreadData()->mallocAllowed); - sqlite3ThreadData()->mallocAllowed = 1; + assert(sqlite3ThreadData()->mallocDisallowed); + sqlite3ThreadData()->mallocDisallowed = 0; } #endif diff --git a/src/vdbe.c b/src/vdbe.c index 8fefed830..04bf97d53 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.522 2006/01/10 19:45:49 drh Exp $ +** $Id: vdbe.c,v 1.523 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -412,7 +412,7 @@ int sqlite3VdbeExec( for(pc=p->pc; rc==SQLITE_OK; pc++){ assert( pc>=0 && pc<p->nOp ); assert( pTos<=&p->aStack[pc] ); - if( sqlite3ThreadData()->mallocFailed ) goto no_mem; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto no_mem; #ifdef VDBE_PROFILE origPc = pc; start = hwtime(); @@ -1167,7 +1167,7 @@ case OP_Function: { if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; (*ctx.pFunc->xFunc)(&ctx, n, apVal); if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; - if( sqlite3ThreadData()->mallocFailed ) goto no_mem; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto no_mem; popStack(&pTos, n); /* If any auxilary data functions have been called by this user function, @@ -4020,7 +4020,7 @@ case OP_ParseSchema: { /* no-push */ sqlite3SafetyOff(db); assert( db->init.busy==0 ); db->init.busy = 1; - assert(0==sqlite3ThreadData()->mallocFailed); + assert(0==sqlite3ThreadDataReadOnly()->mallocFailed); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); sqliteFree(zSql); db->init.busy = 0; @@ -4616,7 +4616,7 @@ abort_due_to_misuse: */ abort_due_to_error: if( p->zErrMsg==0 ){ - if( sqlite3ThreadData()->mallocFailed ) rc = SQLITE_NOMEM; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) rc = SQLITE_NOMEM; sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0); } goto vdbe_halt; diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 462f38023..74bd8bd9d 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -156,7 +156,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){ sqlite3 *db; int rc; - assert(!sqlite3ThreadData()->mallocFailed); + assert(!sqlite3ThreadDataReadOnly()->mallocFailed); if( p==0 || p->magic!=VDBE_MAGIC_RUN ){ return SQLITE_MISUSE; @@ -404,7 +404,7 @@ static void columnMallocFailure(sqlite3_stmt *pStmt) ** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR ** and _finalize() will return NOMEM. */ - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ ((Vdbe *)pStmt)->rc = SQLITE_NOMEM; sqlite3MallocClearFailed(); } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 3080af59e..ab8282eae 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -102,7 +102,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ p->nOp++; assert( p->magic==VDBE_MAGIC_INIT ); resizeOpArray(p, i+1); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ return 0; } pOp = &p->aOp[i]; @@ -301,7 +301,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ int addr; assert( p->magic==VDBE_MAGIC_INIT ); resizeOpArray(p, p->nOp + nOp); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ return 0; } addr = p->nOp; @@ -415,7 +415,7 @@ static void freeP3(int p3type, void *p3){ 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 || sqlite3ThreadData()->mallocFailed ){ + if( p==0 || p->aOp==0 || sqlite3ThreadDataReadOnly()->mallocFailed ){ if (n != P3_KEYINFO) { freeP3(n, (void*)*(char**)&zP3); } @@ -472,7 +472,8 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_list ap; assert( p->nOp>0 ); - assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 || sqlite3ThreadData()->mallocFailed ); + assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 + || sqlite3ThreadDataReadOnly()->mallocFailed ); va_start(ap, zFormat); sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC); va_end(ap); @@ -738,7 +739,7 @@ void sqlite3VdbeMakeReady( + nMem*sizeof(Mem) /* aMem */ + nCursor*sizeof(Cursor*) /* apCsr */ ); - if( !sqlite3ThreadData()->mallocFailed ){ + if( !sqlite3ThreadDataReadOnly()->mallocFailed ){ p->aMem = &p->aStack[nStack]; p->nMem = nMem; p->aVar = &p->aMem[nMem]; @@ -890,7 +891,7 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){ int rc; Mem *pColName; assert( idx<(2*p->nResColumn) ); - if( sqlite3ThreadData()->mallocFailed ) return SQLITE_NOMEM; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) return SQLITE_NOMEM; assert( p->aColName!=0 ); pColName = &(p->aColName[idx]); if( N==P3_DYNAMIC || N==P3_STATIC ){ @@ -1153,7 +1154,7 @@ int sqlite3VdbeHalt(Vdbe *p){ int i; int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */ - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ p->rc = SQLITE_NOMEM; } diff --git a/src/vdbemem.c b/src/vdbemem.c index e3463352f..d0cadbddd 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -756,7 +756,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ }else if( !(pVal->flags&MEM_Blob) ){ sqlite3VdbeMemStringify(pVal, enc); } - assert(pVal->enc==enc || sqlite3ThreadData()->mallocFailed); + assert(pVal->enc==enc || sqlite3ThreadDataReadOnly()->mallocFailed); return (const void *)(pVal->enc==enc ? (pVal->z) : 0); } diff --git a/src/where.c b/src/where.c index e427e62c1..bcb342ff9 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.193 2006/01/10 17:58:23 danielk1977 Exp $ +** $Id: where.c,v 1.194 2006/01/11 21:41:22 drh Exp $ */ #include "sqliteInt.h" @@ -567,7 +567,7 @@ static void exprAnalyze( int nPattern; int isComplete; - if( sqlite3ThreadData()->mallocFailed ) return; + if( sqlite3ThreadDataReadOnly()->mallocFailed ) return; prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); if( pExpr->op==TK_IN ){ assert( pExpr->pRight==0 ); @@ -1438,7 +1438,7 @@ WhereInfo *sqlite3WhereBegin( ** return value. */ pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel)); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ goto whereBeginNoMem; } pWInfo->pParse = pParse; @@ -1462,7 +1462,7 @@ WhereInfo *sqlite3WhereBegin( createMask(&maskSet, pTabList->a[i].iCursor); } exprAnalyzeAll(pTabList, &maskSet, &wc); - if( sqlite3ThreadData()->mallocFailed ){ + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ goto whereBeginNoMem; } |