diff options
author | danielk1977 <danielk1977@noemail.net> | 2008-02-13 18:25:27 +0000 |
---|---|---|
committer | danielk1977 <danielk1977@noemail.net> | 2008-02-13 18:25:27 +0000 |
commit | a7a8e14bf2158f30674cbc182e964b20dc9b3b86 (patch) | |
tree | b9987b03c14b3f04b30e6a24d0b718e2a67c42d1 | |
parent | 0f35a6b529ba6ec6bcca1dc6c8cd80e5d062320a (diff) | |
download | sqlite-a7a8e14bf2158f30674cbc182e964b20dc9b3b86.tar.gz sqlite-a7a8e14bf2158f30674cbc182e964b20dc9b3b86.zip |
Where possible, avoid freeing buffers allocated for vdbe memory cells in case they can be reused. (CVS 4783)
FossilOrigin-Name: 990237e27e417aff3dbf05784b716c21f3761a3a
-rw-r--r-- | manifest | 58 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/attach.c | 6 | ||||
-rw-r--r-- | src/insert.c | 7 | ||||
-rw-r--r-- | src/legacy.c | 10 | ||||
-rw-r--r-- | src/mem1.c | 12 | ||||
-rw-r--r-- | src/mem2.c | 26 | ||||
-rw-r--r-- | src/mem3.c | 6 | ||||
-rw-r--r-- | src/os.c | 2 | ||||
-rw-r--r-- | src/pragma.c | 9 | ||||
-rw-r--r-- | src/select.c | 6 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 | ||||
-rw-r--r-- | src/tclsqlite.c | 6 | ||||
-rw-r--r-- | src/test1.c | 14 | ||||
-rw-r--r-- | src/test8.c | 21 | ||||
-rw-r--r-- | src/test_malloc.c | 29 | ||||
-rw-r--r-- | src/utf.c | 54 | ||||
-rw-r--r-- | src/vdbe.c | 227 | ||||
-rw-r--r-- | src/vdbeInt.h | 13 | ||||
-rw-r--r-- | src/vdbeapi.c | 1 | ||||
-rw-r--r-- | src/vdbeaux.c | 49 | ||||
-rw-r--r-- | src/vdbemem.c | 393 | ||||
-rw-r--r-- | test/mallocB.test | 4 | ||||
-rw-r--r-- | test/ptrchng.test | 24 | ||||
-rw-r--r-- | test/tester.tcl | 5 |
25 files changed, 547 insertions, 440 deletions
@@ -1,5 +1,5 @@ -C When\smaterializing\sa\sview\sfor\san\sUPDATE\sor\sDELETE\smake\suse\sof\sthe\sWHERE\nclause\sto\slimit\sthe\snumber\sof\srows\smaterialized.\s\sTicket\s#2938.\s(CVS\s4782) -D 2008-02-12T16:52:14 +C Where\spossible,\savoid\sfreeing\sbuffers\sallocated\sfor\svdbe\smemory\scells\sin\scase\sthey\scan\sbe\sreused.\s(CVS\s4783) +D 2008-02-13T18:25:27 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in bc2b5df3e3d0d4b801b824b7ef6dec43812b049b F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -80,7 +80,7 @@ F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc F src/alter.c b494a50f239a760565ce6220ee316e96956ec054 F src/analyze.c a78ac494668581fe7f54ee63700815bb0ea34261 -F src/attach.c 90665c7ef5145e066570f66d7f0f15cdd0a4d14b +F src/attach.c e13d62597e8725075b27186817f7e745122af24e F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/btmutex.c 483ced3c52205b04b97df69161fadbf87f4f1ea2 F src/btree.c 29ea577155f39be65bdec1c7782301ff2ee9eb3f @@ -97,24 +97,24 @@ F src/fault.c 049b88b8ba0a1db3240aeaf9695cd08b9a3ba9e1 F src/func.c 8e3d0c59961dc403716767308ee764504179054b F src/hash.c 2dc6afe7478a0b739499af360c8863c900ea11a8 F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 -F src/insert.c d422fda2d1f02219871cb7e3e4b49c680632450e +F src/insert.c b313f5ecadf82dda15b1aa6780b0310eceb9e776 F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 -F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66 +F src/legacy.c cb1939fdeb91ea88fb44fbd2768a10e14bc44650 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35 F src/loadext.c d17a0f760d6866aacf5262f97d8efaaad379cdd7 F src/main.c b4014b71979a58d6aa79549fdf87175ab7bdf1cc F src/malloc.c 60e392a4c12c839517f9b0db7b995f825444fb35 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 -F src/mem1.c 6d1a11864963d249c67e72ad5f6533b040333880 -F src/mem2.c 607af52ad7593f34934e7e4fa53a364556853d30 -F src/mem3.c 9d80034bb004c1bddc28d6befe1ddb044d18deab +F src/mem1.c b15e107d51bdd4bcf410c18798ee48bee4768d4e +F src/mem2.c ed0cb11ae43a3cc92bfb07172c2801956e94eaba +F src/mem3.c cf1bf5b2f9d4d76e465c84c0607f6882d3b1b522 F src/mem4.c 36ecd536a8b7acfe4cbf011353dae6ea68121e40 F src/mutex.c 3259f62c2429967aee6dc112117a6d2f499ef061 F src/mutex.h 079fa6fe9da18ceb89e79012c010594c6672addb F src/mutex_os2.c 19ab15764736f13b94b4f70e53f77547cbddd47a F src/mutex_unix.c a6e111947a3cdaa2cda394ed060d7f496fcb4af8 F src/mutex_w32.c 6e197765f283815496193e78e9548b5d0e53b68e -F src/os.c 50c0c1706c35f872db312815aaecc4b5ebcd6a4c +F src/os.c 2f2753b8d33f79d169c43d6bb0b25b3c58fd33de F src/os.h d04706d54a072c7a30ab9e346ad916ef28c842d5 F src/os_common.h 98862f120ca6bf7a48ce8b16f158b77d00bc9d2f F src/os_os2.c bf1cd3d4f42c1b1ab059c12732cd9f7be4e718a6 @@ -128,27 +128,27 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c 2ed81808091ce42ceb1cf209e4ce87922a0065c8 F src/pager.h 8174615ffd14ccc2cad2b081b919a398fa95e3f9 F src/parse.y 00f2698c8ae84f315be5e3f10b63c94f531fdd6d -F src/pragma.c 2bb8d6882b9a330e041acd05fb6aff5a01bf0a08 +F src/pragma.c e3f39f8576234887ecd0c1de43dc51af5855930c F src/prepare.c 1b0601ca3f97a9d253cc08697484e3045a1678e9 F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910 F src/random.c 02ef38b469237482f1ea14a78b2087cfbaec48bd -F src/select.c 394aa3542e8df599dcca77b0e75f7875760a13ad +F src/select.c 1d780691071af7d58b83a6b38517c2687dd83c5b F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c ca06cb687c40a8bff6307b5fad41a0e86a0f8558 F src/sqlite.h.in 690736613958e0f462e08ae2a9136fa335214edc F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb -F src/sqliteInt.h e4ca11fff0cdac38551b75a2a278edb8ad9e1f00 +F src/sqliteInt.h 822045362bdddd303a0b17aa09679ba735ffbaa1 F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e F src/table.c 46ccf9b7892a86f57420ae7bac69ecd5e72d26b5 -F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf -F src/test1.c 5363a117741f26e84b85e30757f0f4414331c46f +F src/tclsqlite.c 0d4483e37c6a1e87f80565e50d977df6dd2bf732 +F src/test1.c 28b135491b436b1df6390a8b53834da2f94efca4 F src/test2.c 77b34303883b9d722c65a6879bb0163a400e3789 F src/test3.c 4557ee13c6e5921eb28979ff77cdbd913bfde6be F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071 F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4 F src/test6.c f8b34a6ff04937092327798ddf0ab46863535bc5 F src/test7.c acec2256c7c2d279db5a8b5fa1a2a68fcc942c67 -F src/test8.c cab3f576353dfef4877c7cc3b0d0e48acc65c37c +F src/test8.c 25e127f0e21f59da24fa33cdbc645851cfb933f1 F src/test9.c 4615ef08750245a2d96aaa7cbe2fb4aff2b57acc F src/test_async.c 5f21392d66869a4c87dc9153e40d0dc0e085261f F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436 @@ -157,7 +157,7 @@ F src/test_config.c e7db7a46833d0df98ae6c9a11f70dada1bcca249 F src/test_devsym.c fd8884c2269fb7e0db2c52d21ec59d31a33790ba F src/test_hexio.c 1a1cd8324d57585ea86b922f609fa1fbaaf9662d F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 -F src/test_malloc.c 0bc9d27c09efe0be63d0de5fb6e38a4253cd5551 +F src/test_malloc.c f57e6327a9c32dc71fb2c15941f64d4e91461d3b F src/test_md5.c c107c96637123239c3518b5fbe97a79130f4d32e F src/test_onefile.c 54282b6796d55d7acc489be83b89b8715e7d3756 F src/test_schema.c 12c9de7661d6294eec2d57afbb52e2af1128084f @@ -167,17 +167,17 @@ F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730 F src/tokenize.c c4b79fd48ddb709b2b8522b7d93a5a3d98168ca4 F src/trigger.c 9bd3b6fa0beff4a02d262c96466f752ec15a7fc3 F src/update.c 9b3be169cd2a0b065717164aa0f90aa48f34aed1 -F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 +F src/utf.c 32b00d6e19010025e58f2ecb2f921d5e126771b4 F src/util.c c56e41ed4769c1f2b8af9ffde4757a7b4fb08ed1 F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0 -F src/vdbe.c 1049375248b494e626598abffeeb31052c660c78 +F src/vdbe.c a172f5134d19ae910134e28987bf7906523c9b6f F src/vdbe.h 58a7d931ffb704e034b2a725981cfa5bd406fad9 -F src/vdbeInt.h 969d360acc85f7b2069a8169b4f8a3e1fbaccd44 -F src/vdbeapi.c 61b37dbe11baa221baea7f93c01780705d2419ed -F src/vdbeaux.c 771b9ffd7b42cbb4bd029d7a9414a7cb03f924a7 +F src/vdbeInt.h 76c81d057a39813de0fda3cad1498655d53ec69d +F src/vdbeapi.c cf9fc963efae3cdf5de08e2a9718b487059c7fc5 +F src/vdbeaux.c 36d4db24659146606a1c755650f2a70cf88eec25 F src/vdbeblob.c 63c750acc7b5012479f508c0e9627372a82cb65d F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 -F src/vdbemem.c cee169fb5542cccfd1e8d832ae4538cb69b8917a +F src/vdbemem.c e060d04bc6f8cf32c638fddada266b01cad8ee9a F src/vtab.c dc8947c9c79780b19ee6d6bae4ea624a2a303353 F src/where.c 7ff0ca021cc77086e367ed3b6308fbc6bc9e1a31 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 @@ -378,7 +378,7 @@ F test/malloc8.test addc27d907fec1af429551b95c72caa47fce2974 F test/malloc9.test 95d7069ad4fa262bf33bc4c5ca0a46f2bb2391cb F test/mallocA.test 5ee8d42ff90e5b1aeee6fb645e73ffcb35bffd21 F test/mallocAll.test 2a2222a5e447be6c6579055a9a26e507e4586f4e -F test/mallocB.test 82ecf4d3fa6c389cabc747daa2deddfe94af2a74 +F test/mallocB.test d4a91e7d9cc916d009e0fec08537b3be299ee514 F test/mallocC.test 9daac0aa8e5b0afa7b0a3fb0cd792f02fe0cc838 F test/mallocD.test 24c1d07a00e605831d0d627b036bd690b2952416 F test/mallocE.test e15333c394d7c330c8372a7cdf7b0f7c16573082 @@ -412,7 +412,7 @@ F test/pragma.test d9f3d80583b80708aa270e8c5038dee949190d78 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/printf.test c3405535b418d454e8a52196a0fc592ec9eec58d F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x -F test/ptrchng.test 38ae1806833d72d9a81a6121322e274f24937e18 +F test/ptrchng.test 1f7bb92398163f1c18d69727c3ab31d90e94b458 F test/quick.test 771a6b3a88fdd0e7e813ce013ceda29037bc9462 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0 @@ -453,7 +453,7 @@ F test/table.test 13b1c2e2fb4727b35ee1fb7641fc469214fd2455 F test/tableapi.test 4546eb710d979db023bfcc16b0c108b1557fcb43 F test/tclsqlite.test 3fac87cb1059c46b8fa8a60b553f4f1adb0fb6d9 F test/temptable.test 19b851b9e3e64d91e9867619b2a3f5fffee6e125 -F test/tester.tcl bfad4d2acf0659c6afbf48a98556b0433d2906dc +F test/tester.tcl 70ed4c0dda3e2277bac9e0bf38e60df9dc360d08 F test/thread001.test 8fbd9559da0bbdc273e00318c7fd66c162020af7 F test/thread002.test 2c4ad2c386f60f6fe268cd91c769ee35b3c1fd0b F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 @@ -617,7 +617,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 607247c27b80520b8c25c489757288b8ea186f9e -R 6e7459c99c887be282a1c6ce2d461da7 -U drh -Z 584629669827c756e74626290b2a5564 +P 5ab71c3a79cac04cb2c576f83a62218d05571006 +R c1dd02f73a73bb7e12988703f2d12663 +U danielk1977 +Z 2dff5d02e45b3ba8d57e28cad43b1b4e diff --git a/manifest.uuid b/manifest.uuid index 1db4f72be..6137d5bb8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5ab71c3a79cac04cb2c576f83a62218d05571006
\ No newline at end of file +990237e27e417aff3dbf05784b716c21f3761a3a
\ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 67a34b7b0..905b1b052 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.71 2008/02/06 14:11:35 drh Exp $ +** $Id: attach.c,v 1.72 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -328,14 +328,14 @@ static void codeAttach( } v = sqlite3GetVdbe(pParse); - regArgs = sqlite3GetTempRange(pParse, 3); + regArgs = sqlite3GetTempRange(pParse, 4); sqlite3ExprCode(pParse, pFilename, regArgs); sqlite3ExprCode(pParse, pDbname, regArgs+1); sqlite3ExprCode(pParse, pKey, regArgs+2); assert( v || db->mallocFailed ); if( v ){ - sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-nFunc, regArgs); + sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-nFunc, regArgs+3); sqlite3VdbeChangeP5(v, nFunc); pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF); diff --git a/src/insert.c b/src/insert.c index 07b069c6f..9d1673b79 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.228 2008/01/25 15:04:50 drh Exp $ +** $Id: insert.c,v 1.229 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -218,14 +218,15 @@ static void autoIncEnd( Vdbe *v = pParse->pVdbe; Db *pDb = &pParse->db->aDb[iDb]; int j1; + int iRec = ++pParse->nMem; /* Memory cell used for record */ assert( v ); sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1); sqlite3VdbeJumpHere(v, j1); - sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, memId-1); - sqlite3VdbeAddOp3(v, OP_Insert, iCur, memId-1, memId+1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec); + sqlite3VdbeAddOp3(v, OP_Insert, iCur, iRec, memId+1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp1(v, OP_Close, iCur); } diff --git a/src/legacy.c b/src/legacy.c index c004b89e1..c1d1accd1 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.22 2007/08/29 12:31:26 danielk1977 Exp $ +** $Id: legacy.c,v 1.23 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -82,6 +82,10 @@ int sqlite3_exec( if( 0==nCallback ){ for(i=0; i<nCol; i++){ azCols[i] = (char *)sqlite3_column_name(pStmt, i); + if( !azCols[i] ){ + db->mallocFailed = 1; + goto exec_out; + } } nCallback++; } @@ -89,6 +93,10 @@ int sqlite3_exec( azVals = &azCols[nCol]; for(i=0; i<nCol; i++){ azVals[i] = (char *)sqlite3_column_text(pStmt, i); + if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){ + db->mallocFailed = 1; + goto exec_out; + } } } if( xCallback(pArg, nCol, azVals, azCols) ){ diff --git a/src/mem1.c b/src/mem1.c index 60ffc9138..33c4902d9 100644 --- a/src/mem1.c +++ b/src/mem1.c @@ -12,7 +12,7 @@ ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem1.c,v 1.14 2007/11/29 18:36:49 drh Exp $ +** $Id: mem1.c,v 1.15 2008/02/13 18:25:27 danielk1977 Exp $ */ /* @@ -190,6 +190,16 @@ void sqlite3_free(void *pPrior){ } /* +** Return the number of bytes allocated at p. +*/ +int sqlite3MallocSize(void *p){ + sqlite3_int64 *pInt; + if( !p ) return 0; + pInt = p; + return pInt[-1]; +} + +/* ** Change the size of an existing memory allocation */ void *sqlite3_realloc(void *pPrior, int nBytes){ diff --git a/src/mem2.c b/src/mem2.c index 0c99c63e5..807b72011 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -12,7 +12,7 @@ ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem2.c,v 1.19 2008/01/22 21:30:53 drh Exp $ +** $Id: mem2.c,v 1.20 2008/02/13 18:25:27 danielk1977 Exp $ */ /* @@ -244,6 +244,18 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ } /* +** Return the number of bytes currently allocated at address p. +*/ +int sqlite3MallocSize(void *p){ + struct MemBlockHdr *pHdr; + if( !p ){ + return 0; + } + pHdr = sqlite3MemsysGetHeader(p); + return pHdr->iSize; +} + +/* ** Allocate nByte bytes of memory. */ void *sqlite3_malloc(int nByte){ @@ -452,5 +464,17 @@ void sqlite3_memdebug_dump(const char *zFilename){ fclose(out); } +/* +** Return the number of times sqlite3_malloc() has been called. +*/ +int sqlite3_memdebug_malloc_count(){ + int i; + int nTotal = 0; + for(i=0; i<NCSIZE; i++){ + nTotal += mem.sizeCnt[i]; + } + return nTotal; +} + #endif /* SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */ diff --git a/src/mem3.c b/src/mem3.c index 0d98372a5..05b35ad89 100644 --- a/src/mem3.c +++ b/src/mem3.c @@ -20,7 +20,7 @@ ** This version of the memory allocation subsystem is used if ** and only if SQLITE_MEMORY_SIZE is defined. ** -** $Id: mem3.c,v 1.8 2007/12/29 13:18:22 drh Exp $ +** $Id: mem3.c,v 1.9 2008/02/13 18:25:27 danielk1977 Exp $ */ /* @@ -291,7 +291,7 @@ static void memsys3OutOfMemory(int nByte){ ** size returned omits the 8-byte header overhead. This only ** works for chunks that are currently checked out. */ -static int memsys3Size(void *p){ +int sqlite3MallocSize(void *p){ Mem3Block *pBlock = (Mem3Block*)p; assert( (pBlock[-1].u.hdr.size4x&1)!=0 ); return (pBlock[-1].u.hdr.size4x&~3)*2 - 4; @@ -556,7 +556,7 @@ void *sqlite3_realloc(void *pPrior, int nBytes){ return 0; } assert( mem.mutex!=0 ); - nOld = memsys3Size(pPrior); + nOld = sqlite3MallocSize(pPrior); if( nBytes<=nOld && nBytes>=nOld-128 ){ return pPrior; } @@ -1,4 +1,4 @@ - /* +/* ** 2005 November 29 ** ** The author disclaims copyright to this source code. In place of diff --git a/src/pragma.c b/src/pragma.c index dc7db612b..4019ca77a 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.169 2008/01/22 01:48:09 drh Exp $ +** $Id: pragma.c,v 1.170 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -894,8 +894,8 @@ void sqlite3Pragma( if( cnt==0 ) continue; /* Make sure sufficient number of registers have been allocated */ - if( pParse->nMem < cnt+3 ){ - pParse->nMem = cnt+3; + if( pParse->nMem < cnt+4 ){ + pParse->nMem = cnt+4; } /* Do the b-tree integrity checks */ @@ -905,7 +905,8 @@ void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P4_DYNAMIC); - sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 2); + sqlite3VdbeAddOp2(v, OP_Move, 2, 4); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); diff --git a/src/select.c b/src/select.c index 590f6e685..a6ecc6fc8 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.412 2008/02/06 23:52:37 drh Exp $ +** $Id: select.c,v 1.413 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -810,8 +810,8 @@ static void generateSortTail( int j1; assert( nColumn==1 ); j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRow, &p->affinity, 1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid, &p->affinity, 1); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid); sqlite3VdbeJumpHere(v, j1); break; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f9087f7c9..8a3e6a323 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.660 2008/02/12 16:52:14 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.661 2008/02/13 18:25:27 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1683,6 +1683,7 @@ char *sqlite3DbStrDup(sqlite3*,const char*); char *sqlite3DbStrNDup(sqlite3*,const char*, int); void *sqlite3DbReallocOrFree(sqlite3 *, void *, int); void *sqlite3DbRealloc(sqlite3 *, void *, int); +int sqlite3MallocSize(void *); char *sqlite3MPrintf(sqlite3*,const char*, ...); char *sqlite3VMPrintf(sqlite3*,const char*, va_list); diff --git a/src/tclsqlite.c b/src/tclsqlite.c index a151bb6ac..ebb8c0f7c 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -12,7 +12,7 @@ ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** -** $Id: tclsqlite.c,v 1.207 2007/11/14 06:48:48 danielk1977 Exp $ +** $Id: tclsqlite.c,v 1.208 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "tcl.h" #include <errno.h> @@ -1702,7 +1702,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ switch( sqlite3_column_type(pStmt, i) ){ case SQLITE_BLOB: { int bytes = sqlite3_column_bytes(pStmt, i); - pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes); + char *zBlob = sqlite3_column_blob(pStmt, i); + if( !zBlob ) bytes = 0; + pVal = Tcl_NewByteArrayObj(zBlob, bytes); break; } case SQLITE_INTEGER: { diff --git a/src/test1.c b/src/test1.c index 5fb8fa779..adb979781 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.287 2008/01/23 14:51:50 drh Exp $ +** $Id: test1.c,v 1.288 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -954,16 +954,17 @@ static int test_create_function( /* Use the sqlite3_create_function16() API here. Mainly for fun, but also ** because it is not tested anywhere else. */ if( rc==SQLITE_OK ){ + void *zUtf16; sqlite3_value *pVal; sqlite3_mutex_enter(db->mutex); pVal = sqlite3ValueNew(db); sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC); + zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); if( db->mallocFailed ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_create_function16(db, - sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), - 1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0); + rc = sqlite3_create_function16(db, zUtf16, + 1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0); } sqlite3ValueFree(pVal); sqlite3_mutex_leave(db->mutex); @@ -2152,6 +2153,7 @@ static int test_collate( rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF8, (void *)SQLITE_UTF8, val?test_collate_func:0); if( rc==SQLITE_OK ){ + void *zUtf16; if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR; rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE, (void *)SQLITE_UTF16LE, val?test_collate_func:0); @@ -2165,11 +2167,11 @@ static int test_collate( sqlite3_mutex_enter(db->mutex); pVal = sqlite3ValueNew(db); sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC); + zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); if( db->mallocFailed ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_create_collation16(db, - sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), SQLITE_UTF16BE, + rc = sqlite3_create_collation16(db, zUtf16, SQLITE_UTF16BE, (void *)SQLITE_UTF16BE, val?test_collate_func:0); } sqlite3ValueFree(pVal); diff --git a/src/test8.c b/src/test8.c index 944ac686e..8c49571af 100644 --- a/src/test8.c +++ b/src/test8.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test8.c,v 1.59 2008/01/22 21:30:53 drh Exp $ +** $Id: test8.c,v 1.60 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -160,7 +160,12 @@ static int getColumnNames( */ nBytes = sizeof(char *) * nCol; for(ii=0; ii<nCol; ii++){ - nBytes += (strlen(sqlite3_column_name(pStmt, ii)) + 1); + const char *zName = sqlite3_column_name(pStmt, ii); + if( !zName ){ + rc = SQLITE_NOMEM; + goto out; + } + nBytes += strlen(zName)+1; } aCol = (char **)sqlite3MallocZero(nBytes); if( !aCol ){ @@ -952,11 +957,15 @@ int echoUpdate( if( bindArgOne ){ sqlite3_bind_value(pStmt, 1, apData[1]); } - for(i=2; i<nData; i++){ - if( apData[i] ) sqlite3_bind_value(pStmt, i, apData[i]); + for(i=2; i<nData && rc==SQLITE_OK; i++){ + if( apData[i] ) rc = sqlite3_bind_value(pStmt, i, apData[i]); + } + if( rc==SQLITE_OK ){ + sqlite3_step(pStmt); + rc = sqlite3_finalize(pStmt); + }else{ + sqlite3_finalize(pStmt); } - sqlite3_step(pStmt); - rc = sqlite3_finalize(pStmt); } if( pRowid && rc==SQLITE_OK ){ diff --git a/src/test_malloc.c b/src/test_malloc.c index d581ea3bf..df35b207d 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -13,7 +13,7 @@ ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. ** -** $Id: test_malloc.c,v 1.11 2008/01/31 14:43:24 drh Exp $ +** $Id: test_malloc.c,v 1.12 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -343,6 +343,32 @@ static int test_memdebug_dump( return TCL_OK; } +/* +** Usage: sqlite3_memdebug_malloc_count +** +** Return the total number of times malloc() has been called. +*/ +static int test_memdebug_malloc_count( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int nMalloc = -1; + if( objc!=1 ){ + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } +#if defined(SQLITE_MEMDEBUG) + { + extern int sqlite3_memdebug_malloc_count(); + nMalloc = sqlite3_memdebug_malloc_count(); + } +#endif + Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc)); + return TCL_OK; +} + /* ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? @@ -504,6 +530,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ { "sqlite3_memdebug_fail", test_memdebug_fail }, { "sqlite3_memdebug_pending", test_memdebug_pending }, { "sqlite3_memdebug_settitle", test_memdebug_settitle }, + { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ @@ -12,7 +12,7 @@ ** This file contains routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** -** $Id: utf.c,v 1.59 2007/10/03 08:46:45 danielk1977 Exp $ +** $Id: utf.c,v 1.60 2008/02/13 18:25:27 danielk1977 Exp $ ** ** Notes on UTF-8: ** @@ -188,7 +188,6 @@ int sqlite3Utf8Read( ** encoding, or if *pMem does not contain a string value. */ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ - unsigned char zShort[NBFS]; /* Temporary short output buffer */ int len; /* Maximum length of output string in bytes */ unsigned char *zOut; /* Output buffer */ unsigned char *zIn; /* Input iterator */ @@ -254,19 +253,14 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ /* Set zIn to point at the start of the input buffer and zTerm to point 1 ** byte past the end. ** - ** Variable zOut is set to point at the output buffer. This may be space - ** obtained from sqlite3_malloc(), or Mem.zShort, if it large enough and - ** not in use, or the zShort array on the stack (see above). + ** Variable zOut is set to point at the output buffer, space obtained + ** from sqlite3_malloc(). */ zIn = (u8*)pMem->z; zTerm = &zIn[pMem->n]; - if( len>NBFS ){ - zOut = sqlite3DbMallocRaw(pMem->db, len); - if( !zOut ){ - return SQLITE_NOMEM; - } - }else{ - zOut = zShort; + zOut = sqlite3DbMallocRaw(pMem->db, len); + if( !zOut ){ + return SQLITE_NOMEM; } z = zOut; @@ -308,15 +302,9 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); sqlite3VdbeMemRelease(pMem); - pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); + pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem); pMem->enc = desiredEnc; - if( zOut==zShort ){ - memcpy(pMem->zShort, zOut, len); - zOut = (u8*)pMem->zShort; - pMem->flags |= (MEM_Term|MEM_Short); - }else{ - pMem->flags |= (MEM_Term|MEM_Dyn); - } + pMem->flags |= (MEM_Term|MEM_Dyn); pMem->z = (char*)zOut; translate_out: @@ -355,24 +343,14 @@ int sqlite3VdbeMemHandleBom(Mem *pMem){ } if( bom ){ - /* This function is called as soon as a string is stored in a Mem*, - ** from within sqlite3VdbeMemSetStr(). At that point it is not possible - ** for the string to be stored in Mem.zShort, or for it to be stored - ** in dynamic memory with no destructor. - */ - assert( !(pMem->flags&MEM_Short) ); - assert( !(pMem->flags&MEM_Dyn) || pMem->xDel ); - if( pMem->flags & MEM_Dyn ){ - void (*xDel)(void*) = pMem->xDel; - char *z = pMem->z; - pMem->z = 0; - pMem->xDel = 0; - rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, - SQLITE_TRANSIENT); - xDel(z); - }else{ - rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom, - SQLITE_TRANSIENT); + rc = sqlite3VdbeMemMakeWriteable(pMem); + if( rc==SQLITE_OK ){ + pMem->n -= 2; + memmove(pMem->z, &pMem->z[2], pMem->n); + pMem->z[pMem->n] = '\0'; + pMem->z[pMem->n+1] = '\0'; + pMem->flags |= MEM_Term; + pMem->enc = bom; } } return rc; diff --git a/src/vdbe.c b/src/vdbe.c index 2901752a1..8bcff572a 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.708 2008/02/06 14:11:35 drh Exp $ +** $Id: vdbe.c,v 1.709 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -236,9 +236,8 @@ static void applyNumericAffinity(Mem *pRec){ i64 value; sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8); if( !realnum && sqlite3Atoi64(pRec->z, &value) ){ - sqlite3VdbeMemRelease(pRec); pRec->u.i = value; - pRec->flags = MEM_Int; + MemSetTypeFlag(pRec, MEM_Int); }else{ sqlite3VdbeMemRealify(pRec); } @@ -1000,14 +999,19 @@ case OP_ResultRow: { ** Add the text in register P1 onto the end of the text in ** register P2 and store the result in register P3. ** If either the P1 or P2 text are NULL then store NULL in P3. +** +** P3 = P2 || P1 +** +** It is illegal for P1 and P3 to be the same register. Sometimes, +** if P3 is the same register as P2, the implementation is able +** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ - char *zNew; i64 nByte; + assert( pIn1!=pOut ); if( (pIn1->flags | pIn2->flags) & MEM_Null ){ - Release(pOut); - pOut->flags = MEM_Null; + sqlite3VdbeMemSetNull(pOut); break; } ExpandBlob(pIn1); @@ -1018,20 +1022,19 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ if( nByte>SQLITE_MAX_LENGTH ){ goto too_big; } - zNew = sqlite3DbMallocRaw(db, nByte+2); - if( zNew==0 ){ + MemSetTypeFlag(pOut, MEM_Str); + if( sqlite3VdbeMemGrow(pOut, nByte+2, pOut==pIn2) ){ goto no_mem; } - memcpy(zNew, pIn2->z, pIn2->n); - memcpy(&zNew[pIn2->n], pIn1->z, pIn1->n); - zNew[nByte] = 0; - zNew[nByte+1] = 0; - Release(pOut); + if( pOut!=pIn2 ){ + memcpy(pOut->z, pIn2->z, pIn2->n); + } + memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); + pOut->z[nByte] = 0; + pOut->z[nByte+1] = 0; + pOut->flags |= MEM_Term; pOut->n = nByte; - pOut->flags = MEM_Str|MEM_Dyn|MEM_Term; - pOut->xDel = 0; pOut->enc = encoding; - pOut->z = zNew; UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -1105,9 +1108,8 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ break; } } - Release(pOut); pOut->u.i = b; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); }else{ double a, b; a = sqlite3VdbeRealValue(pIn1); @@ -1133,9 +1135,8 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ if( sqlite3_isnan(b) ){ goto arithmetic_result_is_null; } - Release(pOut); pOut->r = b; - pOut->flags = MEM_Real; + MemSetTypeFlag(pOut, MEM_Real); if( (flags & MEM_Real)==0 ){ sqlite3VdbeIntegerAffinity(pOut); } @@ -1168,6 +1169,7 @@ case OP_CollSeq: { ** Invoke a user function (P4 is a pointer to a Function structure that ** defines the function) with P5 arguments taken from register P2 and ** successors. The result of the function is stored in register P3. +** Register P3 must not be one of the function inputs. ** ** P1 is a 32-bit bitmask indicating whether or not each argument to the ** function was determined to be constant at compile time. If the first @@ -1189,6 +1191,7 @@ case OP_Function: { assert( apVal || n==0 ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem) ); + assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n ); pArg = &p->aMem[pOp->p2]; for(i=0; i<n; i++, pArg++){ apVal[i] = pArg; @@ -1205,10 +1208,18 @@ case OP_Function: { ctx.pFunc = ctx.pVdbeFunc->pFunc; } + assert( pOp->p3>0 && pOp->p3<=p->nMem ); + pOut = &p->aMem[pOp->p3]; ctx.s.flags = MEM_Null; - ctx.s.z = 0; - ctx.s.xDel = 0; - ctx.s.db = db; + ctx.s.db = 0; + + /* The output cell may already have a buffer allocated. Move + ** the pointer to ctx.s so in case the user-function can use + ** the already allocated buffer instead of allocating a new one. + */ + sqlite3VdbeMemMove(&ctx.s, pOut); + MemSetTypeFlag(&ctx.s, MEM_Null); + ctx.isError = 0; if( ctx.pFunc->needCollSeq ){ assert( pOp>p->aOp ); @@ -1250,8 +1261,6 @@ case OP_Function: { /* Copy the result of the function into register P3 */ sqlite3VdbeChangeEncoding(&ctx.s, encoding); - assert( pOp->p3>0 && pOp->p3<=p->nMem ); - pOut = &p->aMem[pOp->p3]; sqlite3VdbeMemMove(pOut, &ctx.s); if( sqlite3VdbeMemTooBig(pOut) ){ goto too_big; @@ -1306,9 +1315,8 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ default: assert( pOp->opcode==OP_ShiftRight ); a >>= b; break; } - Release(pOut); pOut->u.i = a; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); break; } @@ -1350,9 +1358,8 @@ case OP_ForceInt: { /* jump, in1 */ if( pIn1->r>(double)v ) v++; if( pOp->p3 && pIn1->r==(double)v ) v++; } - Release(pIn1); pIn1->u.i = v; - pIn1->flags = MEM_Int; + MemSetTypeFlag(pIn1, MEM_Int); break; } @@ -1373,8 +1380,7 @@ case OP_MustBeInt: { /* jump, in1 */ pc = pOp->p2 - 1; } }else{ - Release(pIn1); - pIn1->flags = MEM_Int; + MemSetTypeFlag(pIn1, MEM_Int); } break; } @@ -1411,7 +1417,7 @@ case OP_ToText: { /* same as TK_TO_TEXT, in1 */ pIn1->flags |= (pIn1->flags&MEM_Blob)>>3; applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); rc = ExpandBlob(pIn1); - assert( pIn1->flags & MEM_Str ); + assert( pIn1->flags & MEM_Str || db->mallocFailed ); pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob); UPDATE_MAX_BLOBSIZE(pIn1); break; @@ -1430,10 +1436,9 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ if( pIn1->flags & MEM_Null ) break; if( (pIn1->flags & MEM_Blob)==0 ){ applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); - assert( pIn1->flags & MEM_Str ); - pIn1->flags |= MEM_Blob; + assert( pIn1->flags & MEM_Str || db->mallocFailed ); } - pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Str); + MemSetTypeFlag(pIn1, MEM_Blob); UPDATE_MAX_BLOBSIZE(pIn1); break; } @@ -1591,8 +1596,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ */ if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &p->aMem[pOp->p2]; - Release(pOut); - pOut->flags = MEM_Null; + MemSetTypeFlag(pOut, MEM_Null); REGISTER_TRACE(pOp->p2, pOut); }else if( pOp->p5 & SQLITE_JUMPIFNULL ){ pc = pOp->p2-1; @@ -1622,8 +1626,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &p->aMem[pOp->p2]; - Release(pOut); - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = res; REGISTER_TRACE(pOp->p2, pOut); }else if( res ){ @@ -1671,12 +1674,11 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 }; v1 = or_logic[v1*3+v2]; } - Release(pOut); if( v1==2 ){ - pOut->flags = MEM_Null; + MemSetTypeFlag(pOut, MEM_Null); }else{ pOut->u.i = v1; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); } break; } @@ -1691,7 +1693,7 @@ case OP_Not: { /* same as TK_NOT, in1 */ if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */ sqlite3VdbeMemIntegerify(pIn1); pIn1->u.i = !pIn1->u.i; - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); break; } @@ -1705,7 +1707,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1 */ if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */ sqlite3VdbeMemIntegerify(pIn1); pIn1->u.i = ~pIn1->u.i; - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); break; } @@ -1823,10 +1825,11 @@ case OP_Column: { Mem sMem; /* For storing the record being decoded */ sMem.flags = 0; + sMem.db = 0; assert( p1<p->nCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pDest = &p->aMem[pOp->p3]; - sqlite3VdbeMemSetNull(pDest); + MemSetTypeFlag(pDest, MEM_Null); /* This block sets the variable payloadSize to be the total number of ** bytes in the record. @@ -1877,7 +1880,7 @@ case OP_Column: { /* If payloadSize is 0, then just store a NULL */ if( payloadSize==0 ){ - assert( pDest->flags==MEM_Null ); + assert( pDest->flags&MEM_Null ); goto op_column_out; } if( payloadSize>SQLITE_MAX_LENGTH ){ @@ -1943,6 +1946,8 @@ case OP_Column: { ** acquire the complete header text. */ if( !zRec && avail<offset ){ + sMem.flags = 0; + sMem.db = 0; rc = sqlite3VdbeMemFromBtree(pCrsr, 0, offset, pC->isIndex, &sMem); if( rc!=SQLITE_OK ){ goto op_column_out; @@ -1994,22 +1999,30 @@ case OP_Column: { if( aOffset[p2] ){ assert( rc==SQLITE_OK ); if( zRec ){ - zData = &zRec[aOffset[p2]]; + if( pDest->flags&MEM_Dyn ){ + sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], &sMem); + sMem.db = db; + sqlite3VdbeMemCopy(pDest, &sMem); + assert( !(sMem.flags&MEM_Dyn) ); + }else{ + sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest); + } }else{ len = sqlite3VdbeSerialTypeLen(aType[p2]); + sqlite3VdbeMemMove(&sMem, pDest); rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex, &sMem); if( rc!=SQLITE_OK ){ goto op_column_out; } zData = sMem.z; + sqlite3VdbeSerialGet((u8*)zData, aType[p2], pDest); } - sqlite3VdbeSerialGet((u8*)zData, aType[p2], pDest); pDest->enc = encoding; }else{ if( pOp->p4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ - assert( pDest->flags==MEM_Null ); + assert( pDest->flags&MEM_Null ); } } @@ -2019,16 +2032,14 @@ case OP_Column: { ** This prevents a memory copy. */ if( (sMem.flags & MEM_Dyn)!=0 ){ - assert( pDest->flags & MEM_Ephem ); - assert( pDest->flags & (MEM_Str|MEM_Blob) ); - assert( pDest->z==sMem.z ); - assert( sMem.flags & MEM_Term ); - pDest->flags &= ~MEM_Ephem; + assert( !sMem.xDel ); + assert( !(pDest->flags & MEM_Dyn) ); + assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z ); + pDest->flags &= ~(MEM_Ephem|MEM_Static); pDest->flags |= MEM_Dyn|MEM_Term; + pDest->z = sMem.z; } - /* pDest->z might be pointing to sMem.zShort[]. Fix that so that we - ** can abandon sMem */ rc = sqlite3VdbeMemMakeWriteable(pDest); op_column_out: @@ -2086,7 +2097,6 @@ case OP_MakeRecord: { char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ int i; /* Space used in zNewRecord[] */ - char zTemp[NBFS]; /* Space to hold small records */ nField = pOp->p1; zAffinity = pOp->p4.z; @@ -2130,15 +2140,17 @@ case OP_MakeRecord: { goto too_big; } - /* Allocate space for the new record. */ - if( nByte>sizeof(zTemp) ){ - zNewRecord = sqlite3DbMallocRaw(db, nByte); - if( !zNewRecord ){ - goto no_mem; - } - }else{ - zNewRecord = (u8*)zTemp; + /* Make sure the output register has a buffer large enough to store + ** the new record. The output register (pOp->p3) is not allowed to + ** be one of the input registers (because the following call to + ** sqlite3VdbeMemGrow() could clobber the value before it is used). + */ + assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 ); + pOut = &p->aMem[pOp->p3]; + if( sqlite3VdbeMemGrow(pOut, nByte, 0) ){ + goto no_mem; } + zNewRecord = (u8 *)pOut->z; /* Write the record */ i = sqlite3PutVarint(zNewRecord, nHdr); @@ -2152,20 +2164,9 @@ case OP_MakeRecord: { assert( i==nByte ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); - pOut = &p->aMem[pOp->p3]; - Release(pOut); pOut->n = nByte; - if( nByte<=sizeof(zTemp) ){ - assert( zNewRecord==(unsigned char *)zTemp ); - pOut->z = pOut->zShort; - memcpy(pOut->zShort, zTemp, nByte); - pOut->flags = MEM_Blob | MEM_Short; - }else{ - assert( zNewRecord!=(unsigned char *)zTemp ); - pOut->z = (char*)zNewRecord; - pOut->flags = MEM_Blob | MEM_Dyn; - pOut->xDel = 0; - } + pOut->flags = MEM_Blob | MEM_Dyn; + pOut->xDel = 0; if( nZero ){ pOut->u.i = nZero; pOut->flags |= MEM_Zero; @@ -2343,7 +2344,7 @@ case OP_ReadCookie: { /* out2-prerelease */ */ rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, 1 + iCookie, (u32 *)&iMeta); pOut->u.i = iMeta; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); break; } @@ -2896,7 +2897,6 @@ case OP_IsUnique: { /* jump, in3 */ pK = &p->aMem[pOp->p4.i]; sqlite3VdbeMemIntegerify(pIn3); R = pIn3->u.i; - assert( (pIn3->flags & MEM_Dyn)==0 ); assert( i>=0 && i<p->nCursor ); pCx = p->apCsr[i]; assert( pCx!=0 ); @@ -2960,7 +2960,7 @@ case OP_IsUnique: { /* jump, in3 */ ** a UNIQUE constraint.) */ pIn3->u.i = v; - assert( pIn3->flags==MEM_Int ); + assert( pIn3->flags&MEM_Int ); } break; } @@ -3021,7 +3021,7 @@ case OP_Sequence: { /* out2-prerelease */ assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); pOut->u.i = p->apCsr[i]->seqCount++; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); break; } @@ -3174,7 +3174,7 @@ case OP_NewRowid: { /* out2-prerelease */ pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = v; break; } @@ -3368,13 +3368,15 @@ case OP_ResetCount: { ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. */ -case OP_RowKey: /* out2-prerelease */ -case OP_RowData: { /* out2-prerelease */ +case OP_RowKey: +case OP_RowData: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; u32 n; + pOut = &p->aMem[pOp->p2]; + /* Note that RowKey and RowData are really exactly the same instruction */ assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; @@ -3401,17 +3403,11 @@ case OP_RowData: { /* out2-prerelease */ goto too_big; } } - pOut->n = n; - if( n<=NBFS ){ - pOut->flags = MEM_Blob | MEM_Short; - pOut->z = pOut->zShort; - }else{ - char *z = sqlite3_malloc( n ); - if( z==0 ) goto no_mem; - pOut->flags = MEM_Blob | MEM_Dyn; - pOut->xDel = 0; - pOut->z = z; + if( sqlite3VdbeMemGrow(pOut, n, 0) ){ + goto no_mem; } + pOut->n = n; + MemSetTypeFlag(pOut, MEM_Blob); if( pC->isIndex ){ rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z); }else{ @@ -3450,7 +3446,7 @@ case OP_Rowid: { /* out2-prerelease */ v = keyToInt(v); } pOut->u.i = v; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); break; } @@ -3642,8 +3638,9 @@ case OP_IdxInsert: { /* in2 */ /* Opcode: IdxDelete P1 P2 * * * ** -** The content of register P2 is an index key built using the either the -** MakeIdxRec opcode. Removes that entry from the index. +** The content of register P2 is an index key built using the +** MakeIdxRec opcode. This opcode removes that entry from the +** index opened by cursor P1. */ case OP_IdxDelete: { /* in2 */ int i = pOp->p1; @@ -3689,7 +3686,7 @@ case OP_IdxRowid: { /* out2-prerelease */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = rowid; } } @@ -3801,7 +3798,7 @@ case OP_Destroy: { /* out2-prerelease */ assert( iCnt==1 ); assert( (p->btreeMask & (1<<iDb))!=0 ); rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = iMoved; #ifndef SQLITE_OMIT_AUTOVACUUM if( rc==SQLITE_OK && iMoved!=0 ){ @@ -3870,7 +3867,7 @@ case OP_CreateTable: { /* out2-prerelease */ rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags); if( rc==SQLITE_OK ){ pOut->u.i = pgno; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); } break; } @@ -4023,12 +4020,8 @@ case OP_IntegrityCk: { if( nErr==0 ){ assert( z==0 ); }else{ - pIn1->z = z; - pIn1->n = strlen(z); - pIn1->flags = MEM_Str | MEM_Dyn | MEM_Term; - pIn1->xDel = 0; + sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free); } - pIn1->enc = SQLITE_UTF8; UPDATE_MAX_BLOBSIZE(pIn1); sqlite3VdbeChangeEncoding(pIn1, encoding); sqlite3_free(aRoot); @@ -4058,8 +4051,7 @@ case OP_FifoRead: { /* jump */ CHECK_FOR_INTERRUPT; assert( pOp->p1>0 && pOp->p1<=p->nMem ); pOut = &p->aMem[pOp->p1]; - Release(pOut); - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); if( sqlite3VdbeFifoPop(&p->sFifo, &pOut->u.i)==SQLITE_DONE ){ pc = pOp->p2 - 1; } @@ -4137,7 +4129,7 @@ case OP_MemMax: { /* in1, in2 */ ** not contain an integer. An assertion fault will result if you try. */ case OP_IfPos: { /* jump, in1 */ - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); if( pIn1->u.i>0 ){ pc = pOp->p2 - 1; } @@ -4152,7 +4144,7 @@ case OP_IfPos: { /* jump, in1 */ ** not contain an integer. An assertion fault will result if you try. */ case OP_IfNeg: { /* jump, in1 */ - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); if( pIn1->u.i<0 ){ pc = pOp->p2 - 1; } @@ -4167,7 +4159,7 @@ case OP_IfNeg: { /* jump, in1 */ ** not contain an integer. An assertion fault will result if you try. */ case OP_IfZero: { /* jump, in1 */ - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); if( pIn1->u.i==0 ){ pc = pOp->p2 - 1; } @@ -4502,7 +4494,7 @@ case OP_VRowid: { /* out2-prerelease */ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xRowid(pCur->pVtabCursor, &iRow); if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = iRow; break; } @@ -4531,8 +4523,15 @@ case OP_VColumn: { pModule = pCur->pVtabCursor->pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); - sContext.s.flags = MEM_Null; - sContext.s.db = db; + + /* The output cell may already have a buffer allocated. Move + ** the current contents to sContext.s so in case the user-function + ** can use the already allocated buffer instead of allocating a + ** new one. + */ + sqlite3VdbeMemMove(&sContext.s, pDest); + MemSetTypeFlag(&sContext.s, MEM_Null); + if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 407ed49c9..ca9c39f07 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -95,13 +95,6 @@ struct Cursor { typedef struct Cursor Cursor; /* -** Number of bytes of string storage space available to each stack -** layer without having to malloc. NBFS is short for Number of Bytes -** For Strings. -*/ -#define NBFS 32 - -/* ** A value for Cursor.cacheValid that means the cache is always invalid. */ #define CACHE_STALE 0 @@ -130,7 +123,6 @@ struct Mem { u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ - char zShort[NBFS]; /* Space for short strings */ }; /* One or more of the following flags are set to indicate the validOK @@ -154,6 +146,9 @@ struct Mem { #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ +#define MemSetTypeFlag(p, f) \ + ((p)->flags = ((p)->flags&~(MEM_Int|MEM_Real|MEM_Null|MEM_Blob|MEM_Str))|f) + /* Whenever Mem contains a valid string or blob representation, one of ** the following flags must be set to determine the memory management ** policy for Mem.z. The MEM_Term flag tells us whether or not the @@ -163,7 +158,6 @@ struct Mem { #define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */ #define MEM_Static 0x0080 /* Mem.z points to a static string */ #define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ -#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */ #define MEM_Agg 0x0400 /* Mem.z points to an agg function context */ #define MEM_Zero 0x0800 /* Mem.i contains count of 0s appended to blob */ @@ -398,6 +392,7 @@ void sqlite3VdbeMemRelease(Mem *p); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeOpcodeHasProperty(int, int); +int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); #ifndef NDEBUG void sqlite3VdbeMemSanity(Mem*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index e756c7051..8b4283d94 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -944,6 +944,7 @@ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ if( rc==SQLITE_OK ){ rc = sqlite3VdbeMemCopy(&p->aVar[i-1], pValue); } + rc = sqlite3ApiExit(p->db, rc); sqlite3_mutex_leave(p->db->mutex); return rc; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index c15207b9b..ca368b6ec 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -735,11 +735,15 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ ** Release an array of N Mem elements */ static void releaseMemArray(Mem *p, int N){ - if( p ){ + if( p && N ){ + sqlite3 *db = p->db; + int malloc_failed = db->mallocFailed; while( N-->0 ){ assert( N<2 || p[0].db==p[1].db ); - sqlite3VdbeMemSetNull(p++); + sqlite3VdbeMemRelease(p); + p++->flags = MEM_Null; } + db->mallocFailed = malloc_failed; } } @@ -786,6 +790,7 @@ int sqlite3VdbeList( rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0); }else{ + char *z; Op *pOp = &p->aOp[i]; if( p->explain==1 ){ pMem->flags = MEM_Int; @@ -819,18 +824,29 @@ int sqlite3VdbeList( pMem++; } - pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P4 */ - pMem->z = displayP4(pOp, pMem->zShort, sizeof(pMem->zShort)); - assert( pMem->z!=0 ); - pMem->n = strlen(pMem->z); + if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */ + p->db->mallocFailed = 1; + return SQLITE_NOMEM; + } + pMem->flags = MEM_Dyn|MEM_Str|MEM_Term; + z = displayP4(pOp, pMem->z, 32); + if( z!=pMem->z ){ + sqlite3VdbeMemSetStr(pMem, z, -1, SQLITE_UTF8, 0); + }else{ + assert( pMem->z!=0 ); + pMem->n = strlen(pMem->z); + pMem->enc = SQLITE_UTF8; + } pMem->type = SQLITE_TEXT; - pMem->enc = SQLITE_UTF8; pMem++; if( p->explain==1 ){ - pMem->flags = MEM_Str|MEM_Term|MEM_Short; - pMem->n = sprintf(pMem->zShort, "%.2x", pOp->p5); /* P5 */ - pMem->z = pMem->zShort; + if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ + p->db->mallocFailed = 1; + return SQLITE_NOMEM; + } + pMem->flags = MEM_Dyn|MEM_Str|MEM_Term; + pMem->n = sprintf(pMem->z, "%.2x", pOp->p5); /* P5 */ pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; pMem++; @@ -1058,6 +1074,9 @@ static void closeAllCursorsExceptActiveVtabs(Vdbe *p){ static void Cleanup(Vdbe *p){ int i; closeAllCursorsExceptActiveVtabs(p); + for(i=1; i<=p->nMem; i++){ + MemSetTypeFlag(&p->aMem[i], MEM_Null); + } releaseMemArray(&p->aMem[1], p->nMem); sqlite3VdbeFifoClear(&p->sFifo); if( p->contextStack ){ @@ -2133,8 +2152,10 @@ int sqlite3VdbeRecordCompare( Mem mem2; mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; + mem1.flags = 0; mem2.enc = pKeyInfo->enc; mem2.db = pKeyInfo->db; + mem2.flags = 0; idx1 = GetVarint(aKey1, szHdr1); d1 = szHdr1; @@ -2159,8 +2180,8 @@ int sqlite3VdbeRecordCompare( /* Do the comparison */ rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0); - if( mem1.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem1); - if( mem2.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem2); + if( mem1.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem1); + if( mem2.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem2); if( rc!=0 ){ break; } @@ -2222,6 +2243,8 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ if( nCellKey<=0 ){ return SQLITE_CORRUPT_BKPT; } + m.flags = 0; + m.db = 0; rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m); if( rc ){ return rc; @@ -2261,6 +2284,8 @@ int sqlite3VdbeIdxKeyCompare( *res = 0; return SQLITE_OK; } + m.db = 0; + m.flags = 0; rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m); if( rc ){ return rc; diff --git a/src/vdbemem.c b/src/vdbemem.c index fa407b671..d620aa2e5 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -60,32 +60,82 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ } /* +** Make sure pMem->z points to a writable allocation of at least +** n bytes. +** +** If the memory cell currently contains string or blob data +** and the third argument passed to this function is true, the +** current content of the cell is preserved. Otherwise, it may +** be discarded. +** +** This function sets the MEM_Dyn flag and clears any xDel callback. +** It also clears MEM_Ephem and MEM_Static. If the preserve flag is +** not set, Mem.n is zeroed. +*/ +int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){ + int f = pMem->flags; + + assert( (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==0 + || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Dyn + || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Ephem + || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Static + ); + + if( ((f&MEM_Dyn)==0 || pMem->xDel || sqlite3MallocSize(pMem->z)<n) ){ + + /* Allocate the new buffer. The minimum allocation size is 32 bytes. */ + char *z = 0; + if( n>0 ){ + if( preserve && (f&MEM_Dyn) && !pMem->xDel ){ + z = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); + pMem->z = 0; + preserve = 0; + }else{ + z = sqlite3DbMallocRaw(pMem->db, (n>32?n:32)); + } + if( !z ){ + return SQLITE_NOMEM; + } + } + + /* If the value is currently a string or blob and the preserve flag + ** is true, copy the content to the new buffer. + */ + if( pMem->flags&(MEM_Blob|MEM_Str) && preserve ){ + int nCopy = (pMem->n>n?n:pMem->n); + memcpy(z, pMem->z, nCopy); + } + + /* Release the old buffer. */ + sqlite3VdbeMemRelease(pMem); + + pMem->z = z; + pMem->flags |= MEM_Dyn; + pMem->flags &= ~(MEM_Ephem|MEM_Static); + pMem->xDel = 0; + } + return SQLITE_OK; +} + +/* ** Make the given Mem object MEM_Dyn. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemDynamicify(Mem *pMem){ - int n; - u8 *z; + int f; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); expandBlob(pMem); - if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){ - return SQLITE_OK; - } - assert( (pMem->flags & MEM_Dyn)==0 ); - n = pMem->n; - assert( pMem->flags & (MEM_Str|MEM_Blob) ); - z = sqlite3DbMallocRaw(pMem->db, n+2 ); - if( z==0 ){ - return SQLITE_NOMEM; + f = pMem->flags; + if( (f&(MEM_Str|MEM_Blob)) && ((f&MEM_Dyn)==0 || pMem->xDel) ){ + if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ + return SQLITE_NOMEM; + } + pMem->z[pMem->n] = 0; + pMem->z[pMem->n+1] = 0; + pMem->flags |= MEM_Term; } - pMem->flags |= MEM_Dyn|MEM_Term; - pMem->xDel = 0; - memcpy(z, pMem->z, n ); - z[n] = 0; - z[n+1] = 0; - pMem->z = (char*)z; - pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short); + return SQLITE_OK; } @@ -96,24 +146,22 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){ #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *pMem){ if( pMem->flags & MEM_Zero ){ - char *pNew; int nByte; - assert( (pMem->flags & MEM_Blob)!=0 ); - nByte = pMem->n + pMem->u.i; - if( nByte<=0 ) nByte = 1; + assert( pMem->flags&MEM_Blob ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - pNew = sqlite3DbMallocRaw(pMem->db, nByte); - if( pNew==0 ){ + + /* Set nByte to the number of bytes required to store the expanded blob. */ + nByte = pMem->n + pMem->u.i; + if( nByte<=0 ){ + nByte = 1; + } + if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ return SQLITE_NOMEM; } - memcpy(pNew, pMem->z, pMem->n); - memset(&pNew[pMem->n], 0, pMem->u.i); - sqlite3VdbeMemRelease(pMem); - pMem->z = pNew; + + memset(&pMem->z[pMem->n], 0, pMem->u.i); pMem->n += pMem->u.i; - pMem->u.i = 0; - pMem->flags &= ~(MEM_Zero|MEM_Static|MEM_Ephem|MEM_Short|MEM_Term); - pMem->flags |= MEM_Dyn; + pMem->flags &= ~(MEM_Zero|MEM_Term); } return SQLITE_OK; } @@ -127,33 +175,7 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){ ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ - int n; - u8 *z; - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - expandBlob(pMem); - if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){ - return SQLITE_OK; - } - assert( (pMem->flags & MEM_Dyn)==0 ); - assert( pMem->flags & (MEM_Str|MEM_Blob) ); - if( (n = pMem->n)+2<sizeof(pMem->zShort) ){ - z = (u8*)pMem->zShort; - pMem->flags |= MEM_Short|MEM_Term; - }else{ - z = sqlite3DbMallocRaw(pMem->db, n+2 ); - if( z==0 ){ - return SQLITE_NOMEM; - } - pMem->flags |= MEM_Dyn|MEM_Term; - pMem->xDel = 0; - } - memcpy(z, pMem->z, n ); - z[n] = 0; - z[n+1] = 0; - pMem->z = (char*)z; - pMem->flags &= ~(MEM_Ephem|MEM_Static); - assert(0==(1&(int)pMem->z)); - return SQLITE_OK; + return sqlite3VdbeMemDynamicify(pMem); } /* @@ -164,27 +186,12 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){ if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){ return SQLITE_OK; /* Nothing to do */ } - if( pMem->flags & (MEM_Static|MEM_Ephem) ){ - return sqlite3VdbeMemMakeWriteable(pMem); - }else{ - char *z; - sqlite3VdbeMemExpandBlob(pMem); - z = sqlite3DbMallocRaw(pMem->db, pMem->n+2); - if( !z ){ - return SQLITE_NOMEM; - } - memcpy(z, pMem->z, pMem->n); - z[pMem->n] = 0; - z[pMem->n+1] = 0; - if( pMem->xDel ){ - pMem->xDel(pMem->z); - }else{ - sqlite3_free(pMem->z); - } - pMem->xDel = 0; - pMem->z = z; - pMem->flags |= MEM_Term; + if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ + return SQLITE_NOMEM; } + pMem->z[pMem->n] = 0; + pMem->z[pMem->n+1] = 0; + pMem->flags |= MEM_Term; return SQLITE_OK; } @@ -204,29 +211,32 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){ int sqlite3VdbeMemStringify(Mem *pMem, int enc){ int rc = SQLITE_OK; int fg = pMem->flags; - char *z = pMem->zShort; + const int nByte = 32; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(fg&MEM_Zero) ); assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( fg&(MEM_Int|MEM_Real) ); - /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 + if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + return SQLITE_NOMEM; + } + + /* For a Real or Integer, use sqlite3_mprintf() to produce the UTF-8 ** string representation of the value. Then, if the required encoding ** is UTF-16le or UTF-16be do a translation. ** ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. */ if( fg & MEM_Int ){ - sqlite3_snprintf(NBFS, z, "%lld", pMem->u.i); + sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); }else{ assert( fg & MEM_Real ); - sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r); + sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->r); } - pMem->n = strlen(z); - pMem->z = z; + pMem->n = strlen(pMem->z); pMem->enc = SQLITE_UTF8; - pMem->flags |= MEM_Str | MEM_Short | MEM_Term; + pMem->flags |= MEM_Str|MEM_Term; sqlite3VdbeChangeEncoding(pMem, enc); return rc; } @@ -246,19 +256,15 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); ctx.s.flags = MEM_Null; - ctx.s.z = pMem->zShort; ctx.s.db = pMem->db; ctx.pMem = pMem; ctx.pFunc = pFunc; ctx.isError = 0; pFunc->xFinalize(&ctx); - if( pMem->z && pMem->z!=pMem->zShort ){ + if( pMem->z ){ sqlite3_free( pMem->z ); } *pMem = ctx.s; - if( pMem->flags & MEM_Short ){ - pMem->z = pMem->zShort; - } rc = (ctx.isError?SQLITE_ERROR:SQLITE_OK); } return rc; @@ -394,14 +400,17 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){ } } +static void setTypeFlag(Mem *pMem, int f){ + MemSetTypeFlag(pMem, f); +} + /* ** Convert pMem to type integer. Invalidate any prior representations. */ int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); pMem->u.i = sqlite3VdbeIntValue(pMem); - sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Int; + setTypeFlag(pMem, MEM_Int); return SQLITE_OK; } @@ -412,8 +421,7 @@ int sqlite3VdbeMemIntegerify(Mem *pMem){ int sqlite3VdbeMemRealify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); pMem->r = sqlite3VdbeRealValue(pMem); - sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Real; + setTypeFlag(pMem, MEM_Real); return SQLITE_OK; } @@ -434,8 +442,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){ sqlite3VdbeMemIntegerify(pMem); }else{ pMem->r = r1; - pMem->flags = MEM_Real; - sqlite3VdbeMemRelease(pMem); + setTypeFlag(pMem, MEM_Real); } return SQLITE_OK; } @@ -444,10 +451,8 @@ int sqlite3VdbeMemNumerify(Mem *pMem){ ** Delete any previous value and set the value stored in *pMem to NULL. */ void sqlite3VdbeMemSetNull(Mem *pMem){ - sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Null; + setTypeFlag(pMem, MEM_Null); pMem->type = SQLITE_NULL; - pMem->n = 0; } /* @@ -456,12 +461,12 @@ void sqlite3VdbeMemSetNull(Mem *pMem){ */ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Blob|MEM_Zero|MEM_Short; + setTypeFlag(pMem, MEM_Blob); + pMem->flags = MEM_Blob|MEM_Zero; pMem->type = SQLITE_BLOB; pMem->n = 0; if( n<0 ) n = 0; pMem->u.i = n; - pMem->z = pMem->zShort; pMem->enc = SQLITE_UTF8; } @@ -514,10 +519,10 @@ int sqlite3VdbeMemTooBig(Mem *p){ */ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ sqlite3VdbeMemRelease(pTo); - memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); + memcpy(pTo, pFrom, sizeof(*pFrom)); pTo->xDel = 0; - if( pTo->flags & (MEM_Str|MEM_Blob) ){ - pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short|MEM_Ephem); + if( pTo->flags&MEM_Dyn ){ + pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); pTo->flags |= srcType; } @@ -528,12 +533,46 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ ** freed before the copy is made. */ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ - int rc; - sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem); - if( pTo->flags & MEM_Ephem ){ - rc = sqlite3VdbeMemMakeWriteable(pTo); + int rc = SQLITE_OK; + char *zBuf = 0; + + /* If cell pTo currently has a reusable buffer, save a pointer to it + ** in local variable zBuf. This function attempts to avoid freeing + ** this buffer. + */ + if( pTo->xDel ){ + sqlite3VdbeMemRelease(pTo); + }else if( pTo->flags&MEM_Dyn ){ + zBuf = pTo->z; + } + + /* Copy the contents of *pFrom to *pTo */ + memcpy(pTo, pFrom, sizeof(*pFrom)); + + if( pTo->flags&(MEM_Str|MEM_Blob) && pTo->flags&MEM_Static ){ + /* pFrom contained a pointer to a static string. In this case, + ** free any dynamically allocated buffer associated with pTo. + */ + sqlite3_free(zBuf); }else{ - rc = SQLITE_OK; + char *zData = pTo->z; + + pTo->z = zBuf; + pTo->flags &= ~(MEM_Static|MEM_Ephem); + pTo->flags |= MEM_Dyn; + pTo->xDel = 0; + + if( pTo->flags&(MEM_Str|MEM_Blob) ){ + if( sqlite3VdbeMemGrow(pTo, pTo->n+2, 0) ){ + pTo->n = 0; + rc = SQLITE_NOMEM; + }else{ + memcpy(pTo->z, zData, pTo->n); + pTo->z[pTo->n] = '\0'; + pTo->z[pTo->n+1] = '\0'; + pTo->flags |= MEM_Term; + } + } } return rc; } @@ -552,15 +591,18 @@ void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ sqlite3VdbeMemRelease(pTo); } memcpy(pTo, pFrom, sizeof(Mem)); - if( pFrom->flags & MEM_Short ){ - pTo->z = pTo->zShort; - } pFrom->flags = MEM_Null; pFrom->xDel = 0; } /* ** Change the value of a Mem to be a string or a BLOB. +** +** The memory management strategy depends on the value of the xDel +** parameter. If the value passed is SQLITE_TRANSIENT, then the +** string is copied into a (possibly existing) buffer managed by the +** Mem structure. Otherwise, any existing buffer is freed and the +** pointer copied. */ int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */ @@ -569,59 +611,56 @@ int sqlite3VdbeMemSetStr( u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ + int nByte = n; /* New value for pMem->n */ + int flags = 0; /* New value for pMem->flags */ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - sqlite3VdbeMemRelease(pMem); + + /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ - pMem->flags = MEM_Null; - pMem->type = SQLITE_NULL; + sqlite3VdbeMemSetNull(pMem); return SQLITE_OK; } - pMem->z = (char *)z; - if( xDel==SQLITE_STATIC ){ - pMem->flags = MEM_Static; - }else if( xDel==SQLITE_TRANSIENT ){ - pMem->flags = MEM_Ephem; + + flags = (enc==0?MEM_Blob:MEM_Str); + if( nByte<0 ){ + assert( enc!=0 ); + nByte = ((enc==SQLITE_UTF8)?strlen(z):sqlite3Utf16ByteLen(z, -1)); + flags |= MEM_Term; + } + + /* The following block sets the new values of Mem.z and Mem.xDel. It + ** also sets a flag in local variable "flags" to indicate the memory + ** management (one of MEM_Dyn or MEM_Static). + */ + if( xDel==SQLITE_TRANSIENT ){ + int nAlloc = nByte; + if( flags&MEM_Term ){ + nAlloc += (enc==SQLITE_UTF8?1:2); + } + if( sqlite3VdbeMemGrow(pMem, nAlloc, 0) ){ + return SQLITE_NOMEM; + } + memcpy(pMem->z, z, nAlloc); + flags |= MEM_Dyn; }else{ - pMem->flags = MEM_Dyn; + sqlite3VdbeMemRelease(pMem); + pMem->z = (char *)z; pMem->xDel = xDel; + flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); } - pMem->enc = enc; - pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT; - pMem->n = n; - - assert( enc==0 || enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE - || enc==SQLITE_UTF16BE ); - switch( enc ){ - case 0: - pMem->flags |= MEM_Blob; - pMem->enc = SQLITE_UTF8; - break; - - case SQLITE_UTF8: - pMem->flags |= MEM_Str; - if( n<0 ){ - pMem->n = strlen(z); - pMem->flags |= MEM_Term; - } - break; + pMem->n = nByte; + pMem->flags = flags; + pMem->enc = (enc==0 ? SQLITE_UTF8 : enc); + pMem->type = (enc==0 ? SQLITE_BLOB : SQLITE_TEXT); #ifndef SQLITE_OMIT_UTF16 - case SQLITE_UTF16LE: - case SQLITE_UTF16BE: - pMem->flags |= MEM_Str; - if( pMem->n<0 ){ - pMem->n = sqlite3Utf16ByteLen(pMem->z,-1); - pMem->flags |= MEM_Term; - } - if( sqlite3VdbeMemHandleBom(pMem) ){ - return SQLITE_NOMEM; - } -#endif /* SQLITE_OMIT_UTF16 */ - } - if( pMem->flags&MEM_Ephem ){ - return sqlite3VdbeMemMakeWriteable(pMem); + if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ + return SQLITE_NOMEM; } +#endif + return SQLITE_OK; } @@ -769,6 +808,7 @@ int sqlite3VdbeMemFromBtree( char *zData; /* Data from the btree layer */ int available = 0; /* Number of bytes available on the local btree page */ sqlite3 *db; /* Database connection */ + int rc = SQLITE_OK; db = sqlite3BtreeCursorDb(pCur); assert( sqlite3_mutex_held(db->mutex) ); @@ -779,49 +819,28 @@ int sqlite3VdbeMemFromBtree( } assert( zData!=0 ); - pMem->db = db; - pMem->n = amt; - if( offset+amt<=available ){ + if( offset+amt<=available && ((pMem->flags&MEM_Dyn)==0 || pMem->xDel) ){ + sqlite3VdbeMemRelease(pMem); pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; - }else{ - int rc; - if( amt>NBFS-2 ){ - zData = (char *)sqlite3DbMallocRaw(db, amt+2); - if( !zData ){ - return SQLITE_NOMEM; - } - pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term; - pMem->xDel = 0; - }else{ - zData = &(pMem->zShort[0]); - pMem->flags = MEM_Blob|MEM_Short|MEM_Term; - } - pMem->z = zData; + }else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){ + pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term; pMem->enc = 0; pMem->type = SQLITE_BLOB; - if( key ){ - rc = sqlite3BtreeKey(pCur, offset, amt, zData); + rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z); }else{ - rc = sqlite3BtreeData(pCur, offset, amt, zData); + rc = sqlite3BtreeData(pCur, offset, amt, pMem->z); } - zData[amt] = 0; - zData[amt+1] = 0; + pMem->z[amt] = 0; + pMem->z[amt+1] = 0; if( rc!=SQLITE_OK ){ - if( amt>NBFS-2 ){ - assert( zData!=pMem->zShort ); - assert( pMem->flags & MEM_Dyn ); - sqlite3_free(zData); - } else { - assert( zData==pMem->zShort ); - assert( pMem->flags & MEM_Short ); - } - return rc; + sqlite3VdbeMemRelease(pMem); } } + pMem->n = amt; - return SQLITE_OK; + return rc; } #if 0 @@ -1019,7 +1038,7 @@ void sqlite3ValueSetStr( */ void sqlite3ValueFree(sqlite3_value *v){ if( !v ) return; - sqlite3ValueSetStr(v, 0, 0, SQLITE_UTF8, SQLITE_STATIC); + sqlite3VdbeMemRelease((Mem *)v); sqlite3_free(v); } diff --git a/test/mallocB.test b/test/mallocB.test index 90888579f..72e89c936 100644 --- a/test/mallocB.test +++ b/test/mallocB.test @@ -13,7 +13,7 @@ # that they have little in common. # # -# $Id: mallocB.test,v 1.7 2008/01/17 20:26:47 drh Exp $ +# $Id: mallocB.test,v 1.8 2008/02/13 18:25:27 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -31,7 +31,7 @@ source $testdir/malloc_common.tcl do_malloc_test mallocB-1 -sqlbody {SELECT - 456} do_malloc_test mallocB-2 -sqlbody {SELECT - 456.1} do_malloc_test mallocB-3 -sqlbody {SELECT random()} -do_malloc_test mallocB-4 -sqlbody {SELECT zeroblob(1000)} +do_malloc_test mallocB-4 -sqlbody {SELECT length(zeroblob(1000))} ifcapable subquery { do_malloc_test mallocB-5 -sqlbody {SELECT * FROM (SELECT 1) GROUP BY 1;} } diff --git a/test/ptrchng.test b/test/ptrchng.test index 69bc19351..406f2e252 100644 --- a/test/ptrchng.test +++ b/test/ptrchng.test @@ -21,7 +21,7 @@ # sqlite3_value_bytes() # sqlite3_value_bytes16() # -# $Id: ptrchng.test,v 1.2 2007/09/12 17:01:45 danielk1977 Exp $ +# $Id: ptrchng.test,v 1.3 2008/02/13 18:25:27 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -52,6 +52,8 @@ do_test ptrchng-1.1 { # For the short entries that fit in the Mem.zBuf[], the pointer should # never change regardless of what type conversions occur. # +# UPDATE: No longer true, as Mem.zBuf[] has been removed. +# do_test ptrchng-2.1 { execsql { SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=1 @@ -61,18 +63,18 @@ do_test ptrchng-2.2 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=1 } -} {0} +} {1} ifcapable utf16 { do_test ptrchng-2.3 { execsql { SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=1 } - } {0} + } {1} do_test ptrchng-2.4 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=1 } - } {0} + } {1} do_test ptrchng-2.5 { execsql { SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=1 @@ -82,7 +84,7 @@ ifcapable utf16 { execsql { SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=1 } - } {0} + } {1} } do_test ptrchng-2.11 { execsql { @@ -93,18 +95,18 @@ do_test ptrchng-2.12 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=3 } -} {0} +} {1} ifcapable utf16 { do_test ptrchng-2.13 { execsql { SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=3 } - } {0} + } {1} do_test ptrchng-2.14 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=3 } - } {0} + } {1} do_test ptrchng-2.15 { execsql { SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=3 @@ -115,7 +117,7 @@ btree_breakpoint execsql { SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=3 } - } {0} + } {1} } # For the long entries that do not fit in the Mem.zBuf[], the pointer @@ -130,7 +132,7 @@ do_test ptrchng-3.2 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=2 } -} {0} +} {1} ifcapable utf16 { do_test ptrchng-3.3 { execsql { @@ -162,7 +164,7 @@ do_test ptrchng-3.12 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=4 } -} {0} +} {1} ifcapable utf16 { do_test ptrchng-3.13 { execsql { diff --git a/test/tester.tcl b/test/tester.tcl index 618026b00..e0c2a50c9 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -11,7 +11,7 @@ # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.103 2008/02/08 18:25:30 danielk1977 Exp $ +# $Id: tester.tcl,v 1.104 2008/02/13 18:25:27 danielk1977 Exp $ set tcl_precision 15 @@ -227,6 +227,9 @@ proc finalize_testing {} { } puts "Maximum memory usage: [sqlite3_memory_highwater 1] bytes" puts "Current memory usage: [sqlite3_memory_highwater] bytes" + if {[info commands sqlite3_memdebug_malloc_count] ne ""} { + puts "Number of malloc() : [sqlite3_memdebug_malloc_count] calls" + } foreach f [glob -nocomplain test.db-*-journal] { file delete -force $f } |