mirror of https://github.com/sqlite/sqlite
Merge updates from trunk.
FossilOrigin-Name: b8094166b3c6a8ec7913b403e08b5e6790fb03c1
This commit is contained in:
commit
9cdd401d37
|
@ -1228,7 +1228,6 @@ clean:
|
|||
rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
|
||||
rm -f mkkeywordhash$(BEXE) keywordhash.h
|
||||
rm -f *.da *.bb *.bbg gmon.out
|
||||
rm -rf quota2a quota2b quota2c
|
||||
rm -rf tsrc .target_source
|
||||
rm -f tclsqlite3$(TEXE)
|
||||
rm -f testfixture$(TEXE) test.db
|
||||
|
|
|
@ -1882,7 +1882,7 @@ fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR)
|
|||
rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c
|
||||
|
||||
sqlite3session.lo: $(TOP)\ext\session\sqlite3sesion.c $(HDR) $(EXTHDR)
|
||||
sqlite3session.lo: $(TOP)\ext\session\sqlite3session.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\session\sqlite3session.c
|
||||
|
||||
# FTS5 things
|
||||
|
@ -2075,9 +2075,6 @@ clean:
|
|||
del /Q notasharedlib.* 2>NUL
|
||||
-rmdir /Q/S .deps 2>NUL
|
||||
-rmdir /Q/S .libs 2>NUL
|
||||
-rmdir /Q/S quota2a 2>NUL
|
||||
-rmdir /Q/S quota2b 2>NUL
|
||||
-rmdir /Q/S quota2c 2>NUL
|
||||
-rmdir /Q/S tsrc 2>NUL
|
||||
del /Q .target_source 2>NUL
|
||||
del /Q tclsqlite3.exe 2>NUL
|
||||
|
|
1
main.mk
1
main.mk
|
@ -905,7 +905,6 @@ clean:
|
|||
rm -f mkkeywordhash mkkeywordhash.exe keywordhash.h
|
||||
rm -f $(PUBLISH)
|
||||
rm -f *.da *.bb *.bbg gmon.out
|
||||
rm -rf quota2a quota2b quota2c
|
||||
rm -rf tsrc target_source
|
||||
rm -f testloadext.dll libtestloadext.so
|
||||
rm -f amalgamation-testfixture amalgamation-testfixture.exe
|
||||
|
|
60
manifest
60
manifest
|
@ -1,8 +1,8 @@
|
|||
C Fix\ssome\scompilation\sissues.
|
||||
D 2016-04-11T22:10:26.085
|
||||
F Makefile.in e812bb732d7af01baa09f1278bd4f4a2e3a09449
|
||||
C Merge\supdates\sfrom\strunk.
|
||||
D 2016-04-11T22:24:03.058
|
||||
F Makefile.in eba680121821b8a60940a81454316f47a341487a
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc fe57d7e3e74fa383fd01ced796c0ffd966fc094a
|
||||
F Makefile.msc 71b8b16cf9393f68e2e2035486ca104872558836
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION 5d234da9b5dae329fab75ff75884cfe0a9cb3fda
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
|
@ -300,7 +300,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
|||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 942e1fd30eb352492cf599aa7fcb5334783e4cbf
|
||||
F main.mk a283660f75c3c4b75d8c9d12a40fa38a066eee9d
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
|
@ -319,21 +319,21 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
|||
F src/backup.c f60f0aa55d25d853ffde53d0b0370a7bb7ee41ce
|
||||
F src/bitvec.c 3ee4c8b2c94ed3a7377256e18199e6ff5cf33f63
|
||||
F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
|
||||
F src/btree.c 556203aab543e91f4e20cc273a507ed712c8da26
|
||||
F src/btree.c 3ae6aea66cc4e13d30162ff0d0d43c7088e34abf
|
||||
F src/btree.h a5008b9afe56e8e54ade6c436a910f112defcca9
|
||||
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
|
||||
F src/build.c c5cf206191880f88142352629d53fed174fc10bd
|
||||
F src/build.c 1944d95f0250ec72dab939f8319a12e237aaad61
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 60e135af364d777a9ab41c97e5e89cd224da6198
|
||||
F src/date.c cd412cb2adb0c3a60e085107864931e508f45ad8
|
||||
F src/dbstat.c c845548d4346e606e2f2b7d2e714ace2b8a7dd1b
|
||||
F src/delete.c eeac28b3d3d88e3541bdf93e91ea7492a7b67842
|
||||
F src/expr.c 289ffac5240b60fee0a824d3d5ab2d7bd2630c94
|
||||
F src/delete.c 78eb999114ec04fcf1b7d123ccedb4b5b734930e
|
||||
F src/expr.c 17d4e745ef6a3fd2e4ef863f5f9a4912f1ba1198
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 4c0bd09e602b8ae8d36d81e31e4872d0b53c87bb
|
||||
F src/func.c 552d300265aed09eea21f68ac742a440550c0062
|
||||
F src/global.c 884d4c7eba9f5fc25c96a23b21520da19b7713e2
|
||||
F src/global.c c45ea22aff29334f6a9ec549235ac3357c970015
|
||||
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
|
@ -347,7 +347,7 @@ F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
|
|||
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
F src/memjournal.c 5253fd4335a8d9c64e5df25cb9da6329af5242c7
|
||||
F src/memjournal.c 2815ef7684671d93a1ec6a31e1e63c45de4b4d31
|
||||
F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495
|
||||
F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
|
@ -359,12 +359,12 @@ F src/os.c ca10edb445ad2c5fdc7285b49d72bcdf261fa23e
|
|||
F src/os.h 91ff889115ecd01f436d3611f7f5ea4dc12d92f1
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c b1ccb273771f41dbdbe0ba7c1ad63c38ad5972ec
|
||||
F src/os_unix.c bde4844f0849cab5924c6a81178f8500774ce76b
|
||||
F src/os_win.c 1245c1c1b03f269f8beca1464df2f9a174236dab
|
||||
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
|
||||
F src/pager.c 38718a019ca762ba4f6795425d5a54db70d1790d
|
||||
F src/pager.h e1d38a2f14849e219df0f91f8323504d134c8a56
|
||||
F src/parse.y 5ea8c81c5c41b27887f41b4a7e1c58470d7d3821
|
||||
F src/parse.y 10eb2f3fb62341291528c7984498054731f9d31e
|
||||
F src/pcache.c 647bb53a86b7bbcf55ad88089b3ea5a9170b90df
|
||||
F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545
|
||||
F src/pcache1.c c40cdb93586e21b5dd826b5e671240bd91c26b05
|
||||
|
@ -375,12 +375,12 @@ F src/printf.c 63e6fb12bbe702dd664dc3703776c090383a5a26
|
|||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c b8f7174e5f8c33c44ded3a25a973d0bb89228c20
|
||||
F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
|
||||
F src/select.c 7849cee0a01952a9c93cd28989daedfa57731143
|
||||
F src/select.c d9b8628acb98f1a38921888d823a6b70c7a7774b
|
||||
F src/shell.c b7922fa264f8c8d72a5ec6dd0b091e15a93c4de5
|
||||
F src/sqlite.h.in 7f437b068314f053e6417d452c59f08d05092591
|
||||
F src/sqlite.h.in c8f41612dc1a9b5212a891e1b65a5f589b8b884a
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2
|
||||
F src/sqliteInt.h 594bf31a7a0cc788688ca947e562576e23bd7904
|
||||
F src/sqliteInt.h b3744b29555b83054f315f62d61b3a6558fa9e1c
|
||||
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
||||
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
|
||||
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
||||
|
@ -439,13 +439,13 @@ F src/treeview.c e4b41a37530a191579d3c53142cc44ee2eb99373
|
|||
F src/trigger.c e14840ee0c3e549e758ec9bf3e4146e166002280
|
||||
F src/update.c 3e67ab3c0814635f355fb1f8ab010a2b9e016e7d
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c 8873d696c9ccc4206058c402e09e101f1b81561a
|
||||
F src/util.c 187a0a2aaa3c5d2ccd2ab0143b2fd9e86d6bc816
|
||||
F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52
|
||||
F src/vdbe.c 936166d3dc5aa00364877603f545707896c1519e
|
||||
F src/vdbe.h c16ba943d407baa1c7085eefea73a063fc631863
|
||||
F src/vdbe.c d3843a66d74a7696477ee5141e5eb9a7e5e2401c
|
||||
F src/vdbe.h 5591b5add447096e31288b5a0a78ec5d7b5c5170
|
||||
F src/vdbeInt.h ddb157974436d87652de7dc641f7191496d9a8cd
|
||||
F src/vdbeapi.c ba85b78fe08dc4a9ce747e62c89a2b4a4547e74c
|
||||
F src/vdbeaux.c fa06ba5441714160ab5f64422660ee286968672f
|
||||
F src/vdbeaux.c ace1875da40b7185e604586768d5ac90de7e4f7f
|
||||
F src/vdbeblob.c c9f2f494b911c6fa34efd9803f0a10807da80f77
|
||||
F src/vdbemem.c 5cfef60e60e19cab6275d1b975bf4c791d575beb
|
||||
F src/vdbesort.c 307460bfa4de4d1c3901fcd42089159131e34062
|
||||
|
@ -455,9 +455,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
|||
F src/wal.c 10deb6b43887662691e5f53d10b3c171c401169b
|
||||
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
||||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
F src/where.c 99cc6270fc3915201e2a90bbac3768f007a89c44
|
||||
F src/where.c 24ab561466d92d313747c04edb1a36a7af8663be
|
||||
F src/whereInt.h 93297d56edd137b7ea004490690fb6e2ce028a34
|
||||
F src/wherecode.c 863aedf086131743763c1960637fde904eadc442
|
||||
F src/wherecode.c 8fdad9fbba723df1c1e8d07e7ea8507572040340
|
||||
F src/whereexpr.c fb87944b1254234e5bba671aaf6dee476241506a
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
|
@ -519,7 +519,7 @@ F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
|
|||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f
|
||||
F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c
|
||||
F test/bestindex1.test d5ba89a7941a941476d8d69be39b146aaed3614c
|
||||
F test/bestindex1.test 0cf1bd2d7b97d3a3a8c10736125274f64765c4ee
|
||||
F test/bestindex2.test 4a06b8922ab2fd09434870da8d1cdf525aaf7060
|
||||
F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c
|
||||
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
|
||||
|
@ -615,7 +615,7 @@ F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
|||
F test/delete.test e1bcdf8926234e27aac24b346ad83d3329ec8b6f
|
||||
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
|
||||
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
|
||||
F test/delete4.test 3ac0b8d23689ba764c2e8b78c1b56b8f1b942fa2
|
||||
F test/delete4.test 738044ee892ee0c84e0848e36ba92c55f907d52b
|
||||
F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
|
||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
|
@ -1011,7 +1011,7 @@ F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
|||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
|
||||
F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
|
||||
F test/savepoint7.test db3db281486c925095f305aad09fe806e5188ff3
|
||||
F test/savepoint7.test cde525ea3075283eb950cdcdefe23ead4f700daa
|
||||
F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2
|
||||
F test/scanstatus.test 5253c219e331318a437f436268e0e82345700285
|
||||
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
|
||||
|
@ -1308,7 +1308,7 @@ F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
|
|||
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test f6c3a39e0c819891265e1d0754e99960d81ef6c9
|
||||
F test/view.test 765802c7a66d37fabd5ac8e2f2dbe572b43eb9ab
|
||||
F test/vtab1.test 7c4b81abd88361ada9cbe414c459efca26be6bda
|
||||
F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
|
@ -1420,7 +1420,7 @@ F tool/mkautoconfamal.sh e855df211ecbcc7131dee817110ff386cfb112f7
|
|||
F tool/mkkeywordhash.c f7f3b342211ac6a14258b9726d5b97cf4f548f22
|
||||
F tool/mkmsvcmin.tcl 2f12f7fa8858bbe61cf81820a2da96c79ed1ca8d
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 385c62d78c38b2d92146dcb5abd319dbbc33506d
|
||||
F tool/mkopcodeh.tcl a01d2c1d8a6205b03fc635adf3735b4c523befd3
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl f0d5bb266d1d388cf86fce5ba01a891e95d72d41
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
|
@ -1482,7 +1482,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 00990020d07d7c87b922cdbfa5373298a86bb4b3
|
||||
R b5c956e1077b7c3e444e8f4ed923bce8
|
||||
P 016481b39f8b23b4f0f851053068d8eaee6122e1 3189a7f1851f823218d85a2455bf218d00d81543
|
||||
R 7558a8a571dae2778f18625aa658ad38
|
||||
U mistachkin
|
||||
Z 76d8e561edd13c0c75a00b4aec6f1897
|
||||
Z b10810d48122d46da89a3713378b4792
|
||||
|
|
|
@ -1 +1 @@
|
|||
016481b39f8b23b4f0f851053068d8eaee6122e1
|
||||
b8094166b3c6a8ec7913b403e08b5e6790fb03c1
|
44
src/btree.c
44
src/btree.c
|
@ -8140,6 +8140,28 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|||
pPage = pCur->apPage[iCellDepth];
|
||||
pCell = findCell(pPage, iCellIdx);
|
||||
|
||||
/* If the bPreserve flag is set to true, then the cursor position must
|
||||
** be preserved following this delete operation. If the current delete
|
||||
** will cause a b-tree rebalance, then this is done by saving the cursor
|
||||
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
|
||||
** returning.
|
||||
**
|
||||
** Or, if the current delete will not cause a rebalance, then the cursor
|
||||
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
|
||||
** before or after the deleted entry. In this case set bSkipnext to true. */
|
||||
if( bPreserve ){
|
||||
if( !pPage->leaf
|
||||
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
|
||||
){
|
||||
/* A b-tree rebalance will be required after deleting this entry.
|
||||
** Save the cursor key. */
|
||||
rc = saveCursorKey(pCur);
|
||||
if( rc ) return rc;
|
||||
}else{
|
||||
bSkipnext = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the page containing the entry to delete is not a leaf page, move
|
||||
** the cursor to the largest entry in the tree that is smaller than
|
||||
** the entry being deleted. This cell will replace the cell being deleted
|
||||
|
@ -8166,28 +8188,6 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|||
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
|
||||
}
|
||||
|
||||
/* If the bPreserve flag is set to true, then the cursor position must
|
||||
** be preserved following this delete operation. If the current delete
|
||||
** will cause a b-tree rebalance, then this is done by saving the cursor
|
||||
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
|
||||
** returning.
|
||||
**
|
||||
** Or, if the current delete will not cause a rebalance, then the cursor
|
||||
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
|
||||
** before or after the deleted entry. In this case set bSkipnext to true. */
|
||||
if( bPreserve ){
|
||||
if( !pPage->leaf
|
||||
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
|
||||
){
|
||||
/* A b-tree rebalance will be required after deleting this entry.
|
||||
** Save the cursor key. */
|
||||
rc = saveCursorKey(pCur);
|
||||
if( rc ) return rc;
|
||||
}else{
|
||||
bSkipnext = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make the page containing the entry to be deleted writable. Then free any
|
||||
** overflow pages associated with the entry and finally remove the cell
|
||||
** itself from within the page. */
|
||||
|
|
73
src/build.c
73
src/build.c
|
@ -2176,44 +2176,55 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|||
** statement that defines the view.
|
||||
*/
|
||||
assert( pTable->pSelect );
|
||||
if( pTable->pCheck ){
|
||||
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
|
||||
if( pSel ){
|
||||
n = pParse->nTab;
|
||||
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
||||
pTable->nCol = -1;
|
||||
db->lookaside.bDisable++;
|
||||
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
|
||||
&pTable->nCol, &pTable->aCol);
|
||||
db->lookaside.bDisable--;
|
||||
}else{
|
||||
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
|
||||
if( pSel ){
|
||||
n = pParse->nTab;
|
||||
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
||||
pTable->nCol = -1;
|
||||
db->lookaside.bDisable++;
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
xAuth = db->xAuth;
|
||||
db->xAuth = 0;
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
db->xAuth = xAuth;
|
||||
xAuth = db->xAuth;
|
||||
db->xAuth = 0;
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
db->xAuth = xAuth;
|
||||
#else
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
#endif
|
||||
db->lookaside.bDisable--;
|
||||
pParse->nTab = n;
|
||||
if( pSelTab ){
|
||||
assert( pTable->aCol==0 );
|
||||
pTable->nCol = pSelTab->nCol;
|
||||
pTable->aCol = pSelTab->aCol;
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
sqlite3DeleteTable(db, pSelTab);
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
||||
}else{
|
||||
pTable->nCol = 0;
|
||||
nErr++;
|
||||
pParse->nTab = n;
|
||||
if( pTable->pCheck ){
|
||||
/* CREATE VIEW name(arglist) AS ...
|
||||
** The names of the columns in the table are taken from
|
||||
** arglist which is stored in pTable->pCheck. The pCheck field
|
||||
** normally holds CHECK constraints on an ordinary table, but for
|
||||
** a VIEW it holds the list of column names.
|
||||
*/
|
||||
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
|
||||
&pTable->nCol, &pTable->aCol);
|
||||
if( db->mallocFailed==0
|
||||
&& pParse->nErr==0
|
||||
&& pTable->nCol==pSel->pEList->nExpr
|
||||
){
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
|
||||
}
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
} else {
|
||||
}else if( pSelTab ){
|
||||
/* CREATE VIEW name AS... without an argument list. Construct
|
||||
** the column names from the SELECT statement that defines the view.
|
||||
*/
|
||||
assert( pTable->aCol==0 );
|
||||
pTable->nCol = pSelTab->nCol;
|
||||
pTable->aCol = pSelTab->aCol;
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
||||
}else{
|
||||
pTable->nCol = 0;
|
||||
nErr++;
|
||||
}
|
||||
if( pSelTab ) sqlite3DeleteTable(db, pSelTab);
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
db->lookaside.bDisable--;
|
||||
} else {
|
||||
nErr++;
|
||||
}
|
||||
pTable->pSchema->schemaFlags |= DB_UnresetViews;
|
||||
#endif /* SQLITE_OMIT_VIEW */
|
||||
|
|
24
src/delete.c
24
src/delete.c
|
@ -143,7 +143,7 @@ Expr *sqlite3LimitWhere(
|
|||
*/
|
||||
if( pOrderBy && (pLimit == 0) ) {
|
||||
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
|
||||
goto limit_where_cleanup_2;
|
||||
goto limit_where_cleanup;
|
||||
}
|
||||
|
||||
/* We only need to generate a select expression if there
|
||||
|
@ -165,16 +165,16 @@ Expr *sqlite3LimitWhere(
|
|||
*/
|
||||
|
||||
pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
|
||||
if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
|
||||
if( pSelectRowid == 0 ) goto limit_where_cleanup;
|
||||
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
|
||||
if( pEList == 0 ) goto limit_where_cleanup_2;
|
||||
if( pEList == 0 ) goto limit_where_cleanup;
|
||||
|
||||
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
||||
** and the SELECT subtree. */
|
||||
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
||||
if( pSelectSrc == 0 ) {
|
||||
sqlite3ExprListDelete(pParse->db, pEList);
|
||||
goto limit_where_cleanup_2;
|
||||
goto limit_where_cleanup;
|
||||
}
|
||||
|
||||
/* generate the SELECT expression tree. */
|
||||
|
@ -184,21 +184,11 @@ Expr *sqlite3LimitWhere(
|
|||
|
||||
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
|
||||
pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
|
||||
if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
|
||||
pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
|
||||
if( pInClause == 0 ) goto limit_where_cleanup_1;
|
||||
|
||||
pInClause->x.pSelect = pSelect;
|
||||
pInClause->flags |= EP_xIsSelect;
|
||||
sqlite3ExprSetHeightAndFlags(pParse, pInClause);
|
||||
pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0) : 0;
|
||||
sqlite3PExprAddSelect(pParse, pInClause, pSelect);
|
||||
return pInClause;
|
||||
|
||||
/* something went wrong. clean up anything allocated. */
|
||||
limit_where_cleanup_1:
|
||||
sqlite3SelectDelete(pParse->db, pSelect);
|
||||
return 0;
|
||||
|
||||
limit_where_cleanup_2:
|
||||
limit_where_cleanup:
|
||||
sqlite3ExprDelete(pParse->db, pWhere);
|
||||
sqlite3ExprListDelete(pParse->db, pOrderBy);
|
||||
sqlite3ExprDelete(pParse->db, pLimit);
|
||||
|
|
219
src/expr.c
219
src/expr.c
|
@ -471,15 +471,13 @@ Expr *sqlite3ExprAlloc(
|
|||
pNew->flags |= EP_IntValue;
|
||||
pNew->u.iValue = iValue;
|
||||
}else{
|
||||
int c;
|
||||
pNew->u.zToken = (char*)&pNew[1];
|
||||
assert( pToken->z!=0 || pToken->n==0 );
|
||||
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
|
||||
pNew->u.zToken[pToken->n] = 0;
|
||||
if( dequote && nExtra>=3
|
||||
&& ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
|
||||
if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
|
||||
if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted;
|
||||
sqlite3Dequote(pNew->u.zToken);
|
||||
if( c=='"' ) pNew->flags |= EP_DblQuoted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -562,6 +560,22 @@ Expr *sqlite3PExpr(
|
|||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add pSelect to the Expr.x.pSelect field. Or, if pExpr is NULL (due
|
||||
** do a memory allocation failure) then delete the pSelect object.
|
||||
*/
|
||||
void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){
|
||||
if( pExpr ){
|
||||
pExpr->x.pSelect = pSelect;
|
||||
ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, pExpr);
|
||||
}else{
|
||||
assert( pParse->db->mallocFailed );
|
||||
sqlite3SelectDelete(pParse->db, pSelect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** If the expression is always either TRUE or FALSE (respectively),
|
||||
** then return 1. If one cannot determine the truth value of the
|
||||
|
@ -722,8 +736,8 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
|||
/*
|
||||
** Recursively delete an expression tree.
|
||||
*/
|
||||
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p==0 ) return;
|
||||
static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
||||
assert( p!=0 );
|
||||
/* Sanity check: Assert that the IntValue is non-negative if it exists */
|
||||
assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
|
||||
if( !ExprHasProperty(p, EP_TokenOnly) ){
|
||||
|
@ -742,6 +756,9 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
|||
sqlite3DbFree(db, p);
|
||||
}
|
||||
}
|
||||
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p ) sqlite3ExprDeleteNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes allocated for the expression structure
|
||||
|
@ -793,7 +810,7 @@ static int dupedExprStructSize(Expr *p, int flags){
|
|||
assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
|
||||
assert( EXPR_FULLSIZE<=0xfff );
|
||||
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
|
||||
if( 0==(flags&EXPRDUP_REDUCE) ){
|
||||
if( 0==flags ){
|
||||
nSize = EXPR_FULLSIZE;
|
||||
}else{
|
||||
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
|
@ -855,88 +872,88 @@ static int dupedExprSize(Expr *p, int flags){
|
|||
** if any. Before returning, *pzBuffer is set to the first byte past the
|
||||
** portion of the buffer copied into by this function.
|
||||
*/
|
||||
static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
|
||||
Expr *pNew = 0; /* Value to return */
|
||||
assert( flags==0 || flags==EXPRDUP_REDUCE );
|
||||
static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
||||
Expr *pNew; /* Value to return */
|
||||
u8 *zAlloc; /* Memory space from which to build Expr object */
|
||||
u32 staticFlag; /* EP_Static if space not obtained from malloc */
|
||||
|
||||
assert( db!=0 );
|
||||
if( p ){
|
||||
const int isReduced = (flags&EXPRDUP_REDUCE);
|
||||
u8 *zAlloc;
|
||||
u32 staticFlag = 0;
|
||||
assert( p );
|
||||
assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
|
||||
assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
|
||||
|
||||
assert( pzBuffer==0 || isReduced );
|
||||
/* Figure out where to write the new Expr structure. */
|
||||
if( pzBuffer ){
|
||||
zAlloc = *pzBuffer;
|
||||
staticFlag = EP_Static;
|
||||
}else{
|
||||
zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
|
||||
staticFlag = 0;
|
||||
}
|
||||
pNew = (Expr *)zAlloc;
|
||||
|
||||
/* Figure out where to write the new Expr structure. */
|
||||
if( pzBuffer ){
|
||||
zAlloc = *pzBuffer;
|
||||
staticFlag = EP_Static;
|
||||
if( pNew ){
|
||||
/* Set nNewSize to the size allocated for the structure pointed to
|
||||
** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
|
||||
** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
|
||||
** by the copy of the p->u.zToken string (if any).
|
||||
*/
|
||||
const unsigned nStructSize = dupedExprStructSize(p, dupFlags);
|
||||
const int nNewSize = nStructSize & 0xfff;
|
||||
int nToken;
|
||||
if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
|
||||
nToken = sqlite3Strlen30(p->u.zToken) + 1;
|
||||
}else{
|
||||
zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, flags));
|
||||
nToken = 0;
|
||||
}
|
||||
if( dupFlags ){
|
||||
assert( ExprHasProperty(p, EP_Reduced)==0 );
|
||||
memcpy(zAlloc, p, nNewSize);
|
||||
}else{
|
||||
u32 nSize = (u32)exprStructSize(p);
|
||||
memcpy(zAlloc, p, nSize);
|
||||
if( nSize<EXPR_FULLSIZE ){
|
||||
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
|
||||
}
|
||||
}
|
||||
pNew = (Expr *)zAlloc;
|
||||
|
||||
if( pNew ){
|
||||
/* Set nNewSize to the size allocated for the structure pointed to
|
||||
** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
|
||||
** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
|
||||
** by the copy of the p->u.zToken string (if any).
|
||||
*/
|
||||
const unsigned nStructSize = dupedExprStructSize(p, flags);
|
||||
const int nNewSize = nStructSize & 0xfff;
|
||||
int nToken;
|
||||
if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
|
||||
nToken = sqlite3Strlen30(p->u.zToken) + 1;
|
||||
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
|
||||
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
|
||||
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
|
||||
pNew->flags |= staticFlag;
|
||||
|
||||
/* Copy the p->u.zToken string, if any. */
|
||||
if( nToken ){
|
||||
char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
|
||||
memcpy(zToken, p->u.zToken, nToken);
|
||||
}
|
||||
|
||||
if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
|
||||
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
|
||||
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
|
||||
}else{
|
||||
nToken = 0;
|
||||
pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
|
||||
}
|
||||
if( isReduced ){
|
||||
assert( ExprHasProperty(p, EP_Reduced)==0 );
|
||||
memcpy(zAlloc, p, nNewSize);
|
||||
}else{
|
||||
u32 nSize = (u32)exprStructSize(p);
|
||||
memcpy(zAlloc, p, nSize);
|
||||
if( nSize<EXPR_FULLSIZE ){
|
||||
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in pNew->pLeft and pNew->pRight. */
|
||||
if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
|
||||
zAlloc += dupedExprNodeSize(p, dupFlags);
|
||||
if( ExprHasProperty(pNew, EP_Reduced) ){
|
||||
pNew->pLeft = p->pLeft ?
|
||||
exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
|
||||
pNew->pRight = p->pRight ?
|
||||
exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
|
||||
}
|
||||
|
||||
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
|
||||
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
|
||||
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
|
||||
pNew->flags |= staticFlag;
|
||||
|
||||
/* Copy the p->u.zToken string, if any. */
|
||||
if( nToken ){
|
||||
char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
|
||||
memcpy(zToken, p->u.zToken, nToken);
|
||||
if( pzBuffer ){
|
||||
*pzBuffer = zAlloc;
|
||||
}
|
||||
|
||||
if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
|
||||
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
|
||||
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
|
||||
}else{
|
||||
pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
|
||||
}
|
||||
}else{
|
||||
if( !ExprHasProperty(p, EP_TokenOnly) ){
|
||||
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
|
||||
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
|
||||
}
|
||||
|
||||
/* Fill in pNew->pLeft and pNew->pRight. */
|
||||
if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
|
||||
zAlloc += dupedExprNodeSize(p, flags);
|
||||
if( ExprHasProperty(pNew, EP_Reduced) ){
|
||||
pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
|
||||
pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
|
||||
}
|
||||
if( pzBuffer ){
|
||||
*pzBuffer = zAlloc;
|
||||
}
|
||||
}else{
|
||||
if( !ExprHasProperty(p, EP_TokenOnly) ){
|
||||
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
|
||||
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
|
@ -988,7 +1005,7 @@ static With *withDup(sqlite3 *db, With *p){
|
|||
*/
|
||||
Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
|
||||
assert( flags==0 || flags==EXPRDUP_REDUCE );
|
||||
return exprDup(db, p, flags, 0);
|
||||
return p ? exprDup(db, p, flags, 0) : 0;
|
||||
}
|
||||
ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
ExprList *pNew;
|
||||
|
@ -1210,7 +1227,7 @@ void sqlite3ExprListSetName(
|
|||
pItem = &pList->a[pList->nExpr-1];
|
||||
assert( pItem->zName==0 );
|
||||
pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
|
||||
if( dequote && pItem->zName ) sqlite3Dequote(pItem->zName);
|
||||
if( dequote ) sqlite3Dequote(pItem->zName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1259,10 +1276,9 @@ void sqlite3ExprListCheckLength(
|
|||
/*
|
||||
** Delete an entire expression list.
|
||||
*/
|
||||
void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
||||
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
|
||||
int i;
|
||||
struct ExprList_item *pItem;
|
||||
if( pList==0 ) return;
|
||||
assert( pList->a!=0 || pList->nExpr==0 );
|
||||
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
|
||||
sqlite3ExprDelete(db, pItem->pExpr);
|
||||
|
@ -1272,6 +1288,9 @@ void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
|||
sqlite3DbFree(db, pList->a);
|
||||
sqlite3DbFree(db, pList);
|
||||
}
|
||||
void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
||||
if( pList ) exprListDeleteNN(db, pList);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the bitwise-OR of all Expr.flags fields in the given
|
||||
|
@ -2316,6 +2335,19 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** Verify the consistency of the column cache
|
||||
*/
|
||||
static int cacheIsValid(Parse *pParse){
|
||||
int i, n;
|
||||
for(i=n=0; i<SQLITE_N_COLCACHE; i++){
|
||||
if( pParse->aColCache[i].iReg>0 ) n++;
|
||||
}
|
||||
return n==pParse->nColCache;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Clear a cache entry.
|
||||
*/
|
||||
|
@ -2326,6 +2358,9 @@ static void cacheEntryClear(Parse *pParse, struct yColCache *p){
|
|||
}
|
||||
p->tempReg = 0;
|
||||
}
|
||||
p->iReg = 0;
|
||||
pParse->nColCache--;
|
||||
assert( cacheIsValid(pParse) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -2369,6 +2404,8 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
|||
p->iReg = iReg;
|
||||
p->tempReg = 0;
|
||||
p->lru = pParse->iCacheCnt++;
|
||||
pParse->nColCache++;
|
||||
assert( cacheIsValid(pParse) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2390,6 +2427,7 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
|||
p->iReg = iReg;
|
||||
p->tempReg = 0;
|
||||
p->lru = pParse->iCacheCnt++;
|
||||
assert( cacheIsValid(pParse) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2399,15 +2437,13 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
|||
** Purge the range of registers from the column cache.
|
||||
*/
|
||||
void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){
|
||||
int i;
|
||||
int iLast = iReg + nReg - 1;
|
||||
struct yColCache *p;
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
int r = p->iReg;
|
||||
if( r>=iReg && r<=iLast ){
|
||||
cacheEntryClear(pParse, p);
|
||||
p->iReg = 0;
|
||||
}
|
||||
if( iReg<=0 || pParse->nColCache==0 ) return;
|
||||
p = &pParse->aColCache[SQLITE_N_COLCACHE-1];
|
||||
while(1){
|
||||
if( p->iReg >= iReg && p->iReg < iReg+nReg ) cacheEntryClear(pParse, p);
|
||||
if( p==pParse->aColCache ) break;
|
||||
p--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2443,7 +2479,6 @@ void sqlite3ExprCachePop(Parse *pParse){
|
|||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
if( p->iReg && p->iLevel>pParse->iCacheLevel ){
|
||||
cacheEntryClear(pParse, p);
|
||||
p->iReg = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2578,7 +2613,6 @@ void sqlite3ExprCacheClear(Parse *pParse){
|
|||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
if( p->iReg ){
|
||||
cacheEntryClear(pParse, p);
|
||||
p->iReg = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2620,6 +2654,7 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
|
|||
}
|
||||
#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
|
||||
|
||||
|
||||
/*
|
||||
** Convert an expression node to a TK_REGISTER
|
||||
*/
|
||||
|
|
|
@ -70,6 +70,7 @@ const unsigned char sqlite3UpperToLower[] = {
|
|||
** isxdigit() 0x08
|
||||
** toupper() 0x20
|
||||
** SQLite identifier character 0x40
|
||||
** Quote character 0x80
|
||||
**
|
||||
** Bit 0x20 is set if the mapped character requires translation to upper
|
||||
** case. i.e. if the character is a lower-case ASCII character.
|
||||
|
@ -95,7 +96,7 @@ const unsigned char sqlite3CtypeMap[256] = {
|
|||
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
|
||||
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, /* 20..27 !"#$%&' */
|
||||
0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
|
||||
0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
|
||||
|
@ -103,8 +104,8 @@ const unsigned char sqlite3CtypeMap[256] = {
|
|||
0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
|
||||
0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
|
||||
0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
|
||||
0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
|
||||
0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
|
||||
0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
|
||||
|
|
|
@ -94,6 +94,7 @@ static int memjrnlRead(
|
|||
#endif
|
||||
|
||||
assert( (iAmt+iOfst)<=p->endpoint.iOffset );
|
||||
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
|
||||
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
|
||||
sqlite3_int64 iOff = 0;
|
||||
for(pChunk=p->pFirst;
|
||||
|
@ -104,6 +105,7 @@ static int memjrnlRead(
|
|||
}
|
||||
}else{
|
||||
pChunk = p->readpoint.pChunk;
|
||||
assert( pChunk!=0 );
|
||||
}
|
||||
|
||||
iChunkOffset = (int)(iOfst%p->nChunkSize);
|
||||
|
@ -115,7 +117,7 @@ static int memjrnlRead(
|
|||
nRead -= iSpace;
|
||||
iChunkOffset = 0;
|
||||
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
|
||||
p->readpoint.iOffset = iOfst+iAmt;
|
||||
p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
|
||||
p->readpoint.pChunk = pChunk;
|
||||
|
||||
return SQLITE_OK;
|
||||
|
|
|
@ -1502,7 +1502,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|||
** lock transitions in terms of the POSIX advisory shared and exclusive
|
||||
** lock primitives (called read-locks and write-locks below, to avoid
|
||||
** confusion with SQLite lock names). The algorithms are complicated
|
||||
** slightly in order to be compatible with windows systems simultaneously
|
||||
** slightly in order to be compatible with Windows95 systems simultaneously
|
||||
** accessing the same database file, in case that is ever required.
|
||||
**
|
||||
** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
|
||||
|
@ -1510,8 +1510,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|||
** range', a range of 510 bytes at a well known offset.
|
||||
**
|
||||
** To obtain a SHARED lock, a read-lock is obtained on the 'pending
|
||||
** byte'. If this is successful, a random byte from the 'shared byte
|
||||
** range' is read-locked and the lock on the 'pending byte' released.
|
||||
** byte'. If this is successful, 'shared byte range' is read-locked
|
||||
** and the lock on the 'pending byte' released. (Legacy note: When
|
||||
** SQLite was first developed, Windows95 systems were still very common,
|
||||
** and Widnows95 lacks a shared-lock capability. So on Windows95, a
|
||||
** single randomly selected by from the 'shared byte range' is locked.
|
||||
** Windows95 is now pretty much extinct, but this work-around for the
|
||||
** lack of shared-locks on Windows95 lives on, for backwards
|
||||
** compatibility.)
|
||||
**
|
||||
** A process may only obtain a RESERVED lock after it has a SHARED lock.
|
||||
** A RESERVED lock is implemented by grabbing a write-lock on the
|
||||
|
@ -1530,11 +1536,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|||
** range'. Since all other locks require a read-lock on one of the bytes
|
||||
** within this range, this ensures that no other locks are held on the
|
||||
** database.
|
||||
**
|
||||
** The reason a single byte cannot be used instead of the 'shared byte
|
||||
** range' is that some versions of windows do not support read-locks. By
|
||||
** locking a random byte from a range, concurrent SHARED locks may exist
|
||||
** even if the locking primitive used is always a write-lock.
|
||||
*/
|
||||
int rc = SQLITE_OK;
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
|
|
89
src/parse.y
89
src/parse.y
|
@ -194,28 +194,6 @@ columnlist ::= columnlist COMMA columnname carglist.
|
|||
columnlist ::= columnname carglist.
|
||||
columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
|
||||
// An IDENTIFIER can be a generic identifier, or one of several
|
||||
// keywords. Any non-standard keyword can also be an identifier.
|
||||
//
|
||||
%token_class id ID|INDEXED.
|
||||
|
||||
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
|
||||
// fallback to ID if they will not parse as their original value.
|
||||
// This obviates the need for the "id" nonterminal.
|
||||
//
|
||||
%fallback ID
|
||||
ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
|
||||
CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
|
||||
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW
|
||||
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
%wildcard ANY.
|
||||
|
||||
// Define operator precedence early so that this is the first occurrence
|
||||
// of the operator tokens in the grammer. Keeping the operators together
|
||||
// causes them to be assigned integer values that are close together,
|
||||
|
@ -240,6 +218,29 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
|||
%left COLLATE.
|
||||
%right BITNOT.
|
||||
|
||||
// An IDENTIFIER can be a generic identifier, or one of several
|
||||
// keywords. Any non-standard keyword can also be an identifier.
|
||||
//
|
||||
%token_class id ID|INDEXED.
|
||||
|
||||
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
|
||||
// fallback to ID if they will not parse as their original value.
|
||||
// This obviates the need for the "id" nonterminal.
|
||||
//
|
||||
%fallback ID
|
||||
ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
|
||||
CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
|
||||
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW
|
||||
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
%wildcard ANY.
|
||||
|
||||
|
||||
// And "ids" is an identifer-or-string.
|
||||
//
|
||||
%token_class ids ID|STRING.
|
||||
|
@ -871,11 +872,15 @@ expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
|
|||
term(A) ::= INTEGER|FLOAT|BLOB(X). {spanExpr(&A,pParse,@X,X);/*A-overwrites-X*/}
|
||||
term(A) ::= STRING(X). {spanExpr(&A,pParse,@X,X);/*A-overwrites-X*/}
|
||||
expr(A) ::= VARIABLE(X). {
|
||||
Token t = X; /*A-overwrites-X*/
|
||||
if( t.n>=2 && t.z[0]=='#' && sqlite3Isdigit(t.z[1]) ){
|
||||
if( !(X.z[0]=='#' && sqlite3Isdigit(X.z[1])) ){
|
||||
spanExpr(&A, pParse, TK_VARIABLE, X);
|
||||
sqlite3ExprAssignVarNumber(pParse, A.pExpr);
|
||||
}else{
|
||||
/* When doing a nested parse, one can include terms in an expression
|
||||
** that look like this: #1 #2 ... These terms refer to registers
|
||||
** in the virtual machine. #N is the N-th register. */
|
||||
Token t = X; /*A-overwrites-X*/
|
||||
assert( t.n>=2 );
|
||||
spanSet(&A, &t, &t);
|
||||
if( pParse->nested==0 ){
|
||||
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
|
||||
|
@ -884,9 +889,6 @@ expr(A) ::= VARIABLE(X). {
|
|||
A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &t);
|
||||
if( A.pExpr ) sqlite3GetInt32(&t.z[1], &A.pExpr->iTable);
|
||||
}
|
||||
}else{
|
||||
spanExpr(&A, pParse, TK_VARIABLE, t);
|
||||
sqlite3ExprAssignVarNumber(pParse, A.pExpr);
|
||||
}
|
||||
}
|
||||
expr(A) ::= expr(A) COLLATE ids(C). {
|
||||
|
@ -1122,36 +1124,19 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||
expr(A) ::= LP(B) select(X) RP(E). {
|
||||
spanSet(&A,&B,&E); /*A-overwrites-B*/
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pSelect = X;
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3SelectDelete(pParse->db, X);
|
||||
}
|
||||
sqlite3PExprAddSelect(pParse, A.pExpr, X);
|
||||
}
|
||||
expr(A) ::= expr(A) in_op(N) LP select(Y) RP(E). [IN] {
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pSelect = Y;
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3SelectDelete(pParse->db, Y);
|
||||
}
|
||||
sqlite3PExprAddSelect(pParse, A.pExpr, Y);
|
||||
exprNot(pParse, N, &A);
|
||||
A.zEnd = &E.z[E.n];
|
||||
}
|
||||
expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z). [IN] {
|
||||
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
|
||||
Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3SrcListDelete(pParse->db, pSrc);
|
||||
}
|
||||
sqlite3PExprAddSelect(pParse, A.pExpr, pSelect);
|
||||
exprNot(pParse, N, &A);
|
||||
A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n];
|
||||
}
|
||||
|
@ -1159,13 +1144,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||
Expr *p;
|
||||
spanSet(&A,&B,&E); /*A-overwrites-B*/
|
||||
p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
|
||||
if( p ){
|
||||
p->x.pSelect = Y;
|
||||
ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, p);
|
||||
}else{
|
||||
sqlite3SelectDelete(pParse->db, Y);
|
||||
}
|
||||
sqlite3PExprAddSelect(pParse, p, Y);
|
||||
}
|
||||
%endif SQLITE_OMIT_SUBQUERY
|
||||
|
||||
|
|
18
src/select.c
18
src/select.c
|
@ -1704,7 +1704,7 @@ int sqlite3ColumnsFromExprList(
|
|||
** This routine requires that all identifiers in the SELECT
|
||||
** statement be resolved.
|
||||
*/
|
||||
static void selectAddColumnTypeAndCollation(
|
||||
void sqlite3SelectAddColumnTypeAndCollation(
|
||||
Parse *pParse, /* Parsing contexts */
|
||||
Table *pTab, /* Add column type information to this table */
|
||||
Select *pSelect /* SELECT used to determine types and collations */
|
||||
|
@ -1726,10 +1726,20 @@ static void selectAddColumnTypeAndCollation(
|
|||
sNC.pSrcList = pSelect->pSrc;
|
||||
a = pSelect->pEList->a;
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
const char *zType;
|
||||
int n, m;
|
||||
p = a[i].pExpr;
|
||||
columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
|
||||
zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
|
||||
szAll += pCol->szEst;
|
||||
pCol->affinity = sqlite3ExprAffinity(p);
|
||||
if( zType && (m = sqlite3Strlen30(zType))>0 ){
|
||||
n = sqlite3Strlen30(pCol->zName);
|
||||
pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
|
||||
if( pCol->zName ){
|
||||
memcpy(&pCol->zName[n+1], zType, m+1);
|
||||
pCol->colFlags |= COLFLAG_HASTYPE;
|
||||
}
|
||||
}
|
||||
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
|
||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
if( pColl && pCol->zColl==0 ){
|
||||
|
@ -1766,7 +1776,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
|||
pTab->zName = 0;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
||||
selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
||||
pTab->iPKey = -1;
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DeleteTable(db, pTab);
|
||||
|
@ -4550,7 +4560,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
|||
Select *pSel = pFrom->pSelect;
|
||||
if( pSel ){
|
||||
while( pSel->pPrior ) pSel = pSel->pPrior;
|
||||
selectAddColumnTypeAndCollation(pParse, pTab, pSel);
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8081,20 +8081,29 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
|||
** CAPI3REF: Start a read transaction on an historical snapshot
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^The [sqlite3_snapshot_open(D,S,P)] interface attempts to move the
|
||||
** read transaction that is currently open on schema S of
|
||||
** [database connection] D so that it refers to historical [snapshot] P.
|
||||
** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
|
||||
** read transaction for schema S of
|
||||
** [database connection] D such that the read transaction
|
||||
** refers to historical [snapshot] P, rather than the most
|
||||
** recent change to the database.
|
||||
** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
|
||||
** or an appropriate [error code] if it fails.
|
||||
**
|
||||
** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
|
||||
** the first operation, apart from other sqlite3_snapshot_open() calls,
|
||||
** following the [BEGIN] that starts a new read transaction.
|
||||
** ^A [snapshot] will fail to open if it has been overwritten by a
|
||||
** the first operation following the [BEGIN] that takes the schema S
|
||||
** out of [autocommit mode].
|
||||
** ^In other words, schema S must not currently be in
|
||||
** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
|
||||
** database connection D must be out of [autocommit mode].
|
||||
** ^A [snapshot] will fail to open if it has been overwritten by a
|
||||
** [checkpoint].
|
||||
** ^A [snapshot] will fail to open if the database connection D has not
|
||||
** previously completed at least one read operation against the database
|
||||
** file. (Hint: Run "[PRAGMA application_id]" against a newly opened
|
||||
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
|
||||
** database connection D does not know that the database file for
|
||||
** schema S is in [WAL mode]. A database connection might not know
|
||||
** that the database file is in [WAL mode] if there has been no prior
|
||||
** I/O on that database connection, or if the database entered [WAL mode]
|
||||
** after the most recent I/O on the database connection.)^
|
||||
** (Hint: Run "[PRAGMA application_id]" against a newly opened
|
||||
** database connection in order to make it ready to use snapshots.)
|
||||
**
|
||||
** The [sqlite3_snapshot_open()] interface is only available when the
|
||||
|
|
|
@ -2814,6 +2814,7 @@ struct Parse {
|
|||
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
|
||||
u8 okConstFactor; /* OK to factor out constants */
|
||||
u8 disableLookaside; /* Number of times lookaside has been disabled */
|
||||
u8 nColCache; /* Number of entries in aColCache[] */
|
||||
int aTempReg[8]; /* Holding area for temporary registers */
|
||||
int nRangeReg; /* Size of the temporary register block */
|
||||
int iRangeReg; /* First register in temporary register block */
|
||||
|
@ -3301,6 +3302,7 @@ int sqlite3CantopenError(int);
|
|||
# define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04)
|
||||
# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
|
||||
# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
|
||||
# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
|
||||
#else
|
||||
# define sqlite3Toupper(x) toupper((unsigned char)(x))
|
||||
# define sqlite3Isspace(x) isspace((unsigned char)(x))
|
||||
|
@ -3309,6 +3311,7 @@ int sqlite3CantopenError(int);
|
|||
# define sqlite3Isdigit(x) isdigit((unsigned char)(x))
|
||||
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
|
||||
# define sqlite3Tolower(x) tolower((unsigned char)(x))
|
||||
# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
int sqlite3IsIdChar(u8);
|
||||
|
@ -3432,7 +3435,7 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
|
|||
|
||||
void sqlite3SetString(char **, sqlite3*, const char*);
|
||||
void sqlite3ErrorMsg(Parse*, const char*, ...);
|
||||
int sqlite3Dequote(char*);
|
||||
void sqlite3Dequote(char*);
|
||||
void sqlite3TokenInit(Token*,char*);
|
||||
int sqlite3KeywordCode(const unsigned char*, int);
|
||||
int sqlite3RunParser(Parse*, const char*, char **);
|
||||
|
@ -3449,6 +3452,7 @@ Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
|
|||
Expr *sqlite3Expr(sqlite3*,int,const char*);
|
||||
void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
|
||||
Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*);
|
||||
void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
|
||||
Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
|
||||
Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
|
||||
void sqlite3ExprAssignVarNumber(Parse*, Expr*);
|
||||
|
@ -3468,6 +3472,7 @@ void sqlite3CollapseDatabaseArray(sqlite3*);
|
|||
void sqlite3CommitInternalChanges(sqlite3*);
|
||||
void sqlite3DeleteColumnNames(sqlite3*,Table*);
|
||||
int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
|
||||
void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,Select*);
|
||||
void sqlite3OpenMasterTable(Parse *, int);
|
||||
Index *sqlite3PrimaryKeyIndex(Table*);
|
||||
|
|
15
src/util.c
15
src/util.c
|
@ -242,18 +242,13 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
|||
** brackets from around identifiers. For example: "[a-b-c]" becomes
|
||||
** "a-b-c".
|
||||
*/
|
||||
int sqlite3Dequote(char *z){
|
||||
void sqlite3Dequote(char *z){
|
||||
char quote;
|
||||
int i, j;
|
||||
if( z==0 ) return -1;
|
||||
if( z==0 ) return;
|
||||
quote = z[0];
|
||||
switch( quote ){
|
||||
case '\'': break;
|
||||
case '"': break;
|
||||
case '`': break; /* For MySQL compatibility */
|
||||
case '[': quote = ']'; break; /* For MS SqlServer compatibility */
|
||||
default: return -1;
|
||||
}
|
||||
if( !sqlite3Isquote(quote) ) return;
|
||||
if( quote=='[' ) quote = ']';
|
||||
for(i=1, j=0;; i++){
|
||||
assert( z[i] );
|
||||
if( z[i]==quote ){
|
||||
|
@ -268,7 +263,6 @@ int sqlite3Dequote(char *z){
|
|||
}
|
||||
}
|
||||
z[j] = 0;
|
||||
return j;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1448,7 +1442,6 @@ LogEst sqlite3LogEstFromDouble(double x){
|
|||
*/
|
||||
u64 sqlite3LogEstToInt(LogEst x){
|
||||
u64 n;
|
||||
if( x<10 ) return 1;
|
||||
n = x%10;
|
||||
x /= 10;
|
||||
if( n>=5 ) n -= 2;
|
||||
|
|
73
src/vdbe.c
73
src/vdbe.c
|
@ -674,37 +674,39 @@ int sqlite3VdbeExec(
|
|||
|
||||
/* Sanity checking on other operands */
|
||||
#ifdef SQLITE_DEBUG
|
||||
assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
|
||||
if( (pOp->opflags & OPFLG_IN1)!=0 ){
|
||||
assert( pOp->p1>0 );
|
||||
assert( pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p1]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
|
||||
REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_IN2)!=0 ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p2]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
|
||||
REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_IN3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p3]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
|
||||
REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_OUT2)!=0 ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
|
||||
memAboutToChange(p, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_OUT3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
memAboutToChange(p, &aMem[pOp->p3]);
|
||||
{
|
||||
u8 opProperty = sqlite3OpcodeProperty[pOp->opcode];
|
||||
if( (opProperty & OPFLG_IN1)!=0 ){
|
||||
assert( pOp->p1>0 );
|
||||
assert( pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p1]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
|
||||
REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
|
||||
}
|
||||
if( (opProperty & OPFLG_IN2)!=0 ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p2]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
|
||||
REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (opProperty & OPFLG_IN3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p3]) );
|
||||
assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
|
||||
REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
|
||||
}
|
||||
if( (opProperty & OPFLG_OUT2)!=0 ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
|
||||
memAboutToChange(p, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (opProperty & OPFLG_OUT3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
memAboutToChange(p, &aMem[pOp->p3]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
|
@ -2755,7 +2757,9 @@ case OP_MakeRecord: {
|
|||
testcase( serial_type==127 );
|
||||
testcase( serial_type==128 );
|
||||
nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
|
||||
}while( (--pRec)>=pData0 );
|
||||
if( pRec==pData0 ) break;
|
||||
pRec--;
|
||||
}while(1);
|
||||
|
||||
/* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
|
||||
** which determines the total number of bytes in the header. The varint
|
||||
|
@ -6875,11 +6879,12 @@ default: { /* This is really OP_Noop and OP_Explain */
|
|||
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( db->flags & SQLITE_VdbeTrace ){
|
||||
u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode];
|
||||
if( rc!=0 ) printf("rc=%d\n",rc);
|
||||
if( pOrigOp->opflags & (OPFLG_OUT2) ){
|
||||
if( opProperty & (OPFLG_OUT2) ){
|
||||
registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]);
|
||||
}
|
||||
if( pOrigOp->opflags & OPFLG_OUT3 ){
|
||||
if( opProperty & OPFLG_OUT3 ){
|
||||
registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ typedef struct SubProgram SubProgram;
|
|||
struct VdbeOp {
|
||||
u8 opcode; /* What operation to perform */
|
||||
signed char p4type; /* One of the P4_xxx constants for p4 */
|
||||
u8 opflags; /* Mask of the OPFLG_* flags in opcodes.h */
|
||||
u8 notUsed1;
|
||||
u8 p5; /* Fifth parameter is an unsigned character */
|
||||
int p1; /* First operand */
|
||||
int p2; /* Second parameter (often the jump destination) */
|
||||
|
|
197
src/vdbeaux.c
197
src/vdbeaux.c
|
@ -545,73 +545,84 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
|||
** (4) Initialize the p4.xAdvance pointer on opcodes that use it.
|
||||
**
|
||||
** (5) Reclaim the memory allocated for storing labels.
|
||||
**
|
||||
** This routine will only function correctly if the mkopcodeh.tcl generator
|
||||
** script numbers the opcodes correctly. Changes to this routine must be
|
||||
** coordinated with changes to mkopcodeh.tcl.
|
||||
*/
|
||||
static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
int i;
|
||||
int nMaxArgs = *pMaxFuncArgs;
|
||||
Op *pOp;
|
||||
Parse *pParse = p->pParse;
|
||||
int *aLabel = pParse->aLabel;
|
||||
p->readOnly = 1;
|
||||
p->bIsReader = 0;
|
||||
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
|
||||
u8 opcode = pOp->opcode;
|
||||
pOp = &p->aOp[p->nOp-1];
|
||||
while(1){
|
||||
|
||||
/* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
|
||||
** cases from this switch! */
|
||||
switch( opcode ){
|
||||
case OP_Transaction: {
|
||||
if( pOp->p2!=0 ) p->readOnly = 0;
|
||||
/* fall thru */
|
||||
}
|
||||
case OP_AutoCommit:
|
||||
case OP_Savepoint: {
|
||||
p->bIsReader = 1;
|
||||
break;
|
||||
}
|
||||
/* Only JUMP opcodes and the short list of special opcodes in the switch
|
||||
** below need to be considered. The mkopcodeh.tcl generator script groups
|
||||
** all these opcodes together near the front of the opcode list. Skip
|
||||
** any opcode that does not need processing by virtual of the fact that
|
||||
** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization.
|
||||
*/
|
||||
if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){
|
||||
/* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
|
||||
** cases from this switch! */
|
||||
switch( pOp->opcode ){
|
||||
case OP_Transaction: {
|
||||
if( pOp->p2!=0 ) p->readOnly = 0;
|
||||
/* fall thru */
|
||||
}
|
||||
case OP_AutoCommit:
|
||||
case OP_Savepoint: {
|
||||
p->bIsReader = 1;
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
case OP_Checkpoint:
|
||||
case OP_Checkpoint:
|
||||
#endif
|
||||
case OP_Vacuum:
|
||||
case OP_JournalMode: {
|
||||
p->readOnly = 0;
|
||||
p->bIsReader = 1;
|
||||
break;
|
||||
}
|
||||
case OP_Vacuum:
|
||||
case OP_JournalMode: {
|
||||
p->readOnly = 0;
|
||||
p->bIsReader = 1;
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
case OP_VUpdate: {
|
||||
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
|
||||
break;
|
||||
}
|
||||
case OP_VFilter: {
|
||||
int n;
|
||||
assert( p->nOp - i >= 3 );
|
||||
assert( pOp[-1].opcode==OP_Integer );
|
||||
n = pOp[-1].p1;
|
||||
if( n>nMaxArgs ) nMaxArgs = n;
|
||||
break;
|
||||
}
|
||||
case OP_VUpdate: {
|
||||
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
|
||||
break;
|
||||
}
|
||||
case OP_VFilter: {
|
||||
int n;
|
||||
assert( (pOp - p->aOp) >= 3 );
|
||||
assert( pOp[-1].opcode==OP_Integer );
|
||||
n = pOp[-1].p1;
|
||||
if( n>nMaxArgs ) nMaxArgs = n;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case OP_Next:
|
||||
case OP_NextIfOpen:
|
||||
case OP_SorterNext: {
|
||||
pOp->p4.xAdvance = sqlite3BtreeNext;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
break;
|
||||
case OP_Next:
|
||||
case OP_NextIfOpen:
|
||||
case OP_SorterNext: {
|
||||
pOp->p4.xAdvance = sqlite3BtreeNext;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
break;
|
||||
}
|
||||
case OP_Prev:
|
||||
case OP_PrevIfOpen: {
|
||||
pOp->p4.xAdvance = sqlite3BtreePrevious;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case OP_Prev:
|
||||
case OP_PrevIfOpen: {
|
||||
pOp->p4.xAdvance = sqlite3BtreePrevious;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
break;
|
||||
if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){
|
||||
assert( ADDR(pOp->p2)<pParse->nLabel );
|
||||
pOp->p2 = aLabel[ADDR(pOp->p2)];
|
||||
}
|
||||
}
|
||||
|
||||
pOp->opflags = sqlite3OpcodeProperty[opcode];
|
||||
if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
|
||||
assert( ADDR(pOp->p2)<pParse->nLabel );
|
||||
pOp->p2 = aLabel[ADDR(pOp->p2)];
|
||||
}
|
||||
if( pOp==p->aOp ) break;
|
||||
pOp--;
|
||||
}
|
||||
sqlite3DbFree(p->db, pParse->aLabel);
|
||||
pParse->aLabel = 0;
|
||||
|
@ -791,52 +802,50 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int);
|
|||
** Delete a P4 value if necessary.
|
||||
*/
|
||||
static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
if( p4 ){
|
||||
assert( db );
|
||||
switch( p4type ){
|
||||
case P4_FUNCCTX: {
|
||||
freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc);
|
||||
/* Fall through into the next case */
|
||||
}
|
||||
case P4_REAL:
|
||||
case P4_INT64:
|
||||
case P4_DYNAMIC:
|
||||
case P4_INTARRAY: {
|
||||
sqlite3DbFree(db, p4);
|
||||
break;
|
||||
}
|
||||
case P4_KEYINFO: {
|
||||
if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
|
||||
break;
|
||||
}
|
||||
assert( db );
|
||||
switch( p4type ){
|
||||
case P4_FUNCCTX: {
|
||||
freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc);
|
||||
/* Fall through into the next case */
|
||||
}
|
||||
case P4_REAL:
|
||||
case P4_INT64:
|
||||
case P4_DYNAMIC:
|
||||
case P4_INTARRAY: {
|
||||
sqlite3DbFree(db, p4);
|
||||
break;
|
||||
}
|
||||
case P4_KEYINFO: {
|
||||
if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
|
||||
break;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
case P4_EXPR: {
|
||||
sqlite3ExprDelete(db, (Expr*)p4);
|
||||
break;
|
||||
}
|
||||
case P4_EXPR: {
|
||||
sqlite3ExprDelete(db, (Expr*)p4);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case P4_MPRINTF: {
|
||||
if( db->pnBytesFreed==0 ) sqlite3_free(p4);
|
||||
break;
|
||||
}
|
||||
case P4_FUNCDEF: {
|
||||
freeEphemeralFunction(db, (FuncDef*)p4);
|
||||
break;
|
||||
}
|
||||
case P4_MEM: {
|
||||
if( db->pnBytesFreed==0 ){
|
||||
sqlite3ValueFree((sqlite3_value*)p4);
|
||||
}else{
|
||||
Mem *p = (Mem*)p4;
|
||||
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case P4_VTAB : {
|
||||
if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
|
||||
break;
|
||||
case P4_MPRINTF: {
|
||||
if( db->pnBytesFreed==0 ) sqlite3_free(p4);
|
||||
break;
|
||||
}
|
||||
case P4_FUNCDEF: {
|
||||
freeEphemeralFunction(db, (FuncDef*)p4);
|
||||
break;
|
||||
}
|
||||
case P4_MEM: {
|
||||
if( db->pnBytesFreed==0 ){
|
||||
sqlite3ValueFree((sqlite3_value*)p4);
|
||||
}else{
|
||||
Mem *p = (Mem*)p4;
|
||||
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case P4_VTAB : {
|
||||
if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1651,11 +1651,12 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
|
|||
*/
|
||||
static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
|
||||
WhereInfo *pWInfo = pWC->pWInfo;
|
||||
int nb = 1+(pWInfo->pTabList->nSrc+7)/8;
|
||||
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
|
||||
Table *pTab = pItem->pTab;
|
||||
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
|
||||
p->iTab, nb, p->maskSelf, nb, p->prereq);
|
||||
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
|
||||
sqlite3DebugPrintf(" %12s",
|
||||
pItem->zAlias ? pItem->zAlias : pTab->zName);
|
||||
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
|
||||
|
|
|
@ -941,7 +941,13 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
|||
}
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
|
||||
/* These registers need to be preserved in case there is an IN operator
|
||||
** loop. So we could deallocate the registers here (and potentially
|
||||
** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems
|
||||
** simpler and safer to simply not reuse the registers.
|
||||
**
|
||||
** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
|
||||
*/
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
|
|
@ -165,4 +165,111 @@ foreach {tn mode} {
|
|||
} $plan($mode)
|
||||
}
|
||||
|
||||
# 2016-04-09.
|
||||
# Demonstrate a register overwrite problem when using two virtual
|
||||
# tables where the outer loop uses the IN operator.
|
||||
#
|
||||
set G(collist) [list PrimaryKey flagA columnA]
|
||||
set G(cols) [join $G(collist) ,]
|
||||
set G(nulls) "NULL"
|
||||
|
||||
proc vtab_command {method args} {
|
||||
global G
|
||||
|
||||
switch -- $method {
|
||||
xConnect {
|
||||
return "CREATE TABLE t1($G(cols))"
|
||||
}
|
||||
|
||||
xBestIndex {
|
||||
set clist [lindex $args 0]
|
||||
#puts $clist
|
||||
set W [list]
|
||||
set U [list]
|
||||
|
||||
set i 0
|
||||
for {set idx 0} {$idx < [llength $clist]} {incr idx} {
|
||||
array set c [lindex $clist $idx]
|
||||
if {$c(op)=="eq" && $c(usable)} {
|
||||
lappend W "[lindex $G(collist) $c(column)] = %$i%"
|
||||
lappend U use $idx
|
||||
incr i
|
||||
}
|
||||
}
|
||||
|
||||
if {$W==""} {
|
||||
set sql "SELECT rowid, * FROM t1"
|
||||
} else {
|
||||
set sql "SELECT rowid, * FROM t1 WHERE [join $W { AND }]"
|
||||
}
|
||||
|
||||
return [concat [list idxstr $sql] $U]
|
||||
}
|
||||
|
||||
xFilter {
|
||||
foreach {idxnum idxstr vals} $args {}
|
||||
|
||||
set map [list]
|
||||
for {set i 0} {$i < [llength $vals]} {incr i} {
|
||||
lappend map "%$i%"
|
||||
set v [lindex $vals $i]
|
||||
if {[string is integer $v]} {
|
||||
lappend map $v
|
||||
} else {
|
||||
lappend map "'$v'"
|
||||
}
|
||||
}
|
||||
set sql [string map $map $idxstr]
|
||||
|
||||
#puts "SQL: $sql"
|
||||
return [list sql $sql]
|
||||
}
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
register_tcl_module db
|
||||
|
||||
do_execsql_test 3.1 "
|
||||
CREATE TABLE t1($G(cols));
|
||||
INSERT INTO t1 VALUES(1, 0, 'ValueA');
|
||||
INSERT INTO t1 VALUES(2, 0, 'ValueA');
|
||||
INSERT INTO t1 VALUES(3, 0, 'ValueB');
|
||||
INSERT INTO t1 VALUES(4, 0, 'ValueB');
|
||||
"
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
CREATE VIRTUAL TABLE VirtualTableA USING tcl(vtab_command);
|
||||
CREATE VIRTUAL TABLE VirtualTableB USING tcl(vtab_command);
|
||||
}
|
||||
|
||||
do_execsql_test 3.3 { SELECT primarykey FROM VirtualTableA } {1 2 3 4}
|
||||
|
||||
do_execsql_test 3.4 {
|
||||
SELECT * FROM
|
||||
VirtualTableA a CROSS JOIN VirtualTableB b ON b.PrimaryKey=a.PrimaryKey
|
||||
WHERE a.ColumnA IN ('ValueA', 'ValueB') AND a.FlagA=0
|
||||
} {
|
||||
1 0 ValueA 1 0 ValueA
|
||||
2 0 ValueA 2 0 ValueA
|
||||
3 0 ValueB 3 0 ValueB
|
||||
4 0 ValueB 4 0 ValueB
|
||||
}
|
||||
|
||||
do_execsql_test 3.5 {
|
||||
SELECT * FROM
|
||||
VirtualTableA a CROSS JOIN VirtualTableB b ON b.PrimaryKey=a.PrimaryKey
|
||||
WHERE a.FlagA=0 AND a.ColumnA IN ('ValueA', 'ValueB')
|
||||
} {
|
||||
1 0 ValueA 1 0 ValueA
|
||||
2 0 ValueA 2 0 ValueA
|
||||
3 0 ValueB 3 0 ValueB
|
||||
4 0 ValueB 4 0 ValueB
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
|
|
@ -139,7 +139,26 @@ do_execsql_test 4.12 {
|
|||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
|
||||
|
||||
# 2016-04-09
|
||||
# Ticket https://sqlite.org/src/info/a306e56ff68b8fa5
|
||||
# Failure to completely delete when reverse_unordered_selects is
|
||||
# engaged.
|
||||
#
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 5.0 {
|
||||
PRAGMA page_size=1024;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX x1 ON t1(b, c);
|
||||
INSERT INTO t1(a,b,c) VALUES(1, 1, zeroblob(80));
|
||||
INSERT INTO t1(a,b,c) SELECT a+1, 1, c FROM t1;
|
||||
INSERT INTO t1(a,b,c) SELECT a+2, 1, c FROM t1;
|
||||
INSERT INTO t1(a,b,c) SELECT a+10, 2, c FROM t1 WHERE b=1;
|
||||
INSERT INTO t1(a,b,c) SELECT a+20, 3, c FROM t1 WHERE b=1;
|
||||
PRAGMA reverse_unordered_selects = ON;
|
||||
DELETE FROM t1 WHERE b=2;
|
||||
SELECT a FROM t1 WHERE b=2;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
|
|
@ -95,4 +95,38 @@ do_test savepoint7-2.2 {
|
|||
list $rc $msg [db eval {SELECT * FROM t2}]
|
||||
} {1 {abort due to ROLLBACK} {}}
|
||||
|
||||
# Ticket: https://www.sqlite.org/src/tktview/7f7f8026eda387d544b
|
||||
# Segfault in the in-memory journal logic triggered by a tricky
|
||||
# combination of SAVEPOINT operations.
|
||||
#
|
||||
unset -nocomplain i
|
||||
for {set i 248} {$i<=253} {incr i} {
|
||||
do_test savepoint7-3.$i {
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA temp_store=MEMORY;
|
||||
BEGIN;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<$::i)
|
||||
INSERT INTO t1(x,y) SELECT x*10, printf('%04d%.800c',x,'*') FROM c;
|
||||
SAVEPOINT one;
|
||||
SELECT count(*) FROM t1;
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<$::i)
|
||||
INSERT INTO t1(x,y) SELECT x*10+1, printf('%04d%.800c',x,'*') FROM c;
|
||||
ROLLBACK TO one;
|
||||
SELECT count(*) FROM t1;
|
||||
SAVEPOINT twoB;
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<10)
|
||||
INSERT INTO t1(x,y) SELECT x*10+2, printf('%04d%.800c',x,'*') FROM c;
|
||||
ROLLBACK TO twoB;
|
||||
RELEASE one;
|
||||
COMMIT;
|
||||
}
|
||||
} [list $i $i]
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
|
|
@ -92,6 +92,26 @@ do_test view-1.8 {
|
|||
}
|
||||
} {2 3 5 6 8 9}
|
||||
|
||||
do_execsql_test view-1.10 {
|
||||
CREATE TABLE t9(x INTEGER);
|
||||
CREATE VIEW v9a AS SELECT x FROM t9;
|
||||
CREATE VIEW v9b AS SELECT * FROM t9;
|
||||
CREATE VIEW v9c(x) AS SELECT x FROM t9;
|
||||
CREATE VIEW v9d(x) AS SELECT * FROM t9;
|
||||
} {}
|
||||
do_execsql_test view-1.11 {
|
||||
PRAGMA table_info(v9a);
|
||||
} {0 x INTEGER 0 {} 0}
|
||||
do_execsql_test view-1.12 {
|
||||
PRAGMA table_info(v9b);
|
||||
} {0 x INTEGER 0 {} 0}
|
||||
do_execsql_test view-1.13 {
|
||||
PRAGMA table_info(v9c);
|
||||
} {0 x INTEGER 0 {} 0}
|
||||
do_execsql_test view-1.14 {
|
||||
PRAGMA table_info(v9d);
|
||||
} {0 x INTEGER 0 {} 0}
|
||||
|
||||
do_test view-2.1 {
|
||||
execsql {
|
||||
CREATE VIEW v2 AS SELECT * FROM t1 WHERE a>5
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
# during code generation, we need to generate corresponding opcodes like
|
||||
# OP_Add and OP_Divide. By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide,
|
||||
# code to translate from one to the other is avoided. This makes the
|
||||
# code generator run (infinitesimally) faster and more importantly it makes
|
||||
# the library footprint smaller.
|
||||
# code generator smaller and faster.
|
||||
#
|
||||
# This script also scans for lines of the form:
|
||||
#
|
||||
|
@ -159,7 +158,29 @@ for {set i 0} {$i<$nOp} {incr i} {
|
|||
}
|
||||
}
|
||||
|
||||
# Generate the numeric values for remaining opcodes
|
||||
# Assign the next group of values to JUMP opcodes
|
||||
#
|
||||
for {set i 0} {$i<$nOp} {incr i} {
|
||||
set name $order($i)
|
||||
if {$op($name)>=0} continue
|
||||
if {!$jump($name)} continue
|
||||
incr cnt
|
||||
while {[info exists used($cnt)]} {incr cnt}
|
||||
set op($name) $cnt
|
||||
set used($cnt) 1
|
||||
set def($cnt) $name
|
||||
}
|
||||
|
||||
# Find the numeric value for the largest JUMP opcode
|
||||
#
|
||||
set mxJump -1
|
||||
for {set i 0} {$i<$nOp} {incr i} {
|
||||
set name $order($i)
|
||||
if {$jump($name) && $op($name)>$mxJump} {set mxJump $op($name)}
|
||||
}
|
||||
|
||||
|
||||
# Generate the numeric values for all remaining opcodes
|
||||
#
|
||||
for {set i 0} {$i<$nOp} {incr i} {
|
||||
set name $order($i)
|
||||
|
@ -232,3 +253,11 @@ for {set i 0} {$i<=$max} {incr i} {
|
|||
}
|
||||
}
|
||||
puts "\175"
|
||||
puts ""
|
||||
puts "/* The sqlite3P2Values() routine is able to run faster if it knows"
|
||||
puts "** the value of the largest JUMP opcode. The smaller the maximum"
|
||||
puts "** JUMP opcode the better, so the mkopcodeh.tcl script that"
|
||||
puts "** generated this include file strives to group all JUMP opcodes"
|
||||
puts "** together near the beginning of the list."
|
||||
puts "*/"
|
||||
puts "#define SQLITE_MX_JUMP_OPCODE $mxJump /* Maximum JUMP opcode */"
|
||||
|
|
Loading…
Reference in New Issue