diff --git a/VERSION b/VERSION index 30291cba22..afad818663 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.10.0 +3.11.0 diff --git a/configure b/configure index 174f41ae24..850d986306 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for sqlite 3.10.0. +# Generated by GNU Autoconf 2.69 for sqlite 3.11.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -726,8 +726,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.10.0' -PACKAGE_STRING='sqlite 3.10.0' +PACKAGE_VERSION='3.11.0' +PACKAGE_STRING='sqlite 3.11.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1460,7 +1460,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures sqlite 3.10.0 to adapt to many kinds of systems. +\`configure' configures sqlite 3.11.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1525,7 +1525,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.10.0:";; + short | recursive ) echo "Configuration of sqlite 3.11.0:";; esac cat <<\_ACEOF @@ -1646,7 +1646,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.10.0 +sqlite configure 3.11.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2065,7 +2065,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sqlite $as_me 3.10.0, which was +It was created by sqlite $as_me 3.11.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12023,7 +12023,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sqlite $as_me 3.10.0, which was +This file was extended by sqlite $as_me 3.11.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -12089,7 +12089,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -sqlite config.status 3.10.0 +sqlite config.status 3.11.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/manifest b/manifest index 6158acb724..5a749962b4 100644 --- a/manifest +++ b/manifest @@ -1,10 +1,10 @@ -C Add\sthe\sfts5speed.tcl\sscript\sto\sext/fts5/tool/. -D 2016-01-11T18:23:07.397 +C Merge\strunk\swith\sthis\sbranch. +D 2016-01-11T18:30:34.152 F Makefile.in 7c8cc4c2f0179efc6fa9492141d1fb65f4807054 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc e45d8b9b56dfa3f2cd860b2c28bd9d304513b042 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 -F VERSION 8b9d3ac6f1962f94e06ba05462422a544f9c4e36 +F VERSION 866588d1edf0ccb5b0d33896974338f97564f719 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90 @@ -29,7 +29,7 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 42b71ad3fe21c9e88fa59e8458ca1a6bc72eb0c0 F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure e511ceefe595e35051933a90c848ab4fa1d48add x +F configure b4519bb54fff37e7cde9d03d8f2946f18d5d0086 x F configure.ac fcfc67b323d32daaa3e46cf7782d9465ed423a6d F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 @@ -280,21 +280,21 @@ F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395 F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 2869a76c03eb393ee795416e2387005553df72bc F src/bitvec.c 1a78d450a17c5016710eec900bedfc5729bf9bdf -F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 -F src/btree.c 4d3452b2a3daf875490ac4f0a278da7f85fabe12 -F src/btree.h 2d76dee44704c47eed323356a758662724b674a0 +F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73 +F src/btree.c 6bd9b3d778a023e2238a81cd0b87b00085220e0e +F src/btree.h 68ef301795e00cdf1d3ab93abc44a43b7fe771e0 F src/btreeInt.h b5f2651b41808f038dee9282c5dc0232ce6532d3 -F src/build.c d8006e9030c61b9495d0b2f724edd3fcdae16930 +F src/build.c 9d497ff4bf3c82cecb520436e0e9963785627583 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 60e135af364d777a9ab41c97e5e89cd224da6198 F src/date.c e4655393bb403fa310eef66cc4583d75d4d7fd93 F src/dbstat.c ffd63fc8ba7541476ced189b95e95d7f2bc63f78 F src/delete.c 00af9f08a15ddc5cba5962d3d3e5bf2d67b2e7da -F src/expr.c 38790e65d1219f2b7dc26458f39a5252fe7c60cd +F src/expr.c fe55c489362d1429c364e98c877514f4455f45a6 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c e18b3dff7d47c7bcac5ac4fc178a89b9fd322b44 -F src/func.c cf5e10af9125b245f1b962e8ba4d520a37818795 +F src/func.c ccaf46fa98f795673afbfab73dff7c18db88f3cd F src/global.c bd5a0af3f30b0c01be6db756c626cd3c33a3d260 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 @@ -309,7 +309,7 @@ F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3 F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a -F src/mem5.c 262055c242fa7db59c5f07ad77fdc4e97888c054 +F src/mem5.c 71f81a11fc5e29a57428761ab38a7bf2ef4ee19d F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85 F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495 F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c @@ -322,14 +322,14 @@ F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8 F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf F src/os_common.h abdb9a191a367793268fe553d25bab894e986a0e F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa -F src/os_unix.c 0ca6d8710366fbb01a275160f018334cd347cbda +F src/os_unix.c 82986e1e75782b54da7822dca42d36d974fc2948 F src/os_win.c 386fba30419e8458b13209781c2af5590eab2811 F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca F src/pager.c 58d2593612acb6b542de6715b4af397ea1fa0a35 F src/pager.h bf25005b4656cd805af43487c3139fca9678d0cc -F src/parse.y 23737e649c26ce327603799e57f5c2ff50e5e6ba +F src/parse.y caad1e98edeca6960493d0c60d31b76820dd7776 F src/pcache.c 73895411fa6b7bd6f0091212feabbe833b358d23 -F src/pcache.h 1ff11adce609ba7de139b6abfabaf9a2bac947b5 +F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545 F src/pcache1.c 72f644dc9e1468c72922eff5904048427b817051 F src/pragma.c f3e7147299ca05ef4304a36f1fd6e002729c72c6 F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c @@ -338,16 +338,16 @@ F src/printf.c af589a27b7d40f6f4f704e9eea99f02f18ad6d32 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c a83b41104e6ff69855d03cd0aaa09e93927ec39f F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c f8fded11fc443a9f5a73cc5db069d06b34460e2f +F src/select.c d84c091185bc160c349e8bf460ebd084dbd77e64 F src/shell.c ed71dc7679e6f087a3f1ea3f9dae4b0fae7209c3 F src/sqlite.h.in 7d87d71b9a4689c51fa092f48f16590ff71558e3 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d -F src/sqliteInt.h f97614d43833bae0ed6c51ac8e550f0099a1d0ba +F src/sqliteInt.h b8ccd34a919e4b6bab8c4164046330002aa9a27a F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e -F src/tclsqlite.c d9439b6a910985b7fff43ba6756bcef00de22649 +F src/tclsqlite.c 82979239a896992f9b78efec81cfda05d316a7d0 F src/test1.c 4f1b42699068b7806af3111786f5ad760c2c1ff7 F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b F src/test3.c a8887dabbbee3059af338f20d290084a63ed1b0f @@ -403,20 +403,20 @@ F src/update.c 17332f9fe818cbc0444c36a811800af8498af4c3 F src/utf.c 32d7f82aa921322f3e1c956f4b58f019ebd2c6b3 F src/util.c e802e8e311a0d6c48cd1b3e89db164f6f0248d70 F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 -F src/vdbe.c 6ac8e5d808d48afc369316e147c191102f0584c1 +F src/vdbe.c 6572d00eefeaa0b14b325fdf3a409920ec3fee82 F src/vdbe.h efb7a8c1459e31f3ea4377824c6a7e4cb5068637 -F src/vdbeInt.h 75c2e82ee3357e9210c06474f8d9bdf12c81105d +F src/vdbeInt.h 42eefa4f9e7432b9968d321b44e48821ec13b189 F src/vdbeapi.c 020681b943e77766b32ae1cddf86d7831b7374ca -F src/vdbeaux.c 3308a07a6b0b64e22e83cbcc76773eaf330b056a +F src/vdbeaux.c 5d8c7c04e0f677033efb1292248a5f9056bbc34c F src/vdbeblob.c fdc4a81605ae7a35ae94a55bd768b66d6be16f15 F src/vdbemem.c fdd1578e47bea61390d472de53c565781d81e045 F src/vdbesort.c a7ec02da4494c59dfd071126dd3726be5a11459d F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 F src/vtab.c 2a8b44aa372c33f6154208e7a7f6c44254549806 F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb -F src/wal.c 974928c988681c5157202c79dd9f26afaa7b5086 +F src/wal.c 92ca9e7923c337c497e4c9aa7edac800e269a1d8 F src/wal.h 907943dfdef10b583e81906679a347e0ec6f1b1b -F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba +F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354 F src/where.c c6d3d2f6af57d574a7365ee2b225a5024f2a6bec F src/whereInt.h 78b6b4de94db84aecbdc07fe3e38f648eb391e9a F src/wherecode.c dfbfe198e418b01f208b489e088edd230c91a4e7 @@ -1066,7 +1066,7 @@ F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl 9df86ab273a0877ffb4ec26c255166dcdca4c278 +F test/tester.tcl af4749cf4abf04291710c5e73f40bc8f411bae86 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1279,12 +1279,12 @@ F test/vtabC.test 4528f459a13136f982e75614d120aef165f17292 F test/vtabD.test 05b3f1d77117271671089e48719524b676842e96 F test/vtabE.test d5024aa42754962f6bb0afd261681686488e7afe F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e -F test/vtabH.test 492ba03dcb7bb8fedcc53f258c410d04013adbc9 +F test/vtabH.test 5f5157a1501d9889ec35c1a1832f69612dd31444 F test/vtabI.test 751b07636700dbdea328e4265b6077ccd6811a3f F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772 -F test/wal.test dbfc482e10c7263298833bb1fc60b3ac9d6340a1 +F test/wal.test 65bfc68f3f09dcbc62cee9f794e560428d96cec7 F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada F test/wal3.test b1d425f68a1f61d12563f0fa1ee6fca7d5afabf4 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c @@ -1306,6 +1306,7 @@ F test/walfault.test 1f8389f7709877e9b4cc679033d71d6fe529056b F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483 F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496 +F test/waloverwrite.test 8702964967c2f28204f0b4f27af65da81999fc99 F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6 F test/walro.test 34422d1d95aaff0388f0791ec20edb34e2a3ed57 F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417 @@ -1411,7 +1412,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 0e3c545423246231ddac8fed2f103d71d556e17f -R af2ae430a57fbc5161db0dbbd31b8a3f +P 2c0b93553ebb00a70c611eb8dac021877933f088 ecc98bef43c2fd07d64e4efddf340929a875ebac +R fac95fe8d4249da246cad11b14ac9297 U dan -Z 7e47e5a1c7084b8fa203746692b6702a +Z 0acdab0d7c32bec7117a883df7ebebf7 diff --git a/manifest.uuid b/manifest.uuid index 7a083e6ea4..0ab6f5ff10 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2c0b93553ebb00a70c611eb8dac021877933f088 \ No newline at end of file +a73d245f2e523a57163bc93d9fb6a74c4cdf21e7 \ No newline at end of file diff --git a/src/btmutex.c b/src/btmutex.c index c9c8572dfb..c1ebff9604 100644 --- a/src/btmutex.c +++ b/src/btmutex.c @@ -169,21 +169,6 @@ int sqlite3BtreeHoldsMutex(Btree *p){ #endif -#ifndef SQLITE_OMIT_INCRBLOB -/* -** Enter and leave a mutex on a Btree given a cursor owned by that -** Btree. These entry points are used by incremental I/O and can be -** omitted if that module is not used. -*/ -void sqlite3BtreeEnterCursor(BtCursor *pCur){ - sqlite3BtreeEnter(pCur->pBtree); -} -void sqlite3BtreeLeaveCursor(BtCursor *pCur){ - sqlite3BtreeLeave(pCur->pBtree); -} -#endif /* SQLITE_OMIT_INCRBLOB */ - - /* ** Enter the mutex on every Btree associated with a database ** connection. This is needed (for example) prior to parsing @@ -217,14 +202,6 @@ void sqlite3BtreeLeaveAll(sqlite3 *db){ } } -/* -** Return true if a particular Btree requires a lock. Return FALSE if -** no lock is ever required since it is not sharable. -*/ -int sqlite3BtreeSharable(Btree *p){ - return p->sharable; -} - #ifndef NDEBUG /* ** Return true if the current thread holds the database connection @@ -298,4 +275,23 @@ void sqlite3BtreeEnterAll(sqlite3 *db){ } } #endif /* if SQLITE_THREADSAFE */ + +#ifndef SQLITE_OMIT_INCRBLOB +/* +** Enter a mutex on a Btree given a cursor owned by that Btree. +** +** These entry points are used by incremental I/O only. Enter() is required +** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not +** the build is threadsafe. Leave() is only required by threadsafe builds. +*/ +void sqlite3BtreeEnterCursor(BtCursor *pCur){ + sqlite3BtreeEnter(pCur->pBtree); +} +# if SQLITE_THREADSAFE +void sqlite3BtreeLeaveCursor(BtCursor *pCur){ + sqlite3BtreeLeave(pCur->pBtree); +} +# endif +#endif /* ifndef SQLITE_OMIT_INCRBLOB */ + #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */ diff --git a/src/btree.c b/src/btree.c index f5feff8a4c..77552d5831 100644 --- a/src/btree.c +++ b/src/btree.c @@ -450,6 +450,10 @@ static void releasePage(MemPage *pPage); /* Forward reference */ static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } +static int cursorOwnsBtShared(BtCursor *p){ + assert( cursorHoldsMutex(p) ); + return (p->pBtree->db==p->pBt->db); +} #endif /* @@ -786,7 +790,7 @@ static int btreeMoveto( static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; int skipNext; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; @@ -3126,7 +3130,6 @@ int sqlite3BtreeNewDb(Btree *p){ ** proceed. */ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ - sqlite3 *pBlock = 0; BtShared *pBt = p->pBt; int rc = SQLITE_OK; @@ -3149,27 +3152,30 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } #ifndef SQLITE_OMIT_SHARED_CACHE - /* If another database handle has already opened a write transaction - ** on this shared-btree structure and a second write transaction is - ** requested, return SQLITE_LOCKED. - */ - if( (wrflag && pBt->inTransaction==TRANS_WRITE) - || (pBt->btsFlags & BTS_PENDING)!=0 - ){ - pBlock = pBt->pWriter->db; - }else if( wrflag>1 ){ - BtLock *pIter; - for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ - if( pIter->pBtree!=p ){ - pBlock = pIter->pBtree->db; - break; + { + sqlite3 *pBlock = 0; + /* If another database handle has already opened a write transaction + ** on this shared-btree structure and a second write transaction is + ** requested, return SQLITE_LOCKED. + */ + if( (wrflag && pBt->inTransaction==TRANS_WRITE) + || (pBt->btsFlags & BTS_PENDING)!=0 + ){ + pBlock = pBt->pWriter->db; + }else if( wrflag>1 ){ + BtLock *pIter; + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + if( pIter->pBtree!=p ){ + pBlock = pIter->pBtree->db; + break; + } } } - } - if( pBlock ){ - sqlite3ConnectionBlocked(p->db, pBlock); - rc = SQLITE_LOCKED_SHAREDCACHE; - goto trans_begun; + if( pBlock ){ + sqlite3ConnectionBlocked(p->db, pBlock); + rc = SQLITE_LOCKED_SHAREDCACHE; + goto trans_begun; + } } #endif @@ -4286,7 +4292,7 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ ** to return an integer result code for historical reasons. */ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 ); assert( pCur->iPageeState==CURSOR_VALID ); @@ -4704,7 +4710,7 @@ static const void *fetchPayload( assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); assert( pCur->info.nSize>0 ); assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); @@ -4750,7 +4756,7 @@ const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){ static int moveToChild(BtCursor *pCur, u32 newPgno){ BtShared *pBt = pCur->pBt; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPageiPage>=0 ); @@ -4796,7 +4802,7 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){ ** the largest cell index. */ static void moveToParent(BtCursor *pCur){ - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); assert( pCur->apPage[pCur->iPage] ); @@ -4836,7 +4842,7 @@ static int moveToRoot(BtCursor *pCur){ MemPage *pRoot; int rc = SQLITE_OK; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); @@ -4915,7 +4921,7 @@ static int moveToLeftmost(BtCursor *pCur){ int rc = SQLITE_OK; MemPage *pPage; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ assert( pCur->aiIdx[pCur->iPage]nCell ); @@ -4940,7 +4946,7 @@ static int moveToRightmost(BtCursor *pCur){ int rc = SQLITE_OK; MemPage *pPage = 0; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); @@ -4961,7 +4967,7 @@ static int moveToRightmost(BtCursor *pCur){ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ @@ -4984,7 +4990,7 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ @@ -5062,7 +5068,7 @@ int sqlite3BtreeMovetoUnpacked( int rc; RecordCompare xRecordCompare; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); @@ -5310,7 +5316,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ int idx; MemPage *pPage; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); assert( *pRes==0 ); if( pCur->eState!=CURSOR_VALID ){ @@ -5374,7 +5380,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ } int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ MemPage *pPage; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pRes!=0 ); assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); @@ -5419,7 +5425,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ int rc; MemPage *pPage; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pRes!=0 ); assert( *pRes==0 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); @@ -5475,7 +5481,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ return rc; } int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pRes!=0 ); assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); @@ -7955,7 +7961,7 @@ int sqlite3BtreeInsert( return pCur->skipNext; } - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE && (pBt->btsFlags & BTS_READ_ONLY)==0 ); @@ -8102,7 +8108,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){ u16 szCell; /* Size of the cell being deleted */ int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */ - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( pCur->curFlags & BTCF_WriteFlag ); @@ -9564,7 +9570,7 @@ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ */ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ int rc; - assert( cursorHoldsMutex(pCsr) ); + assert( cursorOwnsBtShared(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert( pCsr->curFlags & BTCF_Incrblob ); @@ -9671,3 +9677,12 @@ int sqlite3BtreeIsReadonly(Btree *p){ ** Return the size of the header added to each page by this module. */ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } + +#if !defined(SQLITE_OMIT_SHARED_CACHE) +/* +** Return true if the Btree passed as the only argument is sharable. +*/ +int sqlite3BtreeSharable(Btree *p){ + return p->sharable; +} +#endif diff --git a/src/btree.h b/src/btree.h index 09b713f3db..2f398e7bba 100644 --- a/src/btree.h +++ b/src/btree.h @@ -287,15 +287,17 @@ void sqlite3BtreeCursorList(Btree*); #ifndef SQLITE_OMIT_SHARED_CACHE void sqlite3BtreeEnter(Btree*); void sqlite3BtreeEnterAll(sqlite3*); + int sqlite3BtreeSharable(Btree*); + void sqlite3BtreeEnterCursor(BtCursor*); #else # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) +# define sqlite3BtreeSharable(X) 0 +# define sqlite3BtreeEnterCursor(X) #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE - int sqlite3BtreeSharable(Btree*); void sqlite3BtreeLeave(Btree*); - void sqlite3BtreeEnterCursor(BtCursor*); void sqlite3BtreeLeaveCursor(BtCursor*); void sqlite3BtreeLeaveAll(sqlite3*); #ifndef NDEBUG @@ -306,9 +308,7 @@ void sqlite3BtreeCursorList(Btree*); #endif #else -# define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeLeave(X) -# define sqlite3BtreeEnterCursor(X) # define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeLeaveAll(X) diff --git a/src/build.c b/src/build.c index 63e3004657..6aac454172 100644 --- a/src/build.c +++ b/src/build.c @@ -24,15 +24,6 @@ */ #include "sqliteInt.h" -/* -** This routine is called when a new SQL statement is beginning to -** be parsed. Initialize the pParse structure as needed. -*/ -void sqlite3BeginParse(Parse *pParse, int explainFlag){ - pParse->explain = (u8)explainFlag; - pParse->nVar = 0; -} - #ifndef SQLITE_OMIT_SHARED_CACHE /* ** The TableLock structure is only used by the sqlite3TableLock() and diff --git a/src/expr.c b/src/expr.c index d8d36afa54..3be3bf52db 100644 --- a/src/expr.c +++ b/src/expr.c @@ -461,8 +461,9 @@ Expr *sqlite3ExprAlloc( assert( iValue>=0 ); } } - pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra); + pNew = sqlite3DbMallocRaw(db, sizeof(Expr)+nExtra); if( pNew ){ + memset(pNew, 0, sizeof(Expr)); pNew->op = (u8)op; pNew->iAgg = -1; if( pToken ){ diff --git a/src/func.c b/src/func.c index ad4cf73c31..45bbb35cd8 100644 --- a/src/func.c +++ b/src/func.c @@ -567,10 +567,10 @@ static void total_changes( ** A structure defining how to do GLOB-style comparisons. */ struct compareInfo { - u8 matchAll; - u8 matchOne; - u8 matchSet; - u8 noCase; + u8 matchAll; /* "*" or "%" */ + u8 matchOne; /* "?" or "_" */ + u8 matchSet; /* "[" or 0 */ + u8 noCase; /* true to ignore case differences */ }; /* @@ -633,22 +633,14 @@ static int patternCompare( const u8 *zPattern, /* The glob pattern */ const u8 *zString, /* The string to compare against the glob */ const struct compareInfo *pInfo, /* Information about how to do the compare */ - u32 esc /* The escape character */ + u32 matchOther /* The escape char (LIKE) or '[' (GLOB) */ ){ u32 c, c2; /* Next pattern and input string chars */ u32 matchOne = pInfo->matchOne; /* "?" or "_" */ u32 matchAll = pInfo->matchAll; /* "*" or "%" */ - u32 matchOther; /* "[" or the escape character */ u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ const u8 *zEscaped = 0; /* One past the last escaped input char */ - /* The GLOB operator does not have an ESCAPE clause. And LIKE does not - ** have the matchSet operator. So we either have to look for one or - ** the other, never both. Hence the single variable matchOther is used - ** to store the one we have to look for. - */ - matchOther = esc ? esc : pInfo->matchSet; - while( (c = Utf8Read(zPattern))!=0 ){ if( c==matchAll ){ /* Match "*" */ /* Skip over multiple "*" characters in the pattern. If there @@ -662,7 +654,7 @@ static int patternCompare( if( c==0 ){ return 1; /* "*" at the end of the pattern matches */ }else if( c==matchOther ){ - if( esc ){ + if( pInfo->matchSet==0 ){ c = sqlite3Utf8Read(&zPattern); if( c==0 ) return 0; }else{ @@ -670,7 +662,7 @@ static int patternCompare( ** recursive search in this case, but it is an unusual case. */ assert( matchOther<0x80 ); /* '[' is a single-byte character */ while( *zString - && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ + && patternCompare(&zPattern[-1],zString,pInfo,matchOther)==0 ){ SQLITE_SKIP_UTF8(zString); } return *zString!=0; @@ -696,18 +688,18 @@ static int patternCompare( } while( (c2 = *(zString++))!=0 ){ if( c2!=c && c2!=cx ) continue; - if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; + if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1; } }else{ while( (c2 = Utf8Read(zString))!=0 ){ if( c2!=c ) continue; - if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; + if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1; } } return 0; } if( c==matchOther ){ - if( esc ){ + if( pInfo->matchSet==0 ){ c = sqlite3Utf8Read(&zPattern); if( c==0 ) return 0; zEscaped = zPattern; @@ -760,7 +752,7 @@ static int patternCompare( ** The sqlite3_strglob() interface. */ int sqlite3_strglob(const char *zGlobPattern, const char *zString){ - return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0; + return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[')==0; } /* @@ -798,9 +790,10 @@ static void likeFunc( sqlite3_value **argv ){ const unsigned char *zA, *zB; - u32 escape = 0; + u32 escape; int nPat; sqlite3 *db = sqlite3_context_db_handle(context); + struct compareInfo *pInfo = sqlite3_user_data(context); #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( sqlite3_value_type(argv[0])==SQLITE_BLOB @@ -840,13 +833,13 @@ static void likeFunc( return; } escape = sqlite3Utf8Read(&zEsc); + }else{ + escape = pInfo->matchSet; } if( zA && zB ){ - struct compareInfo *pInfo = sqlite3_user_data(context); #ifdef SQLITE_TEST sqlite3_like_count++; #endif - sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)); } } diff --git a/src/mem5.c b/src/mem5.c index 49bebca093..7316a630a6 100644 --- a/src/mem5.c +++ b/src/mem5.c @@ -102,6 +102,7 @@ static SQLITE_WSD struct Mem5Global { */ sqlite3_mutex *mutex; +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Performance statistics */ @@ -113,6 +114,7 @@ static SQLITE_WSD struct Mem5Global { u32 maxOut; /* Maximum instantaneous currentOut */ u32 maxCount; /* Maximum instantaneous currentCount */ u32 maxRequest; /* Largest allocation (exclusive of internal frag) */ +#endif /* ** Lists of free blocks. aiFreelist[0] is a list of free blocks of @@ -224,14 +226,17 @@ static void *memsys5MallocUnsafe(int nByte){ /* nByte must be a positive */ assert( nByte>0 ); + /* No more than 1GiB per allocation */ + if( nByte > 0x40000000 ) return 0; + +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* Keep track of the maximum allocation request. Even unfulfilled ** requests are counted */ if( (u32)nByte>mem5.maxRequest ){ - /* Abort if the requested allocation size is larger than the largest - ** power of two that we can represent using 32-bit signed integers. */ - if( nByte > 0x40000000 ) return 0; mem5.maxRequest = nByte; } +#endif + /* Round nByte up to the next valid power of two */ for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz0 ); assert( mem5.currentOut>=(size*mem5.szAtom) ); mem5.currentCount--; mem5.currentOut -= size*mem5.szAtom; assert( mem5.currentOut>0 || mem5.currentCount==0 ); assert( mem5.currentCount>0 || mem5.currentOut==0 ); +#endif mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize; while( ALWAYS(iLogsize0 - { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, + { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, +#else + { "mmap", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent) +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, +#else + { "munmap", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent) -#if HAVE_MREMAP +#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, #else { "mremap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent) +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, +#else + { "getpagesize", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent) { "readlink", (sqlite3_syscall_ptr)readlink, 0 }, #define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent) -#endif }; /* End of the overrideable system calls */ diff --git a/src/parse.y b/src/parse.y index 6ac2be21f2..d6a587a2c8 100644 --- a/src/parse.y +++ b/src/parse.y @@ -114,10 +114,10 @@ cmdlist ::= cmdlist ecmd. cmdlist ::= ecmd. ecmd ::= SEMI. ecmd ::= explain cmdx SEMI. -explain ::= . { sqlite3BeginParse(pParse, 0); } +explain ::= . %ifndef SQLITE_OMIT_EXPLAIN -explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); } -explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); } +explain ::= EXPLAIN. { pParse->explain = 1; } +explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; } %endif SQLITE_OMIT_EXPLAIN cmdx ::= cmd. { sqlite3FinishCoding(pParse); } diff --git a/src/pcache.h b/src/pcache.h index 42c44cf7ba..475c04c061 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -55,6 +55,8 @@ struct PgHdr { #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */ #define PGHDR_MMAP 0x040 /* This is an mmap page object */ +#define PGHDR_WAL_APPEND 0x080 /* Appended to wal file */ + /* Initialize and shutdown the page cache subsystem */ int sqlite3PcacheInitialize(void); void sqlite3PcacheShutdown(void); diff --git a/src/select.c b/src/select.c index f8b8e9e77f..b1db07d09a 100644 --- a/src/select.c +++ b/src/select.c @@ -111,29 +111,34 @@ Select *sqlite3SelectNew( Select *pNew; Select standin; sqlite3 *db = pParse->db; - pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); + pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); if( pNew==0 ){ assert( db->mallocFailed ); pNew = &standin; - memset(pNew, 0, sizeof(*pNew)); } if( pEList==0 ){ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0)); } pNew->pEList = pEList; + pNew->op = TK_SELECT; + pNew->selFlags = selFlags; + pNew->iLimit = 0; + pNew->iOffset = 0; + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->nSelectRow = 0; if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc)); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; - pNew->selFlags = selFlags; - pNew->op = TK_SELECT; + pNew->pPrior = 0; + pNew->pNext = 0; pNew->pLimit = pLimit; pNew->pOffset = pOffset; + pNew->pWith = 0; assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 ); - pNew->addrOpenEphm[0] = -1; - pNew->addrOpenEphm[1] = -1; if( db->mallocFailed ) { clearSelect(db, pNew, pNew!=&standin); pNew = 0; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c01bbc7869..a4d4f65f3c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -767,10 +767,6 @@ typedef INT16_TYPE LogEst; */ #ifdef __APPLE__ # include -# if TARGET_OS_IPHONE -# undef SQLITE_MAX_MMAP_SIZE -# define SQLITE_MAX_MMAP_SIZE 0 -# endif #endif #ifndef SQLITE_MAX_MMAP_SIZE # if defined(__linux__) \ @@ -3340,7 +3336,6 @@ void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); void sqlite3ResetAllSchemasOfConnection(sqlite3*); void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); -void sqlite3BeginParse(Parse*,int); void sqlite3CommitInternalChanges(sqlite3*); void sqlite3DeleteColumnNames(sqlite3*,Table*); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); diff --git a/src/tclsqlite.c b/src/tclsqlite.c index f024317e90..604e898265 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -2976,6 +2976,10 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0); return TCL_OK; } + if( strcmp(zArg,"-sourceid")==0 ){ + Tcl_AppendResult(interp,sqlite3_sourceid(), (char*)0); + return TCL_OK; + } if( strcmp(zArg,"-has-codec")==0 ){ #ifdef SQLITE_HAS_CODEC Tcl_AppendResult(interp,"1",(char*)0); diff --git a/src/vdbe.c b/src/vdbe.c index 5acb3b3137..7eb4c0baeb 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2374,7 +2374,6 @@ case OP_Column: { u64 offset64; /* 64-bit offset */ u32 avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ - u16 fx; /* pDest->flags value */ Mem *pReg; /* PseudoTable input register */ p2 = pOp->p2; @@ -2552,10 +2551,31 @@ case OP_Column: { assert( sqlite3VdbeCheckMemInvariants(pDest) ); if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); assert( t==pC->aType[p2] ); + pDest->enc = encoding; if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ - sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest); + zData = pC->aRow + aOffset[p2]; + if( t<12 ){ + sqlite3VdbeSerialGet(zData, t, pDest); + }else{ + /* If the column value is a string, we need a persistent value, not + ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent + ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). + */ + static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; + pDest->n = len = (t-12)/2; + if( pDest->szMalloc < len+2 ){ + pDest->flags = MEM_Null; + if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; + }else{ + pDest->z = pDest->zMalloc; + } + memcpy(pDest->z, zData, len); + pDest->z[len] = 0; + pDest->z[len+1] = 0; + pDest->flags = aFlag[t&1]; + } }else{ /* This branch happens only when content is on overflow pages */ if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 @@ -2567,38 +2587,20 @@ case OP_Column: { ** 2. the length(X) function if X is a blob, and ** 3. if the content length is zero. ** So we might as well use bogus content rather than reading - ** content from disk. NULL will work for the value for strings - ** and blobs and whatever is in the payloadSize64 variable - ** will work for everything else. */ - sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest); + ** content from disk. */ + static u8 aZero[8]; /* This is the bogus content */ + sqlite3VdbeSerialGet(aZero, t, pDest); }else{ rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable, pDest); - if( rc!=SQLITE_OK ){ - goto op_column_error; + if( rc==SQLITE_OK ){ + sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); + pDest->flags &= ~MEM_Ephem; } - sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); - pDest->flags &= ~MEM_Ephem; } } - pDest->enc = encoding; op_column_out: - /* If the column value is an ephemeral string, go ahead and persist - ** that string in case the cursor moves before the column value is - ** used. The following code does the equivalent of Deephemeralize() - ** but does it faster. */ - if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){ - fx = pDest->flags & (MEM_Str|MEM_Blob); - assert( fx!=0 ); - zData = (const u8*)pDest->z; - len = pDest->n; - if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem; - memcpy(pDest->z, zData, len); - pDest->z[len] = 0; - pDest->z[len+1] = 0; - pDest->flags = fx|MEM_Term; - } op_column_error: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index d1de55eb1c..b231cf908e 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -489,11 +489,15 @@ int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); -#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 +#if !defined(SQLITE_OMIT_SHARED_CACHE) void sqlite3VdbeEnter(Vdbe*); - void sqlite3VdbeLeave(Vdbe*); #else # define sqlite3VdbeEnter(X) +#endif + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 + void sqlite3VdbeLeave(Vdbe*); +#else # define sqlite3VdbeLeave(X) #endif diff --git a/src/vdbeaux.c b/src/vdbeaux.c index dbbb2a6ccb..aa8070a132 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1317,7 +1317,7 @@ void sqlite3VdbeUsesBtree(Vdbe *p, int i){ } } -#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 +#if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** If SQLite is compiled to support shared-cache mode and to be threadsafe, ** this routine obtains the mutex associated with each BtShared structure diff --git a/src/wal.c b/src/wal.c index 4238ea483b..ae6a54849a 100644 --- a/src/wal.c +++ b/src/wal.c @@ -445,6 +445,7 @@ struct Wal { u8 padToSectorBoundary; /* Pad transactions out to the next sector */ WalIndexHdr hdr; /* Wal-index header for current transaction */ u32 minFrame; /* Ignore wal frames before this one */ + u32 iReCksum; /* On commit, recalculate checksums from here */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ #ifdef SQLITE_DEBUG @@ -698,14 +699,16 @@ static void walEncodeFrame( assert( WAL_FRAME_HDRSIZE==24 ); sqlite3Put4byte(&aFrame[0], iPage); sqlite3Put4byte(&aFrame[4], nTruncate); - memcpy(&aFrame[8], pWal->hdr.aSalt, 8); + if( pWal->iReCksum==0 ){ + memcpy(&aFrame[8], pWal->hdr.aSalt, 8); - nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); - walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); - walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); + nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); + walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); + walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); - sqlite3Put4byte(&aFrame[16], aCksum[0]); - sqlite3Put4byte(&aFrame[20], aCksum[1]); + sqlite3Put4byte(&aFrame[16], aCksum[0]); + sqlite3Put4byte(&aFrame[20], aCksum[1]); + } } /* @@ -2632,6 +2635,7 @@ int sqlite3WalBeginWriteTransaction(Wal *pWal){ /* Cannot start a write transaction without first holding a read ** transaction. */ assert( pWal->readLock>=0 ); + assert( pWal->writeLock==0 && pWal->iReCksum==0 ); if( pWal->readOnly ){ return SQLITE_READONLY; @@ -2667,6 +2671,7 @@ int sqlite3WalEndWriteTransaction(Wal *pWal){ if( pWal->writeLock ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; + pWal->iReCksum = 0; pWal->truncateOnCommit = 0; } return SQLITE_OK; @@ -2885,6 +2890,59 @@ static int walWriteOneFrame( return rc; } +/* +** This function is called as part of committing a transaction within which +** one or more frames have been overwritten. It updates the checksums for +** all frames written to the wal file by the current transaction starting +** with the earliest to have been overwritten. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int walRewriteChecksums(Wal *pWal, u32 iLast){ + const int szPage = pWal->szPage;/* Database page size */ + int rc = SQLITE_OK; /* Return code */ + u8 *aBuf; /* Buffer to load data from wal file into */ + u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */ + u32 iRead; /* Next frame to read from wal file */ + i64 iCksumOff; + + aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE); + if( aBuf==0 ) return SQLITE_NOMEM; + + /* Find the checksum values to use as input for the recalculating the + ** first checksum. If the first frame is frame 1 (implying that the current + ** transaction restarted the wal file), these values must be read from the + ** wal-file header. Otherwise, read them from the frame header of the + ** previous frame. */ + assert( pWal->iReCksum>0 ); + if( pWal->iReCksum==1 ){ + iCksumOff = 24; + }else{ + iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16; + } + rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff); + pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf); + pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]); + + iRead = pWal->iReCksum; + pWal->iReCksum = 0; + for(; rc==SQLITE_OK && iRead<=iLast; iRead++){ + i64 iOff = walFrameOffset(iRead, szPage); + rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff); + if( rc==SQLITE_OK ){ + u32 iPgno, nDbSize; + iPgno = sqlite3Get4byte(aBuf); + nDbSize = sqlite3Get4byte(&aBuf[4]); + + walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame); + rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff); + } + } + + sqlite3_free(aBuf); + return rc; +} + /* ** Write a set of frames to the log. The caller must hold the write-lock ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). @@ -2905,6 +2963,8 @@ int sqlite3WalFrames( int szFrame; /* The size of a single frame */ i64 iOffset; /* Next byte to write in WAL file */ WalWriter w; /* The writer */ + u32 iFirst = 0; /* First frame that may be overwritten */ + WalIndexHdr *pLive; /* Pointer to shared header */ assert( pList ); assert( pWal->writeLock ); @@ -2920,6 +2980,11 @@ int sqlite3WalFrames( } #endif + pLive = (WalIndexHdr*)walIndexHdr(pWal); + if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){ + iFirst = pLive->mxFrame+1; + } + /* See if it is possible to write these frames into the start of the ** log file, instead of appending to it at pWal->hdr.mxFrame. */ @@ -2984,6 +3049,27 @@ int sqlite3WalFrames( /* Write all frames into the log file exactly once */ for(p=pList; p; p=p->pDirty){ int nDbSize; /* 0 normally. Positive == commit flag */ + + /* Check if this page has already been written into the wal file by + ** the current transaction. If so, overwrite the existing frame and + ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that + ** checksums must be recomputed when the transaction is committed. */ + if( iFirst && (p->pDirty || isCommit==0) ){ + u32 iWrite = 0; + VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite); + assert( rc==SQLITE_OK || iWrite==0 ); + if( iWrite>=iFirst ){ + i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; + if( pWal->iReCksum==0 || iWriteiReCksum ){ + pWal->iReCksum = iWrite; + } + rc = sqlite3OsWrite(pWal->pWalFd, p->pData, szPage, iOff); + if( rc ) return rc; + p->flags &= ~PGHDR_WAL_APPEND; + continue; + } + } + iFrame++; assert( iOffset==walFrameOffset(iFrame, szPage) ); nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0; @@ -2991,6 +3077,13 @@ int sqlite3WalFrames( if( rc ) return rc; pLast = p; iOffset += szFrame; + p->flags |= PGHDR_WAL_APPEND; + } + + /* Recalculate checksums within the wal file if required. */ + if( isCommit && pWal->iReCksum ){ + rc = walRewriteChecksums(pWal, iFrame); + if( rc ) return rc; } /* If this is the end of a transaction, then we might need to pad @@ -3042,6 +3135,7 @@ int sqlite3WalFrames( */ iFrame = pWal->hdr.mxFrame; for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){ + if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue; iFrame++; rc = walIndexAppend(pWal, iFrame, p->pgno); } @@ -3154,6 +3248,7 @@ int sqlite3WalCheckpoint( /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ + if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else{ diff --git a/src/walker.c b/src/walker.c index 81e0f2cd60..1e0ad32871 100644 --- a/src/walker.c +++ b/src/walker.c @@ -36,9 +36,8 @@ ** The return value from this routine is WRC_Abort to abandon the tree walk ** and WRC_Continue to continue. */ -int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ +static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; - if( pExpr==0 ) return WRC_Continue; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); rc = pWalker->xExprCallback(pWalker, pExpr); @@ -54,6 +53,9 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ } return rc & WRC_Abort; } +int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ + return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; +} /* ** Call sqlite3WalkExpr() for every expression in list p or until diff --git a/test/tester.tcl b/test/tester.tcl index 4008a34491..426808ea90 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -1028,7 +1028,13 @@ proc finalize_testing {} { output2 "[expr {$nErr-$nKnown}] new errors and $nKnown known errors\ out of $nTest tests" } else { - output2 "$nErr errors out of $nTest tests" + set cpuinfo {} + if {[catch {exec hostname} hname]==0} {set cpuinfo [string trim $hname]} + append cpuinfo " $::tcl_platform(os)" + append cpuinfo " [expr {$::tcl_platform(pointerSize)*8}]-bit" + append cpuinfo " [string map {E -e} $::tcl_platform(byteOrder)]" + output2 "SQLite [sqlite3 -sourceid]" + output2 "$nErr errors out of $nTest tests on $cpuinfo" } if {$nErr>$nKnown} { output2 -nonewline "!Failures on these tests:" diff --git a/test/vtabH.test b/test/vtabH.test index 7bd542e05b..d16db13674 100644 --- a/test/vtabH.test +++ b/test/vtabH.test @@ -68,19 +68,19 @@ set x7 backbone set x8 backarrow set x9 castle -db func glob gfunc +db func glob -argcount 2 gfunc proc gfunc {a b} { incr ::gfunc return 1 } -db func like lfunc +db func like -argcount 2 lfunc proc lfunc {a b} { incr ::gfunc 100 return 1 } -db func regexp rfunc +db func regexp -argcount 2 rfunc proc rfunc {a b} { incr ::gfunc 10000 return 1 diff --git a/test/wal.test b/test/wal.test index bfe3634577..abd3a3ce49 100644 --- a/test/wal.test +++ b/test/wal.test @@ -712,7 +712,7 @@ do_test wal-11.5 { do_test wal-11.6 { execsql COMMIT list [expr [file size test.db]/1024] [file size test.db-wal] -} [list 3 [wal_file_size 41 1024]] +} [list 3 [wal_file_size 40 1024]] do_test wal-11.7 { execsql { SELECT count(*) FROM t1; @@ -722,15 +722,22 @@ do_test wal-11.7 { do_test wal-11.8 { execsql { PRAGMA wal_checkpoint } list [expr [file size test.db]/1024] [file size test.db-wal] -} [list 37 [wal_file_size 41 1024]] +} [list 37 [wal_file_size 40 1024]] do_test wal-11.9 { db close list [expr [file size test.db]/1024] [log_deleted test.db-wal] } {37 1} sqlite3_wal db test.db -set nWal 39 -if {[permutation]!="mmap"} {set nWal 37} -ifcapable !mmap {set nWal 37} + +# After adding the capability of WAL to overwrite prior uncommitted +# frame in the WAL-file with revised content, the size of the WAL file +# following cache-spill is smaller. +# +#set nWal 39 +#if {[permutation]!="mmap"} {set nWal 37} +#ifcapable !mmap {set nWal 37} +set nWal 34 + do_test wal-11.10 { execsql { PRAGMA cache_size = 10; diff --git a/test/waloverwrite.test b/test/waloverwrite.test new file mode 100644 index 0000000000..5e51a70d3f --- /dev/null +++ b/test/waloverwrite.test @@ -0,0 +1,164 @@ +# 2010 May 5 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the operation of the library in +# "PRAGMA journal_mode=WAL" mode. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/wal_common.tcl +set testprefix waloverwrite + +ifcapable !wal {finish_test ; return } + +# Simple test: +# +# Test cases *.1 - *.6: +# +# + Create a database of blobs roughly 50 pages in size. +# +# + Set the db cache size to something much smaller than this (5 pages) +# +# + Within a transaction, loop through the set of blobs 5 times. Update +# each blob as it is visited. +# +# + Test that the wal file is roughly 50 pages in size - even though many +# database pages have been written to it multiple times. +# +# + Take a copy of the database and wal file. Test that recovery can +# be run on it. +# +# Test cases *.7 - *.9: +# +# + Same thing, but before committing the statement transaction open +# a SAVEPOINT, update the blobs another 5 times, then roll it back. +# +# + Check that if recovery is run on the resulting wal file, the rolled +# back changes from within the SAVEPOINT are not present in the db. +# +# The above is run twice - once where the wal file is empty at the start of +# step 3 (tn==1) and once where it already contains a transaction (tn==2). +# +foreach {tn xtra} { + 1 {} + 2 { UPDATE t1 SET y = randomblob(799) WHERE x=4 } +} { + reset_db + do_execsql_test 1.$tn.0 { + CREATE TABLE t1(x, y); + CREATE TABLE t2(x, y); + CREATE INDEX i1y ON t1(y); + + WITH cnt(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<20 + ) + INSERT INTO t1 SELECT i, randomblob(800) FROM cnt; + } {} + + do_test 1.$tn.1 { + set nPg [db one { PRAGMA page_count } ] + expr $nPg>40 && $nPg<50 + } {1} + + do_test 1.$tn.2 { + db close + sqlite3 db test.db + + execsql {PRAGMA journal_mode = wal} + execsql {PRAGMA cache_size = 5} + execsql $xtra + + db transaction { + for {set i 0} {$i < 5} {incr i} { + foreach x [db eval {SELECT x FROM t1}] { + execsql { UPDATE t1 SET y = randomblob(799) WHERE x=$x } + } + } + } + + set nPg [wal_frame_count test.db-wal 1024] + expr $nPg>40 && $nPg<60 + } {1} + + do_execsql_test 1.$tn.3 { PRAGMA integrity_check } ok + + do_test 1.$tn.4 { + forcedelete test.db2 test.db2-wal + forcecopy test.db test.db2 + sqlite3 db2 test.db2 + execsql { SELECT sum(length(y)) FROM t1 } db2 + } [expr 20*800] + + do_test 1.$tn.5 { + db2 close + forcecopy test.db test.db2 + forcecopy test.db-wal test.db2-wal + sqlite3 db2 test.db2 + execsql { SELECT sum(length(y)) FROM t1 } db2 + } [expr 20*799] + + do_test 1.$tn.6 { + execsql { PRAGMA integrity_check } db2 + } ok + db2 close + + do_test 1.$tn.7 { + execsql { PRAGMA wal_checkpoint } + db transaction { + for {set i 0} {$i < 1} {incr i} { + foreach x [db eval {SELECT x FROM t1}] { + execsql { UPDATE t1 SET y = randomblob(798) WHERE x=$x } + } + } + + execsql { + WITH cnt(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<20) + INSERT INTO t2 SELECT i, randomblob(800) FROM cnt; + } + + execsql {SAVEPOINT abc} + for {set i 0} {$i < 5} {incr i} { + foreach x [db eval {SELECT x FROM t1}] { + execsql { UPDATE t1 SET y = randomblob(797) WHERE x=$x } + } + } + breakpoint + execsql {ROLLBACK TO abc} + + } + + set nPg [wal_frame_count test.db-wal 1024] + expr $nPg>55 && $nPg<75 + } {1} + + do_test 1.$tn.8 { + forcedelete test.db2 test.db2-wal + forcecopy test.db test.db2 + sqlite3 db2 test.db2 + execsql { SELECT sum(length(y)) FROM t1 } db2 + } [expr 20*799] + + do_test 1.$tn.9 { + db2 close + forcecopy test.db-wal test.db2-wal + sqlite3 db2 test.db2 + execsql { SELECT sum(length(y)) FROM t1 } db2 + } [expr 20*798] + + do_test 1.$tn.9 { + execsql { PRAGMA integrity_check } db2 + } ok + db2 close +} + +finish_test +