diff --git a/Makefile.in b/Makefile.in index 0352a04fe6..ce845a1965 100644 --- a/Makefile.in +++ b/Makefile.in @@ -548,6 +548,9 @@ sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) +fuzzershell$(EXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h + $(LTLINK) -o $@ $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) + mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) -rpath "$(libdir)" diff --git a/Makefile.msc b/Makefile.msc index 33a5f6015d..b54289cf52 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1183,12 +1183,15 @@ sqlite3.exe: $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h sqldiff.exe: $(TOP)\tool\sqldiff.c sqlite3.c sqlite3.h $(LTLINK) $(TOP)\tool\sqldiff.c sqlite3.c +fuzzershell.exe: $(TOP)\tool\fuzzershell.c sqlite3.c sqlite3.h + $(LTLINK) $(TOP)\tool\fuzzershell.c sqlite3.c + mptester.exe: $(TOP)\mptest\mptest.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h $(LTLINK) $(SHELL_COMPILE_OPTS) $(TOP)\mptest\mptest.c \ /link $(LTLINKOPTS) $(LTLIBPATHS) $(SHELL_LINK_OPTS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) -MPTEST1 = mptester mptest.db $(TOP)/mptest/crash01.test --repeat 20 -MPTEST2 = mptester mptest.db $(TOP)/mptest/multiwrite01.test --repeat 20 +MPTEST1 = mptester mptest.db $(TOP)\mptest\crash01.test --repeat 20 +MPTEST2 = mptester mptest.db $(TOP)\mptest\multiwrite01.test --repeat 20 mptest: mptester.exe del /Q mptest.db 2>NUL @@ -1641,6 +1644,9 @@ queryplantest: testfixture.exe sqlite3.exe test: testfixture.exe sqlite3.exe .\testfixture.exe $(TOP)\test\veryquick.test +smoketest: testfixture.exe + .\testfixture.exe $(TOP)\test\main.test + sqlite3_analyzer.c: $(SQLITE3C) $(TOP)\src\test_stat.c $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl copy $(SQLITE3C) + $(TOP)\src\test_stat.c + $(TOP)\src\tclsqlite.c $@ echo static const char *tclsh_main_loop(void){ >> $@ diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index eab8ad63ad..3037719e9d 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -3459,11 +3459,31 @@ static void fts3ReversePoslist(char *pStart, char **ppPoslist){ char *p = &(*ppPoslist)[-2]; char c = 0; + /* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */ while( p>pStart && (c=*p--)==0 ); + + /* Search backwards for a varint with value zero (the end of the previous + ** poslist). This is an 0x00 byte preceded by some byte that does not + ** have the 0x80 bit set. */ while( p>pStart && (*p & 0x80) | c ){ c = *p--; } - if( p>pStart ){ p = &p[2]; } + assert( p==pStart || c==0 ); + + /* At this point p points to that preceding byte without the 0x80 bit + ** set. So to find the start of the poslist, skip forward 2 bytes then + ** over a varint. + ** + ** Normally. The other case is that p==pStart and the poslist to return + ** is the first in the doclist. In this case do not skip forward 2 bytes. + ** The second part of the if condition (c==0 && *ppPoslist>&p[2]) + ** is required for cases where the first byte of a doclist and the + ** doclist is empty. For example, if the first docid is 10, a doclist + ** that begins with: + ** + ** 0x0A 0x00 + */ + if( p>pStart || (c==0 && *ppPoslist>&p[2]) ){ p = &p[2]; } while( *p++&0x80 ); *ppPoslist = p; } @@ -5765,7 +5785,8 @@ int sqlite3Fts3EvalPhrasePoslist( pIter = pPhrase->pOrPoslist; iDocid = pPhrase->iOrDocid; if( pCsr->bDesc==bDescDoclist ){ - bEof = (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll)); + bEof = !pPhrase->doclist.nAll || + (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll)); while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ sqlite3Fts3DoclistNext( bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, diff --git a/main.mk b/main.mk index 64aa3b82d8..0b7333df2e 100644 --- a/main.mk +++ b/main.mk @@ -416,6 +416,10 @@ sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB) +fuzzershell$(EXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h + $(TCCX) -o fuzzershell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION\ + $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) $(THREADLIB) + mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c $(TCCX) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) $(THREADLIB) diff --git a/manifest b/manifest index ee05b48b56..f1af9cdda2 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Hold\sthe\sdatabase\smutex\sfor\sthe\sduration\sof\ssqlite3session_diff(). -D 2015-04-17T11:31:08.304 +C Merge\sall\srecent\strunk\senhancements\sand\sfixes\sinto\sthe\ssessions\sbranch. +D 2015-04-20T01:32:53.676 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 7e23076b9c9dd5c1901c78cf6cdd64d616e5a539 +F Makefile.in 7599f0c96df628cd543884b1b2f2a2fbffd00079 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 5b2ac9066d9d67427eb98d7e4bf3790c4db51810 +F Makefile.msc e3ce8e0e4eb05e2fcf3828dec70678f2030c9c3f F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 F README.md d58e3bebc0a4145e0f2a87994015fdb575a8e866 F VERSION 2e244662b71e6e68a5c29b014ebc5b7564f4cc5a @@ -78,7 +78,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 4bd75289875b63c04f943d6ed7c31737da99cd74 +F ext/fts3/fts3.c 29300a76fabbbb8fc30bb261c27d421df9f40c76 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h 3626655d6ba903a3919bb44e1c38e5f0f9d6be82 F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365 @@ -170,7 +170,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 3ffc109d70c73c8c1149d7f9c880e22edb8d6c43 +F main.mk 11a73bab5613d7a1554ac3376b7c99a3d9190037 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -178,7 +178,7 @@ F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421 F mptest/crash02.subtest f4ef05adcd15d60e5d2bd654204f2c008b519df8 -F mptest/mptest.c dae6de83eddac3ef97fc4111632f6066760f939a +F mptest/mptest.c fca59f0a922e03f95ed17c44b1515ed37a841c81 F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b @@ -186,21 +186,21 @@ F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c d23d6b6991f66b383934f137fd4384d93fb98c81 F src/analyze.c 91540f835163d5369ccbae78e2e6c74d0dd53c1d -F src/attach.c 3c1053a4cf1c3ca05c8c1d74a94cb688d763cef2 +F src/attach.c c38ac5a520a231d5d0308fd7f2ad95191c867bae F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 -F src/btree.c 67648f6532c2da79d3b3fb6853aa1a0c3ba0e1ad +F src/btree.c 127aceb71ba93f59bc9c6ba810e992a04299e98a F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4 -F src/build.c 01b969b20a44a3d9620e597d9af8242348123540 +F src/build.c e246c2cea69c8f6fc825a156ea2de9dd4a17f18b F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575 F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887 F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/delete.c 5075d88557eb4e2a7fdb2b61a96142830d8589b8 -F src/expr.c 8800584340a9b4f4c0ca55c360de751c6da0b11a +F src/expr.c 5555f768c05d7d4a7840c6c2e72ad7aecbe0fe54 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 3343d551a8d810782257244fb33f2ce191493c39 F src/func.c 1414c24c873c48796ad45942257a179a423ba42f @@ -208,7 +208,7 @@ F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 6663d6885c1e28b503153ff5d817f61cdc1aa901 +F src/insert.c 57381264535195aa3d1f4ba86a7c084412fa7178 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 @@ -237,23 +237,23 @@ F src/os_win.c 03d27be3a20048ef52a648d5f0a15f5edda9f2a3 F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca F src/pager.c 4120a49ecd37697e28f5ed807f470b9c0b88410c F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77 -F src/parse.y 1299c66e7b1707322ccd8af43a359b8fb0d46d72 +F src/parse.y c4e0387bc88c8e21e5ba653e2578959a1f3cdbc7 F src/pcache.c 10539fb959849ad6efff80050541cab3d25089d4 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache1.c 69d137620a305f814398bd29a0c998038c0695e9 -F src/pragma.c 3965ae4e82bed39fb97ce04c5fe18c9bc3ee6a88 +F src/pragma.c 2a81f312cdb78bf0672a0484478ca3c1083028e9 F src/pragma.h 09c89bca58e9a44de2116cc8272b8d454657129f -F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9 +F src/prepare.c 1fffbdcd6f8a0173a8f70d71f22528f4c0e1e3d3 F src/printf.c 08fa675c200aac29e561c6153f91f909ed17612f F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c 66cfe49a9c3b449ef13b89a8c47036a4ed167eab +F src/resolve.c 53486a98c17b7ae09b8c2b398013e973ce4c1aae F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 93260bc9e7e0e6dfe1b7cb8815b0ed4cad8be9e3 -F src/shell.c c4d839ad62f4986891601a21ce629a760f226682 +F src/select.c 361dfc32244656bbe3f0e53d8ed791b3ec0c4be8 +F src/shell.c 48f78c322ea9cba4d0d33bc3d83455f3674a40c2 F src/sqlite.h.in 679a3abfef9c13a989728fd27f308a3e3f00e232 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h f415bc20c6ac85a255f03aa145476655da6f4098 +F src/sqliteInt.h a146261a562d43a4a8ca348f77ca888b50af9b29 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c e7a09215315a978057fb42c640f890160dbcc45e @@ -305,22 +305,22 @@ F src/test_vfs.c b7e6831e6fcf04c5090accff30640ec5c9630739 F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 -F src/tokenize.c a8234a67577308935cdf13e618cd66556f5f45d1 -F src/trigger.c 69a91bed7c94e46223e37ffccfeeb35e34b999ac +F src/tokenize.c b7fb584c2be5ec39b6fdf04b185e7c6f33f8dc15 +F src/trigger.c bc647c712454c9b209fac082bb82870b5fd6fa54 F src/update.c d207deb7a031f698104bee879de0632b611e72dd F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c -F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e +F src/util.c a6431c92803b975b7322724a7b433e538d243539 F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 -F src/vdbe.c f3f2e466c962cbb1f774526d24d963b06dd46a96 +F src/vdbe.c e8f00a2ef92c484ce31cdf3f112b7e83cf4e1a6a F src/vdbe.h 01d8c35cb877faca74331bb690f0327493c2cb50 F src/vdbeInt.h 96e4303a96c6f983e36e1fe32657b2c547f5c8f1 F src/vdbeapi.c d95f2bb43d01a91d93231cde181811b38182202e -F src/vdbeaux.c 70d414ecc1a345f71a52c7e5e4e1bdfa184081ca +F src/vdbeaux.c 4ccd9105cca5c2cbc0481034fd468e3aa184f48f F src/vdbeblob.c ab33f9b57cfce7dddb23853090186da614be4846 F src/vdbemem.c 149e585645c3f3ef063f2b7251646388cfe3d47d F src/vdbesort.c 2e7f683464fd5db3be4beaa1ff2d39e24fcb64b8 -F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 -F src/vtab.c 9ca557215e8591ceb66e0b7c0a579c6df1e54b2d +F src/vdbetrace.c f95c2dff9041fcf07f871789c22ebb0648ea0b7c +F src/vtab.c 5f81f8a59c1f5ddb94c918f25ed5d83578fcc633 F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 753995db83247f20361a8e8a874990b21a75abd9 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 @@ -338,7 +338,7 @@ F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d F test/alter4.test c461150723ac957f3b2214aa0b11552cd72023ec F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f -F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4 +F test/analyze.test 3eb35a4af972f98422e5dc0586501b17d103d321 F test/analyze3.test 75b9e42ea1e4edc919250450dc5762186965d4e6 F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213 F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 @@ -444,7 +444,7 @@ F test/corrupt8.test 2399dfe40d2c0c63af86706e30f3e6302a8d0516 F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85 F test/corruptA.test 53e56dafd180addcdadb402244b8cb9771d2ba26 F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec -F test/corruptC.test 02405cf7ed0c1e989060e1aab6d02ffbc3906fbb +F test/corruptC.test 3fcc0f73d2cf2d69befe2d96332b942426a6aae2 F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040 F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 @@ -494,7 +494,7 @@ F test/e_expr.test 8f5fdd7261e2d746813b0c6a1c0e34824ad3c5ad F test/e_fkey.test a1783fe1f759e1990e6a11adfcf0702dac4d0707 F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 F test/e_insert.test 0e63edc037afe738bb81a626a676811ed7862c90 -F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589 +F test/e_reindex.test 57d439f6c644befc8274ac93cf2f5449cf2736c1 F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_select.test 52692ff3849541e828ad4661fe3773a9b8711763 F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f @@ -517,13 +517,13 @@ F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75 F test/exclusive2.test 32798111aae78a5deec980eee383213f189df308 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30 -F test/expr.test c4b9bf0cc60b26862475e19999fbd2609ca8259c +F test/expr.test 79c3e7502d9e571553b85f0ecc8ff2ac7d0e4931 F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7 F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146 F test/fkey1.test e1d1fa84cde579185ea01358436839703e415a5b -F test/fkey2.test 223c624e7eccee21e89c98d4d127ac88d774b940 +F test/fkey2.test f3d27ecba480a348c328965d154214719bb158a9 F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49 F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d F test/fkey5.test 56bcb5a6e8b725b17febc267fb041a6695e86853 @@ -569,7 +569,7 @@ F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654 F test/fts3_common.tcl 99cf6659b87c0f74f55963c2aea03b3a7d66ceb0 -F test/fts3aa.test edd20ddbbc5b6015ab340abf2ca278ae11ec387d +F test/fts3aa.test 6c263a6f8845205ee02550981a94c2e8dc1e7058 F test/fts3ab.test 7f6cf260ae80dda064023df8e8e503e9a412b91f F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63 F test/fts3ad.test e40570cb6f74f059129ad48bcef3d7cbc20dda49 @@ -673,18 +673,18 @@ F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635 F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 -F test/index3.test 55a90cff99834305e8141df7afaef39674b57062 +F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index5.test 25b0b451aceed4ac5f7d49f856f6de7257470b3e F test/index6.test 3ae54e53c53f2adcacda269237d8e52bdb05a481 -F test/index7.test 3d54dce09344c4530ea39a458aa304da044c887a +F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 -F test/insert4.test 4791662c50518bdd37d394cae9a7a8014e845bb3 +F test/insert4.test a20432f1c0fbbcff8f11d0e6ab4acb8c9db58023 F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6 F test/instr.test 737bbf80685232033f3abedc6ae92f75860b5dd2 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 @@ -761,11 +761,11 @@ F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f -F test/misc1.test 9abcae9a0b8785d6fa92925dbb19c309ae9ea077 +F test/misc1.test 783ba75743b2cf71e0f646bf540a6cef57264811 F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 -F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 +F test/misc5.test f96428ea95b3820aafc6f1c50cf48a09e4597ee1 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2 F test/misc8.test fc2754d38892f7dac30c22db3616c2764f117d66 @@ -812,7 +812,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff F test/permutations.test e5e9f708879336e10095ded8d61966007f4a2c5c -F test/pragma.test e6605ce89c66db930aef561e43a22281a09ffc66 +F test/pragma.test be7195f0aa72bdb8a512133e9640ac40f15b57a2 F test/pragma2.test f624a496a95ee878e81e59961eade66d5c00c028 F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc @@ -830,7 +830,7 @@ F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8 F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 -F test/releasetest.tcl 13f401c10dd4fe1a2fb811ae6ed27fd7d1300d3c +F test/releasetest.tcl a37cd82092c8be438255d65804b5951d6e3ecdae F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 @@ -854,10 +854,10 @@ F test/schema4.test e6a66e20cc69f0e306667c08be7fda3d11707dc5 F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e F test/securedel.test 21749c32ccc30f1ea9e4b9f33295a6521ec20fa0 F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5 -F test/select1.test fc2a61f226a649393664ad54bc5376631801517c +F test/select1.test be62204d2bd9a5a8a149e9974cfddce893d8f686 F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56 F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054 -F test/select4.test 16fa1cafb942f42294ec85cbb78954c2f2d15a44 +F test/select4.test a3201fa921fdfc1397cc629e78c7a976e198a40d F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535 F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0 F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d @@ -927,7 +927,7 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6 -F test/table.test 06271d61eb13871490d38168433c1ef3dd82bb2a +F test/table.test bd841e8df69b99172ce9c7d53587463913d711ca F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 F test/tclsqlite.test 7179b4e0bf236ddf0bfa6bfaefa76fbe0a23c28a @@ -1101,7 +1101,7 @@ F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945 F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359 F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83 F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9 -F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4 +F test/trigger7.test 200dd51e728c9cdc20c72d99d9e9d45c667248f8 F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4 F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41 F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332 @@ -1132,7 +1132,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9 -F test/vtab1.test c9dc2a73e93331d70b37ce4b246ef6dc18412fef +F test/vtab1.test d1e5ec7a818f1d3f0402382b6a1d0c06071b770f F test/vtab2.test 3644649aa8d1daac57fd541f6a5f914cac59203e F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 @@ -1141,7 +1141,7 @@ F test/vtab6.test 5f5380c425e52993560ab4763db4f826d2ba7b09 F test/vtab7.test ae560ebea870ed04e9aa4177cc302f910faaabb5 F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b -F test/vtabA.test c86e1990b7e1e2bb34602a06fffa4c69f2b516dc +F test/vtabA.test 1317f06a03597eee29f40a49b6c21e1aaba4285f F test/vtabB.test 04df5dc531b9f44d9ca65b9c1b79f12b5922a796 F test/vtabC.test 4528f459a13136f982e75614d120aef165f17292 F test/vtabD.test 05b3f1d77117271671089e48719524b676842e96 @@ -1222,6 +1222,7 @@ F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1 F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 +F tool/fuzzershell.c 9e7e273da203037154b433bb67f10b0d9772b370 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce @@ -1244,7 +1245,7 @@ F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c 63cdef19e7fbca0c164b096ef8aef3bb9e9dd222 +F tool/showdb.c 3b5d335d537e4dc44d0c86967023819453c87dc6 F tool/showjournal.c 053eb1cc774710c6890b7dd6293300cc297b16a5 F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68 F tool/showstat4.c 9515faa8ec176599d4a8288293ba8ec61f7b728a @@ -1258,7 +1259,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c -F tool/sqldiff.c 5c16cf3a1f566873abbdecac0d13a6691437564f +F tool/sqldiff.c 393b0f5b17ef29341664563a90d40ee63a0a18f7 F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43 F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d F tool/symbols.sh c5a617b8c61a0926747a56c65f5671ef8ac0e148 @@ -1269,7 +1270,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P abb192a1d79388d4717f459b91e34f9c035935f2 -R 39574ad38832f7643b0bd124d608871c -U dan -Z 2a1b149e99da178a1dea33510073d75a +P 6f33050115562833c43da3c99dd37aeb0bf966b6 592c010478fba7410424f011a62e019c826f1ac3 +R 6536f8d8e866d42286c94c8633072675 +U drh +Z 7d8304bb308c3b4144af41f71be18f06 diff --git a/manifest.uuid b/manifest.uuid index db862f34a6..13bc2f22ab 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6f33050115562833c43da3c99dd37aeb0bf966b6 \ No newline at end of file +b8ef1cdee307441e8d97b4bfc21f8547692eea9f \ No newline at end of file diff --git a/mptest/mptest.c b/mptest/mptest.c index 52ff6a4c83..f81ffb5ca0 100644 --- a/mptest/mptest.c +++ b/mptest/mptest.c @@ -53,6 +53,13 @@ # define GETPID getpid #endif +/* The directory separator character(s) */ +#if defined(_WIN32) +# define isDirSep(c) (((c) == '/') || ((c) == '\\')) +#else +# define isDirSep(c) ((c) == '/') +#endif + /* Mark a parameter as unused to suppress compiler warnings */ #define UNUSED_PARAMETER(x) (void)x @@ -824,7 +831,7 @@ static void waitForClient(int iClient, int iTimeout, char *zErrPrefix){ */ static char *filenameTail(char *z){ int i, j; - for(i=j=0; z[i]; i++) if( z[i]=='/' ) j = i+1; + for(i=j=0; z[i]; i++) if( isDirSep(z[i]) ) j = i+1; return z+j; } @@ -1021,9 +1028,9 @@ static void runScript( char *zNewFile, *zNewScript; char *zToDel = 0; zNewFile = azArg[0]; - if( zNewFile[0]!='/' ){ + if( !isDirSep(zNewFile[0]) ){ int k; - for(k=(int)strlen(zFilename)-1; k>=0 && zFilename[k]!='/'; k--){} + for(k=(int)strlen(zFilename)-1; k>=0 && !isDirSep(zFilename[k]); k--){} if( k>0 ){ zNewFile = zToDel = sqlite3_mprintf("%.*s/%s", k,zFilename,zNewFile); } @@ -1231,7 +1238,7 @@ static void usage(const char *argv0){ int i; const char *zTail = argv0; for(i=0; argv0[i]; i++){ - if( argv0[i]=='/' ) zTail = argv0+i+1; + if( isDirSep(argv0[i]) ) zTail = argv0+i+1; } fprintf(stderr,"Usage: %s DATABASE ?OPTIONS? ?SCRIPT?\n", zTail); exit(1); @@ -1338,6 +1345,7 @@ int SQLITE_CDECL main(int argc, char **argv){ #endif runSql("PRAGMA journal_mode=%Q;", zJMode); } + if( !g.bSync ) trySql("PRAGMA synchronous=OFF"); sqlite3_enable_load_extension(g.db, 1); sqlite3_busy_handler(g.db, busyHandler, 0); sqlite3_create_function(g.db, "vfsname", 0, SQLITE_UTF8, 0, @@ -1346,7 +1354,6 @@ int SQLITE_CDECL main(int argc, char **argv){ evalFunc, 0, 0); g.iTimeout = DEFAULT_TIMEOUT; if( g.bSqlTrace ) sqlite3_trace(g.db, sqlTraceCallback, 0); - if( !g.bSync ) trySql("PRAGMA synchronous=OFF"); if( iClient>0 ){ if( n>0 ) unrecognizedArguments(argv[0], n, argv+2); if( g.iTrace ) logMessage("start-client"); diff --git a/src/attach.c b/src/attach.c index 11296d02ad..efc9eb9a81 100644 --- a/src/attach.c +++ b/src/attach.c @@ -332,7 +332,6 @@ static void codeAttach( SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) ){ - pParse->nErr++; goto attach_end; } diff --git a/src/btree.c b/src/btree.c index 9faf624235..c23cdb947a 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4451,13 +4451,18 @@ static const void *fetchPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 *pAmt /* Write the number of available bytes here */ ){ + u32 amt; 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( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); assert( pCur->info.nSize>0 ); - *pAmt = pCur->info.nLocal; + assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); + assert( pCur->info.pPayloadapPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); + amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload); + if( pCur->info.nLocalinfo.nLocal; + *pAmt = amt; return (void*)pCur->info.pPayload; } @@ -8523,6 +8528,57 @@ static void checkList( } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ +/* +** An implementation of a min-heap. +** +** aHeap[0] is the number of elements on the heap. aHeap[1] is the +** root element. The daughter nodes of aHeap[N] are aHeap[N*2] +** and aHeap[N*2+1]. +** +** The heap property is this: Every node is less than or equal to both +** of its daughter nodes. A consequence of the heap property is that the +** root node aHeap[1] is always the minimum value current in the heap. +** +** The btreeHeapInsert() routine inserts an unsigned 32-bit number onto +** the heap, preserving the heap property. The btreeHeapPull() routine +** removes the root element from the heap (the minimum value in the heap) +** and then move other nodes around as necessary to preserve the heap +** property. +** +** This heap is used for cell overlap and coverage testing. Each u32 +** entry represents the span of a cell or freeblock on a btree page. +** The upper 16 bits are the index of the first byte of a range and the +** lower 16 bits are the index of the last byte of that range. +*/ +static void btreeHeapInsert(u32 *aHeap, u32 x){ + u32 j, i = ++aHeap[0]; + aHeap[i] = x; + while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){ + x = aHeap[j]; + aHeap[j] = aHeap[i]; + aHeap[i] = x; + i = j; + } +} +static int btreeHeapPull(u32 *aHeap, u32 *pOut){ + u32 j, i, x; + if( (x = aHeap[0])==0 ) return 0; + *pOut = aHeap[1]; + aHeap[1] = aHeap[x]; + aHeap[x] = 0xffffffff; + aHeap[0]--; + i = 1; + while( (j = i*2)<=aHeap[0] ){ + if( aHeap[j]>aHeap[j+1] ) j++; + if( aHeap[i]zPfx; @@ -8700,15 +8757,15 @@ static int checkTreePage( */ data = pPage->aData; hdr = pPage->hdrOffset; - hit = sqlite3PageMalloc( pBt->pageSize ); + heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); pCheck->zPfx = 0; - if( hit==0 ){ + if( heap==0 ){ pCheck->mallocFailed = 1; }else{ int contentOffset = get2byteNotZero(&data[hdr+5]); assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ - memset(hit+contentOffset, 0, usableSize-contentOffset); - memset(hit, 1, contentOffset); + heap[0] = 0; + btreeHeapInsert(heap, contentOffset-1); /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the ** number of cells on the page. */ nCell = get2byte(&data[hdr+3]); @@ -8720,7 +8777,6 @@ static int checkTreePage( for(i=0; i=pc; j--) hit[j]++; + btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); } } /* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header @@ -8741,7 +8797,7 @@ static int checkTreePage( assert( i<=usableSize-4 ); /* Enforced by btreeInitPage() */ size = get2byte(&data[i+2]); assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */ - for(j=i+size-1; j>=i; j--) hit[j]++; + btreeHeapInsert(heap, (i<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next ** freeblock in the chain, or zero if the freeblock is the last on the @@ -8753,27 +8809,33 @@ static int checkTreePage( assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */ i = j; } - for(i=cnt=0; i1 ){ + cnt = 0; + assert( heap[0]>0 ); + assert( (heap[1]>>16)==0 ); + btreeHeapPull(heap,&prev); + while( btreeHeapPull(heap,&x) ){ + if( (prev&0xffff)+1>(x>>16) ){ checkAppendMsg(pCheck, - "Multiple uses for byte %d of page %d", i, iPage); + "Multiple uses for byte %u of page %d", x>>16, iPage); break; + }else{ + cnt += (x>>16) - (prev&0xffff) - 1; + prev = x; } } + cnt += usableSize - (prev&0xffff) - 1; /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments ** is stored in the fifth field of the b-tree page header. ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the ** number of fragmented free bytes within the cell content area. */ - if( cnt!=data[hdr+7] ){ + if( heap[0]==0 && cnt!=data[hdr+7] ){ checkAppendMsg(pCheck, "Fragmentation of %d bytes reported as %d on page %d", cnt, data[hdr+7], iPage); } } - sqlite3PageFree(hit); + sqlite3PageFree(heap); releasePage(pPage); end_of_check: diff --git a/src/build.c b/src/build.c index 3021ad4e51..11f0b39245 100644 --- a/src/build.c +++ b/src/build.c @@ -142,9 +142,11 @@ void sqlite3FinishCoding(Parse *pParse){ assert( pParse->pToplevel==0 ); db = pParse->db; - if( db->mallocFailed ) return; if( pParse->nested ) return; - if( pParse->nErr ) return; + if( db->mallocFailed || pParse->nErr ){ + if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; + return; + } /* Begin by generating some termination code at the end of the ** vdbe program @@ -761,14 +763,12 @@ int sqlite3TwoPartName( if( ALWAYS(pName2!=0) && pName2->n>0 ){ if( db->init.busy ) { sqlite3ErrorMsg(pParse, "corrupt database"); - pParse->nErr++; return -1; } *pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); - pParse->nErr++; return -1; } }else{ @@ -927,7 +927,7 @@ void sqlite3StartTable( if( !noErr ){ sqlite3ErrorMsg(pParse, "table %T already exists", pName); }else{ - assert( !db->init.busy ); + assert( !db->init.busy || CORRUPT_DB ); sqlite3CodeVerifySchema(pParse, iDb); } goto begin_table_error; @@ -1216,7 +1216,8 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){ p = pParse->pNewTable; if( p==0 || NEVER(p->nCol<1) ) return; pCol = &p->aCol[p->nCol-1]; - assert( pCol->zType==0 ); + assert( pCol->zType==0 || CORRUPT_DB ); + sqlite3DbFree(pParse->db, pCol->zType); pCol->zType = sqlite3NameFromToken(pParse->db, pType); pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst); } @@ -2450,6 +2451,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); + if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; @@ -2857,8 +2859,7 @@ Index *sqlite3CreateIndex( char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ - assert( pParse->nErr==0 ); /* Never called with prior errors */ - if( db->mallocFailed || IN_DECLARE_VTAB ){ + if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ diff --git a/src/expr.c b/src/expr.c index 77eb35aa74..3f8bd942ef 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1251,7 +1251,8 @@ u32 sqlite3ExprListFlags(const ExprList *pList){ u32 m = 0; if( pList ){ for(i=0; inExpr; i++){ - m |= pList->a[i].pExpr->flags; + Expr *pExpr = pList->a[i].pExpr; + if( ALWAYS(pExpr) ) m |= pList->a[i].pExpr->flags; } } return m; @@ -2016,7 +2017,7 @@ int sqlite3CodeSubselect( pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[1]); pSel->iLimit = 0; - pSel->selFlags &= ~SF_AllValues; + pSel->selFlags &= ~SF_MultiValue; if( sqlite3Select(pParse, pSel, &dest) ){ return 0; } @@ -4017,7 +4018,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; - if( ALWAYS((combinedFlags & EP_Reduced)==0) ){ + if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->iTable!=pB->iTable && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; diff --git a/src/insert.c b/src/insert.c index 805e850089..8994e01746 100644 --- a/src/insert.c +++ b/src/insert.c @@ -342,20 +342,23 @@ static int xferOptimization( /* ** This routine is called to handle SQL of the following forms: ** -** insert into TABLE (IDLIST) values(EXPRLIST) +** insert into TABLE (IDLIST) values(EXPRLIST),(EXPRLIST),... ** insert into TABLE (IDLIST) select +** insert into TABLE (IDLIST) default values ** ** The IDLIST following the table name is always optional. If omitted, -** then a list of all columns for the table is substituted. The IDLIST -** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted. +** then a list of all (non-hidden) columns for the table is substituted. +** The IDLIST appears in the pColumn parameter. pColumn is NULL if IDLIST +** is omitted. ** -** The pList parameter holds EXPRLIST in the first form of the INSERT -** statement above, and pSelect is NULL. For the second form, pList is -** NULL and pSelect is a pointer to the select statement used to generate -** data for the insert. +** For the pSelect parameter holds the values to be inserted for the +** first two forms shown above. A VALUES clause is really just short-hand +** for a SELECT statement that omits the FROM clause and everything else +** that follows. If the pSelect parameter is NULL, that means that the +** DEFAULT VALUES form of the INSERT statement is intended. ** ** The code generated follows one of four templates. For a simple -** insert with data coming from a VALUES clause, the code executes +** insert with data coming from a single-row VALUES clause, the code executes ** once straight down through. Pseudo-code follows (we call this ** the "1st template"): ** @@ -462,7 +465,7 @@ void sqlite3Insert( u8 useTempTable = 0; /* Store SELECT results in intermediate table */ u8 appendFlag = 0; /* True if the insert is likely to be an append */ u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ - u8 bIdListInOrder = 1; /* True if IDLIST is in table order */ + u8 bIdListInOrder; /* True if IDLIST is in table order */ ExprList *pList = 0; /* List of VALUES() to be inserted */ /* Register allocations */ @@ -487,8 +490,8 @@ void sqlite3Insert( } /* If the Select object is really just a simple VALUES() list with a - ** single row values (the common case) then keep that one row of values - ** and go ahead and discard the Select object + ** single row (the common case) then keep that one row of values + ** and discard the other (unused) parts of the pSelect object */ if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){ pList = pSelect->pEList; @@ -596,6 +599,7 @@ void sqlite3Insert( ** is appears in the original table. (The index of the INTEGER ** PRIMARY KEY in the original table is pTab->iPKey.) */ + bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0; if( pColumn ){ for(i=0; inId; i++){ pColumn->a[i].idx = -1; @@ -631,7 +635,8 @@ void sqlite3Insert( ** co-routine is the common header to the 3rd and 4th templates. */ if( pSelect ){ - /* Data is coming from a SELECT. Generate a co-routine to run the SELECT */ + /* Data is coming from a SELECT or from a multi-row VALUES clause. + ** Generate a co-routine to run the SELECT. */ int regYield; /* Register holding co-routine entry-point */ int addrTop; /* Top of the co-routine */ int rc; /* Result code */ @@ -644,8 +649,7 @@ void sqlite3Insert( dest.nSdst = pTab->nCol; rc = sqlite3Select(pParse, pSelect, &dest); regFromSelect = dest.iSdst; - assert( pParse->nErr==0 || rc ); - if( rc || db->mallocFailed ) goto insert_cleanup; + if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup; sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ assert( pSelect->pEList ); @@ -693,8 +697,8 @@ void sqlite3Insert( sqlite3ReleaseTempReg(pParse, regTempRowid); } }else{ - /* This is the case if the data for the INSERT is coming from a VALUES - ** clause + /* This is the case if the data for the INSERT is coming from a + ** single-row VALUES clause */ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); diff --git a/src/parse.y b/src/parse.y index b8ef26810c..6a64206ac0 100644 --- a/src/parse.y +++ b/src/parse.y @@ -409,28 +409,35 @@ cmd ::= select(X). { %type oneselect {Select*} %destructor oneselect {sqlite3SelectDelete(pParse->db, $$);} -select(A) ::= with(W) selectnowith(X). { - Select *p = X, *pNext, *pLoop; - if( p ){ - int cnt = 0, mxSelect; - p->pWith = W; +%include { + /* + ** For a compound SELECT statement, make sure p->pPrior->pNext==p for + ** all elements in the list. And make sure list length does not exceed + ** SQLITE_LIMIT_COMPOUND_SELECT. + */ + static void parserDoubleLinkSelect(Parse *pParse, Select *p){ if( p->pPrior ){ - u16 allValues = SF_Values; - pNext = 0; + Select *pNext = 0, *pLoop; + int mxSelect, cnt = 0; for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ pLoop->pNext = pNext; pLoop->selFlags |= SF_Compound; - allValues &= pLoop->selFlags; } - if( allValues ){ - p->selFlags |= SF_AllValues; - }else if( - (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 - && cnt>mxSelect + if( (p->selFlags & SF_MultiValue)==0 && + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && + cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } } + } +} + +select(A) ::= with(W) selectnowith(X). { + Select *p = X; + if( p ){ + p->pWith = W; + parserDoubleLinkSelect(pParse, p); }else{ sqlite3WithDelete(pParse->db, W); } @@ -445,12 +452,14 @@ selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). { SrcList *pFrom; Token x; x.n = 0; + parserDoubleLinkSelect(pParse, pRhs); pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0); } if( pRhs ){ pRhs->op = (u8)Y; pRhs->pPrior = X; + pRhs->selFlags &= ~SF_MultiValue; if( Y!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, X); @@ -498,13 +507,16 @@ values(A) ::= VALUES LP nexprlist(X) RP. { A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0,0); } values(A) ::= values(X) COMMA LP exprlist(Y) RP. { - Select *pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values,0,0); + Select *pRight, *pLeft = X; + pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); + if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; - pRight->pPrior = X; + pLeft = X; + pRight->pPrior = pLeft; A = pRight; }else{ - A = X; + A = pLeft; } } diff --git a/src/pragma.c b/src/pragma.c index 8f6ac64754..614daa54df 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -946,7 +946,9 @@ void sqlite3Pragma( sqlite3ErrorMsg(pParse, "Safety level may not be changed inside a transaction"); }else{ - pDb->safety_level = getSafetyLevel(zRight,0,1)+1; + int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK; + if( iLevel==0 ) iLevel = 1; + pDb->safety_level = iLevel; setAllPagerFlags(db); } } diff --git a/src/prepare.c b/src/prepare.c index 97be900d68..a55a0fee43 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -67,7 +67,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv[1]==0 ){ corruptSchema(pData, argv[0], 0); - }else if( argv[2] && argv[2][0] ){ + }else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data @@ -98,8 +98,8 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ } } sqlite3_finalize(pStmt); - }else if( argv[0]==0 ){ - corruptSchema(pData, 0, 0); + }else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){ + corruptSchema(pData, argv[0], 0); }else{ /* If the SQL column is blank it means this is an index that ** was created to be the PRIMARY KEY or to fulfill a UNIQUE diff --git a/src/resolve.c b/src/resolve.c index 6294ba26e1..32e0a98fd7 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -460,7 +460,6 @@ static int lookupName( if( cnt==0 && zTab==0 && ExprHasProperty(pExpr,EP_DblQuoted) ){ pExpr->op = TK_STRING; pExpr->pTab = 0; - pExpr->iTable = -1; return WRC_Prune; } @@ -1300,8 +1299,15 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** The ORDER BY clause for compounds SELECT statements is handled ** below, after all of the result-sets for all of the elements of ** the compound have been resolved. + ** + ** If there is an ORDER BY clause on a term of a compound-select other + ** than the right-most term, then that is a syntax error. But the error + ** is not detected until much later, and so we need to go ahead and + ** resolve those symbols on the incorrect ORDER BY for consistency. */ - if( !isCompound && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") ){ + if( isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ + && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") + ){ return WRC_Abort; } if( db->mallocFailed ){ diff --git a/src/select.c b/src/select.c index bed1f80be0..c49f327893 100644 --- a/src/select.c +++ b/src/select.c @@ -111,7 +111,6 @@ Select *sqlite3SelectNew( Select standin; sqlite3 *db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); - assert( db->mallocFailed || !pOffset || pLimit ); /* OFFSET implies LIMIT */ if( pNew==0 ){ assert( db->mallocFailed ); pNew = &standin; @@ -131,7 +130,7 @@ Select *sqlite3SelectNew( pNew->op = TK_SELECT; pNew->pLimit = pLimit; pNew->pOffset = pOffset; - assert( pOffset==0 || pLimit!=0 ); + assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 ); pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; if( db->mallocFailed ) { @@ -1381,7 +1380,7 @@ static const char *columnTypeImpl( ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ - if( iCol>=0 && ALWAYS(iColpEList->nExpr) ){ + if( iCol>=0 && iColpEList->nExpr ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. @@ -2108,8 +2107,7 @@ static int multiSelectValues( int nExpr = p->pEList->nExpr; int nRow = 1; int rc = 0; - assert( p->pNext==0 ); - assert( p->selFlags & SF_AllValues ); + assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); @@ -2218,7 +2216,7 @@ static int multiSelect( /* Special handling for a compound-select that originates as a VALUES clause. */ - if( p->selFlags & SF_AllValues ){ + if( p->selFlags & SF_MultiValue ){ rc = multiSelectValues(pParse, p, &dest); goto multi_select_end; } @@ -2629,7 +2627,7 @@ static int generateOutputSubroutine( ** of the scan loop. */ case SRT_Mem: { - assert( pIn->nSdst==1 ); + assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 ); sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1); /* The LIMIT clause will jump out of the loop for us */ break; @@ -2860,8 +2858,10 @@ static int multiSelectOrderBy( if( aPermute ){ struct ExprList_item *pItem; for(i=0, pItem=pOrderBy->a; iu.x.iOrderByCol>0 - && pItem->u.x.iOrderByCol<=p->pEList->nExpr ); + assert( pItem->u.x.iOrderByCol>0 ); + /* assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ) is also true + ** but only for well-formed SELECT statements. */ + testcase( pItem->u.x.iOrderByCol > p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; } pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1); @@ -4422,7 +4422,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; - if( (pSelect->selFlags & SF_AllValues)==0 ){ + if( (pSelect->selFlags & SF_MultiValue)==0 ){ w.xSelectCallback2 = selectPopWith; } sqlite3WalkSelect(&w, pSelect); @@ -5483,10 +5483,9 @@ int sqlite3Select( */ sqlite3VdbeResolveLabel(v, iEnd); - /* The SELECT was successfully coded. Set the return code to 0 - ** to indicate no errors. - */ - rc = 0; + /* The SELECT has been coded. If there is an error in the Parse structure, + ** set the return code to 1. Otherwise 0. */ + rc = (pParse->nErr>0); /* Control jumps to here if an error is encountered above, or upon ** successful coding of the SELECT. diff --git a/src/shell.c b/src/shell.c index e6f592640e..47a28c2c57 100644 --- a/src/shell.c +++ b/src/shell.c @@ -540,6 +540,7 @@ struct ShellState { int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ int statsOn; /* True to display memory stats before each finalize */ int scanstatsOn; /* True to display scan stats before each finalize */ + int backslashOn; /* Resolve C-style \x escapes in SQL input text */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ @@ -2033,7 +2034,7 @@ static void resolve_backslashes(char *z){ char c; while( *z && *z!='\\' ) z++; for(i=j=0; (c = z[i])!=0; i++, j++){ - if( c=='\\' ){ + if( c=='\\' && z[i+1]!=0 ){ c = z[++i]; if( c=='n' ){ c = '\n'; @@ -4392,6 +4393,7 @@ static int process_input(ShellState *p, FILE *in){ && sqlite3_complete(zSql) ){ p->cnt = 0; open_db(p, 0); + if( p->backslashOn ) resolve_backslashes(zSql); BEGIN_TIMER; rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg); END_TIMER; @@ -4858,6 +4860,13 @@ int SQLITE_CDECL main(int argc, char **argv){ data.statsOn = 1; }else if( strcmp(z,"-scanstats")==0 ){ data.scanstatsOn = 1; + }else if( strcmp(z,"-backslash")==0 ){ + /* Undocumented command-line option: -backslash + ** Causes C-style backslash escapes to be evaluated in SQL statements + ** prior to sending the SQL into SQLite. Useful for injecting + ** crazy bytes in the middle of SQL statements for testing and debugging. + */ + data.backslashOn = 1; }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; }else if( strcmp(z,"-version")==0 ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 136c5e1c4f..eaa4a32ad0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1630,6 +1630,12 @@ struct Table { /* ** Allowed values for Table.tabFlags. +** +** TF_OOOHidden applies to virtual tables that have hidden columns that are +** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING +** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden, +** the TF_OOOHidden attribute would apply in this case. Such tables require +** special handling during INSERT processing. */ #define TF_Readonly 0x01 /* Read-only system table */ #define TF_Ephemeral 0x02 /* An ephemeral table */ @@ -1637,6 +1643,7 @@ struct Table { #define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */ #define TF_Virtual 0x10 /* Is a virtual table */ #define TF_WithoutRowid 0x20 /* No rowid used. PRIMARY KEY is the key */ +#define TF_OOOHidden 0x40 /* Out-of-Order hidden columns */ /* @@ -2393,7 +2400,7 @@ struct Select { #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ #define SF_Compound 0x0040 /* Part of a compound query */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ -#define SF_AllValues 0x0100 /* All terms of compound are VALUES */ +#define SF_MultiValue 0x0100 /* Single VALUES term with multiple rows */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ diff --git a/src/tokenize.c b/src/tokenize.c index 2f8fd98ede..076acb0209 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -516,8 +516,6 @@ abort_parse: pParse->pZombieTab = p->pNextZombie; sqlite3DeleteTable(db, p); } - if( nErr>0 && pParse->rc==SQLITE_OK ){ - pParse->rc = SQLITE_ERROR; - } + assert( nErr==0 || pParse->rc!=SQLITE_OK ); return nErr; } diff --git a/src/trigger.c b/src/trigger.c index ed152d2a8a..1bc232727f 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -193,7 +193,6 @@ void sqlite3BeginTrigger( /* Do not create a trigger on a system table */ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); - pParse->nErr++; goto trigger_cleanup; } @@ -795,6 +794,7 @@ static void transferParseError(Parse *pTo, Parse *pFrom){ if( pTo->nErr==0 ){ pTo->zErrMsg = pFrom->zErrMsg; pTo->nErr = pFrom->nErr; + pTo->rc = pFrom->rc; }else{ sqlite3DbFree(pFrom->db, pFrom->zErrMsg); } diff --git a/src/util.c b/src/util.c index 6e64242e87..0bc1eeacf4 100644 --- a/src/util.c +++ b/src/util.c @@ -655,6 +655,7 @@ int sqlite3GetInt32(const char *zNum, int *pValue){ } } #endif + while( zNum[0]=='0' ) zNum++; for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; } diff --git a/src/vdbe.c b/src/vdbe.c index b2f52b1036..ca5f0b187c 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -549,6 +549,9 @@ int sqlite3VdbeExec( ){ Op *aOp = p->aOp; /* Copy of p->aOp */ Op *pOp = aOp; /* Current operation */ +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + Op *pOrigOp; /* Value of pOp at the top of the loop */ +#endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ @@ -691,6 +694,9 @@ int sqlite3VdbeExec( memAboutToChange(p, &aMem[pOp->p3]); } #endif +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + pOrigOp = pOp; +#endif switch( pOp->opcode ){ @@ -2929,7 +2935,7 @@ case OP_Savepoint: { db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } - if( !isTransaction ){ + if( !isTransaction || p1==SAVEPOINT_ROLLBACK ){ rc = sqlite3VtabSavepoint(db, p1, iSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; } @@ -6549,8 +6555,8 @@ default: { /* This is really OP_Noop and OP_Explain */ #ifdef VDBE_PROFILE { u64 endTime = sqlite3Hwtime(); - if( endTime>start ) pOp->cycles += endTime - start; - pOp->cnt++; + if( endTime>start ) pOrigOp->cycles += endTime - start; + pOrigOp->cnt++; } #endif @@ -6560,16 +6566,16 @@ default: { /* This is really OP_Noop and OP_Explain */ ** the evaluator loop. So we can leave it out when NDEBUG is defined. */ #ifndef NDEBUG - assert( pOp>=&aOp[-1] && pOp<&aOp[p->nOp] ); + assert( pOp>=&aOp[-1] && pOp<&aOp[p->nOp-1] ); #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ if( rc!=0 ) printf("rc=%d\n",rc); - if( pOp->opflags & (OPFLG_OUT2) ){ - registerTrace(pOp->p2, &aMem[pOp->p2]); + if( pOrigOp->opflags & (OPFLG_OUT2) ){ + registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]); } - if( pOp->opflags & OPFLG_OUT3 ){ - registerTrace(pOp->p3, &aMem[pOp->p3]); + if( pOrigOp->opflags & OPFLG_OUT3 ){ + registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); } } #endif /* SQLITE_DEBUG */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 99c6219972..377318a784 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1790,6 +1790,22 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ #endif } +/* +** Close all cursors in the current frame. +*/ +static void closeCursorsInFrame(Vdbe *p){ + if( p->apCsr ){ + int i; + for(i=0; inCursor; i++){ + VdbeCursor *pC = p->apCsr[i]; + if( pC ){ + sqlite3VdbeFreeCursor(p, pC); + p->apCsr[i] = 0; + } + } + } +} + /* ** Copy the values stored in the VdbeFrame structure to its Vdbe. This ** is used, for example, when a trigger sub-program is halted to restore @@ -1797,6 +1813,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ */ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ Vdbe *v = pFrame->v; + closeCursorsInFrame(v); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS v->anExec = pFrame->anExec; #endif @@ -1831,17 +1848,7 @@ static void closeAllCursors(Vdbe *p){ p->nFrame = 0; } assert( p->nFrame==0 ); - - if( p->apCsr ){ - int i; - for(i=0; inCursor; i++){ - VdbeCursor *pC = p->apCsr[i]; - if( pC ){ - sqlite3VdbeFreeCursor(p, pC); - p->apCsr[i] = 0; - } - } - } + closeCursorsInFrame(p); if( p->aMem ){ releaseMemArray(&p->aMem[1], p->nMem); } diff --git a/src/vdbetrace.c b/src/vdbetrace.c index 507c2f12fc..fe0dfd3f7a 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -95,6 +95,8 @@ char *sqlite3VdbeExpandSql( assert( (zRawSql - zStart) > 0 ); sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart)); } + }else if( p->nVar==0 ){ + sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql)); }else{ while( zRawSql[0] ){ n = findNextHostParameter(zRawSql, &nToken); @@ -111,10 +113,12 @@ char *sqlite3VdbeExpandSql( idx = nextIndex; } }else{ - assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' ); + assert( zRawSql[0]==':' || zRawSql[0]=='$' || + zRawSql[0]=='@' || zRawSql[0]=='#' ); testcase( zRawSql[0]==':' ); testcase( zRawSql[0]=='$' ); testcase( zRawSql[0]=='@' ); + testcase( zRawSql[0]=='#' ); idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); assert( idx>0 ); } diff --git a/src/vtab.c b/src/vtab.c index 9629a00dcb..2c6d106794 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -472,7 +472,7 @@ void sqlite3VtabArgExtend(Parse *pParse, Token *p){ pArg->z = p->z; pArg->n = p->n; }else{ - assert(pArg->z < p->z); + assert(pArg->z <= p->z); pArg->n = (int)(&p->z[p->n] - pArg->z); } } @@ -559,6 +559,7 @@ static int vtabCallConstructor( rc = SQLITE_ERROR; }else{ int iCol; + u8 oooHidden = 0; /* If everything went according to plan, link the new VTable structure ** into the linked list headed by pTab->pVTable. Then loop through the ** columns of the table to see if any of them contain the token "hidden". @@ -571,7 +572,10 @@ static int vtabCallConstructor( char *zType = pTab->aCol[iCol].zType; int nType; int i = 0; - if( !zType ) continue; + if( !zType ){ + pTab->tabFlags |= oooHidden; + continue; + } nType = sqlite3Strlen30(zType); if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){ for(i=0; iaCol[iCol].colFlags |= COLFLAG_HIDDEN; + oooHidden = TF_OOOHidden; + }else{ + pTab->tabFlags |= oooHidden; } } } @@ -957,7 +964,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ int rc = SQLITE_OK; assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); - assert( iSavepoint>=0 ); + assert( iSavepoint>=-1 ); if( db->aVTrans ){ int i; for(i=0; rc==SQLITE_OK && inVTrans; i++){ diff --git a/test/analyze.test b/test/analyze.test index c445084263..af277cc835 100644 --- a/test/analyze.test +++ b/test/analyze.test @@ -359,6 +359,6 @@ do_test analyze-99.1 { catchsql { ANALYZE } -} {1 {malformed database schema (sqlite_stat1) - near "nonsense": syntax error}} +} {1 {malformed database schema (sqlite_stat1)}} finish_test diff --git a/test/corruptC.test b/test/corruptC.test index adf6f44c44..a7f93c46d2 100644 --- a/test/corruptC.test +++ b/test/corruptC.test @@ -292,7 +292,7 @@ do_test corruptC-2.15 { hexio_write test.db 986 b9 sqlite3 db test.db catchsql {SELECT count(*) FROM sqlite_master;} -} {1 {malformed database schema (t1i1) - no such table: main.t1}} +} {1 {database disk image is malformed}} # # Now test for a series of quasi-random seeds. diff --git a/test/e_reindex.test b/test/e_reindex.test index 4b86787a05..fa66aa7a1f 100644 --- a/test/e_reindex.test +++ b/test/e_reindex.test @@ -48,8 +48,11 @@ do_execsql_test e_reindex-1.1 { INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); + + CREATE TABLE saved(a,b,c,d,e); + INSERT INTO saved SELECT * FROM sqlite_master WHERE type = 'index'; PRAGMA writable_schema = 1; - UPDATE sqlite_master SET sql = '-- ' || sql WHERE type = 'index'; + DELETE FROM sqlite_master WHERE type = 'index'; } {} db close @@ -59,7 +62,8 @@ do_execsql_test e_reindex-1.2 { INSERT INTO t1 VALUES(7, 8); INSERT INTO t1 VALUES(9, 10); PRAGMA writable_schema = 1; - UPDATE sqlite_master SET sql = substr(sql, 4) WHERE type = 'index'; + INSERT INTO sqlite_master SELECT * FROM saved; + DROP TABLE saved; } {} db close diff --git a/test/expr.test b/test/expr.test index 8d913d2a1a..7d7b8ce5a7 100644 --- a/test/expr.test +++ b/test/expr.test @@ -943,5 +943,13 @@ do_realnum_test expr-13.7 { } } {9.22337203685478e+18} +do_execsql_test expr-13.8 { + SELECT "" <= ''; +} {1} +do_execsql_test expr-13.9 { + SELECT '' <= ""; +} {1} + + finish_test diff --git a/test/fkey2.test b/test/fkey2.test index 8b2871e5a6..aec75ed693 100644 --- a/test/fkey2.test +++ b/test/fkey2.test @@ -676,6 +676,11 @@ do_test fkey2-9.2.3 { SELECT * FROM cc; } } {{} A {} {} B {} 3 A 2 3 B 2} +do_execsql_test fkey2-9.3.0 { + CREATE TABLE t3(x PRIMARY KEY REFERENCES t3 ON DELETE SET NULL); + INSERT INTO t3(x) VALUES(12345); + DROP TABLE t3; +} {} #------------------------------------------------------------------------- # The following tests, fkey2-10.*, test "foreign key mismatch" and @@ -2014,4 +2019,18 @@ do_test fkey2-ce7c13.1.6 { } } {1 {FOREIGN KEY constraint failed}} +# 2015-04-16: Foreign key errors propagate back up to the parser. +# +do_test fkey2-20150416-100 { + db close + sqlite3 db :memory: + catchsql { + PRAGMA foreign_keys=1; + CREATE TABLE t1(x PRIMARY KEY); + CREATE TABLE t(y REFERENCES t0(x)ON DELETE SET DEFAULT); + CREATE TABLE t0(y REFERENCES t1 ON DELETE SET NULL); + REPLACE INTO t1 SELECT(0);CREATE TABLE t2(x);CREATE TABLE t3; + } +} {1 {foreign key mismatch - "t" referencing "t0"}} + finish_test diff --git a/test/fts3aa.test b/test/fts3aa.test index 6ff384a0d3..08d825dd17 100644 --- a/test/fts3aa.test +++ b/test/fts3aa.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix fts3aa # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { @@ -221,5 +222,26 @@ do_catchsql_test fts3aa-7.5 { CREATE VIRTUAL TABLE t4 USING fts4(tokenize=simple, tokenize=simple); } {1 {unrecognized parameter: tokenize=simple}} +do_execsql_test 8.0 { + CREATE VIRTUAL TABLE t0 USING fts4(order=desc); + BEGIN; + INSERT INTO t0(rowid, content) VALUES(1, 'abc'); + UPDATE t0 SET docid=5 WHERE docid=1; + INSERT INTO t0(rowid, content) VALUES(6, 'abc'); +} +do_execsql_test 8.1 { + SELECT docid FROM t0 WHERE t0 MATCH 'abc'; +} {6 5} +do_execsql_test 8.2 { + SELECT docid FROM t0 WHERE t0 MATCH '"abc abc"'; +} {} +do_execsql_test 8.3 { COMMIT } +do_execsql_test 8.4 { + SELECT docid FROM t0 WHERE t0 MATCH 'abc'; +} {6 5} +do_execsql_test 8.5 { + SELECT docid FROM t0 WHERE t0 MATCH '"abc abc"'; +} {} + finish_test diff --git a/test/index3.test b/test/index3.test index a9f9b7ae6f..0cdc6e088d 100644 --- a/test/index3.test +++ b/test/index3.test @@ -51,6 +51,6 @@ do_test index3-99.1 { db close catch { sqlite3 db test.db } catchsql { DROP INDEX i1 } -} {1 {malformed database schema (t1) - near "nonsense": syntax error}} +} {1 {malformed database schema (t1)}} finish_test diff --git a/test/index7.test b/test/index7.test index 9a2444a87e..557fe21324 100644 --- a/test/index7.test +++ b/test/index7.test @@ -311,5 +311,9 @@ do_eqp_test index7-6.4 { } { 0 0 0 {SEARCH TABLE t4 USING INDEX i4 (c=?)} } +do_catchsql_test index7-6.5 { + CREATE INDEX t5a ON t5(a) WHERE a=#1; +} {1 {near "#1": syntax error}} + finish_test diff --git a/test/insert4.test b/test/insert4.test index 889d5e7807..3eece87e5f 100644 --- a/test/insert4.test +++ b/test/insert4.test @@ -560,5 +560,10 @@ do_test insert4-8.25 { } } {1 3} +do_catchsql_test insert4-9.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(x); + INSERT INTO t1(x) VALUES(5 COLLATE xyzzy) UNION SELECT 0; +} {1 {no such collation sequence: xyzzy}} finish_test diff --git a/test/misc1.test b/test/misc1.test index 1b98eafc6a..7ae50e4fe0 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -644,4 +644,44 @@ do_execsql_test misc1-22.1 { SELECT ""+3 FROM (SELECT ""+5); } {3} +# 2015-04-19: NULL pointer dereference on a corrupt schema +# +db close +sqlite3 db :memory: +do_execsql_test misc1-23.1 { + CREATE TABLE t1(x); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE table t(d CHECK(T(#0)'; + BEGIN; + CREATE TABLE t2(y); + ROLLBACK; + DROP TABLE IF EXISTS t3; +} {} + +# 2015-04-19: Faulty assert() statement +# +db close +database_may_be_corrupt +sqlite3 db :memory: +do_catchsql_test misc1-23.2 { + CREATE TABLE t1(x UNIQUE); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE TABLE IF not EXISTS t(c)'; + BEGIN; + CREATE TABLE t2(x); + ROLLBACK; + DROP TABLE F; +} {1 {no such table: F}} +db close +sqlite3 db :memory: +do_catchsql_test misc1-23.3 { + CREATE TABLE t1(x UNIQUE); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE table y(a TEXT, a TEXT)'; + BEGIN; + CREATE TABLE t2(y); + ROLLBACK; + DROP TABLE IF EXISTS t; +} {0 {}} + finish_test diff --git a/test/misc5.test b/test/misc5.test index 14ba44ead0..30176b8082 100644 --- a/test/misc5.test +++ b/test/misc5.test @@ -583,6 +583,24 @@ do_test misc5-7.1 { catchsql $sql } {1 {parser stack overflow}} +# Parser stack overflow is silently ignored when it occurs while parsing the +# schema and PRAGMA writable_schema is turned on. +# +do_test misc5-7.2 { + sqlite3 db2 :memory: + catchsql { + CREATE TABLE t1(x UNIQUE); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE table t(o CHECK(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((;VALUES(o)'; + BEGIN; + CREATE TABLE t2(y); + ROLLBACK; + DROP TABLE IF EXISTS D; + } db2 +} {0 {}} +db2 close + + # Ticket #1911 # ifcapable compound { diff --git a/test/pragma.test b/test/pragma.test index e8a53f442d..587a03c8a6 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -219,6 +219,24 @@ do_test pragma-1.14 { PRAGMA synchronous; } } {2} +do_test pragma-1.14.1 { + execsql { + PRAGMA synchronous=4; + PRAGMA synchronous; + } +} {0} +do_test pragma-1.14.2 { + execsql { + PRAGMA synchronous=3; + PRAGMA synchronous; + } +} {0} +do_test pragma-1.14.3 { + execsql { + PRAGMA synchronous=10; + PRAGMA synchronous; + } +} {2} } ;# ifcapable pager_pragmas # Test turning "flag" pragmas on and off. diff --git a/test/releasetest.tcl b/test/releasetest.tcl index 746fc9bb35..95cacf590f 100644 --- a/test/releasetest.tcl +++ b/test/releasetest.tcl @@ -14,6 +14,7 @@ optional) are: --config CONFIGNAME (Run only CONFIGNAME) --quick (Run "veryquick.test" only) --veryquick (Run "make smoketest" only) + --msvc (Use MSVC as the compiler) --buildonly (Just build testfixture - do not run) --dryrun (Print what would have happened) --info (Show diagnostic info) @@ -22,8 +23,9 @@ The default value for --srcdir is the parent of the directory holding this script. The script determines the default value for --platform using the -$tcl_platform(os) and $tcl_platform(machine) variables. Supported -platforms are "Linux-x86", "Linux-x86_64" and "Darwin-i386". +$tcl_platform(os) and $tcl_platform(machine) variables. Supported +platforms are "Linux-x86", "Linux-x86_64", "Darwin-i386", +"Darwin-x86_64", "Windows NT-intel", and "Windows NT-amd64". Every test begins with a fresh run of the configure script at the top of the SQLite source tree. @@ -238,6 +240,10 @@ array set ::Platforms [strip_comments { "Default" "mptest fulltestonly" "Have-Not" test } + "Windows NT-amd64" { + "Default" "mptest fulltestonly" + "Have-Not" test + } # The Failure-Detection platform runs various tests that deliberately # fail. This is used as a test of this script to verify that this script @@ -296,6 +302,13 @@ proc count_tests_and_errors {logfile rcVar errmsgVar} { set errmsg $msg } } + if {[regexp {fatal error +(.*)} $line all msg]} { + incr ::NERRCASE + if {$rc==0} { + set rc 1 + set errmsg $msg + } + } if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { incr ::NERRCASE if {$rc==0} { @@ -314,7 +327,13 @@ proc count_tests_and_errors {logfile rcVar errmsgVar} { } } close $fd - if {!$seen} { + if {$::BUILDONLY} { + if {$rc==0} { + set errmsg "Build complete" + } else { + set errmsg "Build failed" + } + } elseif {!$seen} { set rc 1 set errmsg "Test did not complete" if {[file readable core]} { @@ -329,7 +348,7 @@ proc run_test_suite {name testtarget config} { # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but # CFLAGS is only passed to gcc. # - set cflags "-g" + set cflags [expr {$::MSVC ? "-Zi" : "-g"}] set opts "" set title ${name}($testtarget) set configOpts "" @@ -349,7 +368,14 @@ proc run_test_suite {name testtarget config} { set cflags [join $cflags " "] set opts [join $opts " "] - append opts " -DSQLITE_NO_SYNC=1 -DHAVE_USLEEP" + append opts " -DSQLITE_NO_SYNC=1" + + # Some configurations already set HAVE_USLEEP; in that case, skip it. + # + if {![regexp { -DHAVE_USLEEP$} $opts] + && ![regexp { -DHAVE_USLEEP[ =]+} $opts]} { + append opts " -DHAVE_USLEEP=1" + } # Set the sub-directory to use. # @@ -390,10 +416,10 @@ proc run_test_suite {name testtarget config} { if {$rc} { puts " FAIL $tm" incr ::NERR - if {$errmsg!=""} {puts " $errmsg"} } else { puts " Ok $tm" } + if {$errmsg!=""} {puts " $errmsg"} } } @@ -401,6 +427,7 @@ proc run_test_suite {name testtarget config} { # the current platform, which may be Windows (via MinGW, etc). # proc configureCommand {opts} { + if {$::MSVC} return [list]; # This is not needed for MSVC. set result [list trace_cmd exec] if {$::tcl_platform(platform)=="windows"} { lappend result sh @@ -414,7 +441,14 @@ proc configureCommand {opts} { # specified targets, compiler flags, and options. # proc makeCommand { targets cflags opts } { - set result [list trace_cmd exec make clean] + set result [list trace_cmd exec] + if {$::MSVC} { + set nmakeDir [file nativename $::SRCDIR] + set nmakeFile [file join $nmakeDir Makefile.msc] + lappend result nmake /f $nmakeFile TOP=$nmakeDir clean + } else { + lappend result make clean + } foreach target $targets { lappend result $target } @@ -443,6 +477,7 @@ proc trace_cmd {args} { proc process_options {argv} { set ::SRCDIR [file normalize [file dirname [file dirname $::argv0]]] set ::QUICK 0 + set ::MSVC 0 set ::BUILDONLY 0 set ::DRYRUN 0 set ::EXEC exec @@ -476,6 +511,10 @@ proc process_options {argv} { set config [lindex $argv $i] } + -msvc { + set ::MSVC 1 + } + -buildonly { set ::BUILDONLY 1 } @@ -494,6 +533,7 @@ proc process_options {argv} { puts " --platform [list $platform]" puts " --config [list $config]" if {$::QUICK} {puts " --quick"} + if {$::MSVC} {puts " --msvc"} if {$::BUILDONLY} {puts " --buildonly"} if {$::DRYRUN} {puts " --dryrun"} if {$::TRACE} {puts " --trace"} @@ -507,7 +547,15 @@ proc process_options {argv} { } exit } - -g - + + -g { + if {$::MSVC} { + lappend ::EXTRACONFIG -Zi + } else { + lappend ::EXTRACONFIG [lindex $argv $i] + } + } + -D* - -O* - -enable-* - @@ -547,6 +595,7 @@ proc process_options {argv} { puts -nonewline "Flags:" if {$::DRYRUN} {puts -nonewline " --dryrun"} if {$::BUILDONLY} {puts -nonewline " --buildonly"} + if {$::MSVC} {puts -nonewline " --msvc"} switch -- $::QUICK { 1 {puts -nonewline " --quick"} 2 {puts -nonewline " --veryquick"} @@ -570,12 +619,20 @@ proc main {argv} { set ::SQLITE_VERSION {} set STARTTIME [clock seconds] foreach {zConfig target} $::CONFIGLIST { + if {$::MSVC && ($zConfig eq "Sanitize" || "checksymbols" in $target + || "valgrindtest" in $target)} { + puts "Skipping $zConfig / $target for MSVC..." + continue + } if {$target ne "checksymbols"} { switch -- $::QUICK { 1 {set target test} 2 {set target smoketest} } - if {$::BUILDONLY} {set target testfixture} + if {$::BUILDONLY} { + set target testfixture + if {$::MSVC} {append target .exe} + } } set config_options [concat $::Configs($zConfig) $::EXTRACONFIG] diff --git a/test/select1.test b/test/select1.test index 875c87c84a..4d6c07f2d0 100644 --- a/test/select1.test +++ b/test/select1.test @@ -307,6 +307,9 @@ do_test select1-4.4 { set v [catch {execsql {SELECT f1 FROM test1 ORDER BY min(f1)}} msg] lappend v $msg } {1 {misuse of aggregate: min()}} +do_catchsql_test select1-4.5 { + INSERT INTO test1(f1) SELECT f1 FROM test1 ORDER BY min(f1); +} {1 {misuse of aggregate: min()}} # The restriction not allowing constants in the ORDER BY clause # has been removed. See ticket #1768 @@ -1072,5 +1075,10 @@ if {[db one {PRAGMA locking_mode}]=="normal"} { do_test select1-16.1 { catchsql {SELECT 1 FROM (SELECT *)} } {1 {no tables specified}} + +# 2015-04-17: assertion fix. +do_catchsql_test select1-16.2 { + SELECT 1 FROM sqlite_master LIMIT 1,#1; +} {1 {near "#1": syntax error}} finish_test diff --git a/test/select4.test b/test/select4.test index 2f3ddbe96a..ce7e7e7b0d 100644 --- a/test/select4.test +++ b/test/select4.test @@ -118,6 +118,10 @@ do_test select4-1.3 { }} msg] lappend v $msg } {1 {ORDER BY clause should come after UNION ALL not before}} +do_catchsql_test select4-1.4 { + SELECT (VALUES(0) INTERSECT SELECT(0) UNION SELECT(0) ORDER BY 1 UNION + SELECT 0 UNION SELECT 0 ORDER BY 1); +} {1 {ORDER BY clause should come after UNION not before}} # Union operator # @@ -148,6 +152,12 @@ do_test select4-2.3 { }} msg] lappend v $msg } {1 {ORDER BY clause should come after UNION not before}} +do_test select4-2.4 { + set v [catch {execsql { + SELECT 0 ORDER BY (SELECT 0) UNION SELECT 0; + }} msg] + lappend v $msg +} {1 {ORDER BY clause should come after UNION not before}} # Except operator # @@ -874,6 +884,14 @@ do_execsql_test select4-14.10 { do_execsql_test select4-14.11 { SELECT (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) } {1} - +do_execsql_test select4-14.12 { + VALUES(1) UNION VALUES(2); +} {1 2} +do_execsql_test select4-14.13 { + VALUES(1),(2),(3) EXCEPT VALUES(2); +} {1 3} +do_execsql_test select4-14.14 { + VALUES(1),(2),(3) EXCEPT VALUES(1),(3); +} {2} finish_test diff --git a/test/table.test b/test/table.test index 69f105aa6c..faa9712bf7 100644 --- a/test/table.test +++ b/test/table.test @@ -272,6 +272,25 @@ do_test table-5.2.1 { } } {} +do_test table-5.2.2 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + CREATE TABLE t0(a,b); + CREATE INDEX t ON t0(a); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE TABLE a.b(a UNIQUE'; + BEGIN; + CREATE TABLE t1(x); + ROLLBACK; + DROP TABLE IF EXISTS t99; + } +} {} +db close +forcedelete test.db +sqlite3 db test.db + # Make sure an EXPLAIN does not really create a new table # do_test table-5.3 { diff --git a/test/trigger7.test b/test/trigger7.test index 8fde2004f8..221962406b 100644 --- a/test/trigger7.test +++ b/test/trigger7.test @@ -114,6 +114,6 @@ do_test trigger7-99.1 { db close catch { sqlite3 db test.db } catchsql { DROP TRIGGER t2r5 } -} {1 {malformed database schema (t2r12) - near "nonsense": syntax error}} +} {1 {malformed database schema (t2r12)}} finish_test diff --git a/test/vtab1.test b/test/vtab1.test index dfc989a643..c0cf3e4e8d 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -1491,4 +1491,41 @@ do_test 23.3.1 { } {1 {database table is locked}} do_execsql_test 23.3.2 { SELECT * FROM t1e } {1 2 3 4} +#------------------------------------------------------------------------- +# At one point SQL like this: +# +# SAVEPOINT xyz; -- Opens SQL transaction +# INSERT INTO vtab -- Write to virtual table +# ROLLBACK TO xyz; +# RELEASE xyz; +# +# was not invoking the xRollbackTo() callback for the ROLLBACK TO +# operation. Which meant that virtual tables like FTS3 would incorrectly +# commit the results of the INSERT as part of the "RELEASE xyz" command. +# +# The following tests check that this has been fixed. +# +ifcapable fts3 { + do_execsql_test 24.0 { + CREATE VIRTUAL TABLE t4 USING fts3(); + SAVEPOINT a; + INSERT INTO t4 VALUES('a b c'); + ROLLBACK TO a; + RELEASE a; + SELECT * FROM t4; + } {} + + do_execsql_test 24.1 { SELECT * FROM t4 WHERE t4 MATCH 'b' } {} + do_execsql_test 24.2 { INSERT INTO t4(t4) VALUES('integrity-check') } {} + + do_execsql_test 24.3 { + SAVEPOINT a; + CREATE VIRTUAL TABLE t5 USING fts3(); + SAVEPOINT b; + ROLLBACK TO a; + SAVEPOINT c; + RELEASE a; + } +} + finish_test diff --git a/test/vtabA.test b/test/vtabA.test index 928cc2b703..eddaa70d1f 100644 --- a/test/vtabA.test +++ b/test/vtabA.test @@ -74,28 +74,39 @@ do_test vtabA-1.6 { SELECT * FROM t1e; } } {{value a} {value c}} +do_execsql_test vtabA-1.7 { + DELETE FROM t1e; + INSERT INTO t1e SELECT 'abc','def'; +} {} +do_execsql_test vtabA-1.8 { + INSERT INTO t1e VALUES('ghi','jkl'),('mno','pqr'),('stu','vwx'); +} {} +do_execsql_test vtabA-1.9 { + SELECT a,b,c, '|' FROM t1e ORDER BY 1; +} {abc {} def | ghi {} jkl | mno {} pqr | stu {} vwx |} + # Test that the expansion of a '*' expression in the result set of # a SELECT does not include the hidden column. # -do_test vtabA-1.7 { +do_test vtabA-1.20 { execsql { INSERT INTO t1e SELECT * FROM t1e; } } {} -do_test vtabA-1.8 { +do_test vtabA-1.21 { execsql { - SELECT * FROM t1e; + SELECT * FROM t1e ORDER BY 1; } -} {{value a} {value c} {value a} {value c}} +} {abc def abc def ghi jkl ghi jkl mno pqr mno pqr stu vwx stu vwx} # Test that the declaration type of the hidden column does not include # the token "HIDDEN". # -do_test vtabA-1.9 { +do_test vtabA-1.22 { get_decltype t1e b } {VARCHAR} -do_test vtabA-1.10 { +do_test vtabA-1.23 { get_collist t1e } {a c} diff --git a/tool/fuzzershell.c b/tool/fuzzershell.c new file mode 100644 index 0000000000..a44a722505 --- /dev/null +++ b/tool/fuzzershell.c @@ -0,0 +1,294 @@ +/* +** 2015-04-17 +** +** 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 is a utility program designed to aid running the SQLite library +** against an external fuzzer, such as American Fuzzy Lop (AFL) +** (http://lcamtuf.coredump.cx/afl/). Basically, this program reads +** SQL text from standard input and passes it through to SQLite for evaluation, +** just like the "sqlite3" command-line shell. Differences from the +** command-line shell: +** +** (1) The complex "dot-command" extensions are omitted. This +** prevents the fuzzer from discovering that it can run things +** like ".shell rm -rf ~" +** +** (2) The database is opened with the SQLITE_OPEN_MEMORY flag so that +** no disk I/O from the database is permitted. The ATTACH command +** with a filename still uses an in-memory database. +** +** (3) The main in-memory database can be initialized from a template +** disk database so that the fuzzer starts with a database containing +** content. +** +** (4) The eval() SQL function is added, allowing the fuzzer to do +** interesting recursive operations. +*/ +#include +#include +#include +#include +#include "sqlite3.h" + +/* +** All global variables are gathered into the "g" singleton. +*/ +struct GlobalVars { + const char *zArgv0; /* Name of program */ +} g; + + + +/* +** Print an error message and abort in such a way to indicate to the +** fuzzer that this counts as a crash. +*/ +static void abendError(const char *zFormat, ...){ + va_list ap; + fprintf(stderr, "%s: ", g.zArgv0); + va_start(ap, zFormat); + vfprintf(stderr, zFormat, ap); + va_end(ap); + fprintf(stderr, "\n"); + abort(); +} +/* +** Print an error message and quit, but not in a way that would look +** like a crash. +*/ +static void fatalError(const char *zFormat, ...){ + va_list ap; + fprintf(stderr, "%s: ", g.zArgv0); + va_start(ap, zFormat); + vfprintf(stderr, zFormat, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(1); +} + +/* +** This callback is invoked by sqlite3_log(). +*/ +static void shellLog(void *pNotUsed, int iErrCode, const char *zMsg){ + printf("LOG: (%d) %s\n", iErrCode, zMsg); +} + +/* +** This callback is invoked by sqlite3_exec() to return query results. +*/ +static int execCallback(void *NotUsed, int argc, char **argv, char **colv){ + int i; + static unsigned cnt = 0; + printf("ROW #%u:\n", ++cnt); + for(i=0; inUsed+p->szSep+1 > p->nAlloc ){ + char *zNew; + p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; + /* Using sqlite3_realloc64() would be better, but it is a recent + ** addition and will cause a segfault if loaded by an older version + ** of SQLite. */ + zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0; + if( zNew==0 ){ + sqlite3_free(p->z); + memset(p, 0, sizeof(*p)); + return 1; + } + p->z = zNew; + } + if( p->nUsed>0 ){ + memcpy(&p->z[p->nUsed], p->zSep, p->szSep); + p->nUsed += p->szSep; + } + memcpy(&p->z[p->nUsed], z, sz); + p->nUsed += sz; + } + return 0; +} + +/* +** Implementation of the eval(X) and eval(X,Y) SQL functions. +** +** Evaluate the SQL text in X. Return the results, using string +** Y as the separator. If Y is omitted, use a single space character. +*/ +static void sqlEvalFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zSql; + sqlite3 *db; + char *zErr = 0; + int rc; + struct EvalResult x; + + memset(&x, 0, sizeof(x)); + x.zSep = " "; + zSql = (const char*)sqlite3_value_text(argv[0]); + if( zSql==0 ) return; + if( argc>1 ){ + x.zSep = (const char*)sqlite3_value_text(argv[1]); + if( x.zSep==0 ) return; + } + x.szSep = (int)strlen(x.zSep); + db = sqlite3_context_db_handle(context); + rc = sqlite3_exec(db, zSql, callback, &x, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + }else if( x.zSep==0 ){ + sqlite3_result_error_nomem(context); + sqlite3_free(x.z); + }else{ + sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free); + } +} +/* End of the eval() implementation +******************************************************************************/ + +/* +** Print sketchy documentation for this utility program +*/ +static void showHelp(void){ + printf("Usage: %s [options]\n", g.zArgv0); + printf( +"Read SQL text from standard input and evaluate it.\n" +"Options:\n" +" -f FILE Read SQL text from FILE instead of standard input\n" +" --help Show this help text\n" +" --initdb DBFILE Initialize the in-memory database using template DBFILE\n" + ); +} + + +int main(int argc, char **argv){ + char *zIn = 0; /* Input text */ + int nAlloc = 0; /* Number of bytes allocated for zIn[] */ + int nIn = 0; /* Number of bytes of zIn[] used */ + size_t got; /* Bytes read from input */ + FILE *in = stdin; /* Where to read SQL text from */ + int rc = SQLITE_OK; /* Result codes from API functions */ + int i; /* Loop counter */ + sqlite3 *db; /* Open database */ + sqlite3 *dbInit; /* On-disk database used to initialize the in-memory db */ + const char *zInitDb = 0;/* Name of the initialization database file */ + char *zErrMsg = 0; /* Error message returned from sqlite3_exec() */ + + g.zArgv0 = argv[0]; + for(i=1; i0 && got #include