Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 36e2d71d71 | |||
| 569d74dc5f | |||
| 9ca0b52623 | |||
| 9b709c0b65 | |||
| a1bb9c0979 | |||
| 436003fc52 | |||
| 8e3b333080 | |||
| 0ac2aa4ed0 | |||
| 7afd98dddb | |||
| 0b150dd857 | |||
| 05d15a69a7 | |||
| a5f2bd7326 | |||
| ef66331fe9 | |||
| ecd2c06025 | |||
| 5bc564f0d3 | |||
| 510eca1d25 | |||
| 90828dde62 | |||
| cda5b88f18 | |||
| ac92abf2d0 | |||
| 2dfea2f020 | |||
| d694cc5909 | |||
| 6477f2a4f8 |
@@ -1,8 +1,5 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Version\s3.7.2\srelease\scandidate\s1
|
||||
D 2010-08-23T18:52:01
|
||||
C Backport\scheck-in\s[62678be3df35cd]:\nWhen\sthe\ssame\sindex\sis\sused\sfor\sall\sOR-terms\sin\sa\sWHERE\sclause,\sthen\stry\sto\nuse\sthat\sindex\sas\sa\scovering\sindex.
|
||||
D 2012-08-25T00:49:08.886
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -110,35 +107,35 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c 8dc27638e7e2553e80b2b621f232be5eb1e85ef3
|
||||
F src/analyze.c da65ce99bb159b10e85a1e460adbe53a88062500
|
||||
F src/attach.c 17bec1f18254d9341369f20f90ba24ce35d20d10
|
||||
F src/analyze.c 0a58e3d8228617e619c48a3aa8991a1ff5ad7768
|
||||
F src/attach.c c689d516ee8cc52bf11bef2067d76eb8b716228a
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 8ff0b7018df253c7f30d3f9702b0b16f19209d5c
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c 5047fb303cdf6806a42676a6f513c57e15b7d69b
|
||||
F src/btree.h b4ba2fdf6b64c7c376bdfffa826af6b786b151d9
|
||||
F src/btreeInt.h 5b034ff54800046cc5870605d683ac1f9134bd99
|
||||
F src/build.c 0018d49629fc4807100c988dd191dd95e185bb38
|
||||
F src/btree.c 40c7a36152403d8e7266f99ef157a661c7ab9691
|
||||
F src/btree.h 2d1a83ad509047e8cc314fda7e054f99ff52414d
|
||||
F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0
|
||||
F src/build.c a8aca43dc4f02b2293fd872eafdc80e487443a80
|
||||
F src/callback.c da3c38d0ef5d7f04fae371e519bda61aa9cb1704
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
|
||||
F src/ctime.c 2e39d3374e785a63117e077bcba9d4a6656df363
|
||||
F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
|
||||
F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd
|
||||
F src/expr.c 9ee507c3dc6eaa5657cbd1dad026cdeda89c559f
|
||||
F src/delete.c e179bd660c559c630813b01d04db663de56a124d
|
||||
F src/expr.c 9c8147b9c2ffcd792191bad51028bf11719bac09
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 58bbf52c6ddd3f64ca40a3230f9e548a83a5cb16
|
||||
F src/fkey.c b792889ef26dd4531e77de35821547c9d2b72ca1
|
||||
F src/func.c 464b0dc70618b896c402c574eb04bc5eacf35341
|
||||
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c a4995747c062256582a90b4f87f716e11b067050
|
||||
F src/insert.c 9b6fa065fc528d305184d7fbd5506c8dd58592e0
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 6d422ea91cf3d2d00408c5a8f2391cd458da85f8
|
||||
F src/main.c 99622181f36d68e9f2a851c7b34263b3dcd03470
|
||||
F src/main.c 7f159a4c79b24a45858046e33353bf1c0a2df659
|
||||
F src/malloc.c 19a468460c7df72de245f10c06bd0625777b7c83
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2
|
||||
@@ -159,30 +156,30 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
|
||||
F src/os_unix.c 11194cbcf6a57456e58022dc537ab8c3497d9bb9
|
||||
F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7
|
||||
F src/pager.c a5f5d9787b11dfb0b6082e6f5846d00b459a8e19
|
||||
F src/pager.h ef8c8f71ab022cc2fff768a1175dd32355be9dcd
|
||||
F src/pager.c ff40d2a98f135c8505b1a0a0b17bbe5f2a3c0cd5
|
||||
F src/pager.h 8167a1e720d0b7a2790079007128e594010220ad
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c e921e8a1d52c93abde63cb6dad1fa39770410c52
|
||||
F src/pragma.c 8b24ce00a93de345b6c3bd1e1e2cfba9f63d2325
|
||||
F src/prepare.c ce4c35a2b1d5fe916e4a46b70d24a6e997d7c4c6
|
||||
F src/prepare.c c2b318037d626fed27905c9446730b560637217a
|
||||
F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 8add6cab889fc02e1492eda8dba462ccf11f51dd
|
||||
F src/select.c 6a7353def8f6e5d800198214bf5477e8d0524e36
|
||||
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
|
||||
F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h e33b15e8176442bf7484f0e716edfd1ce03b2979
|
||||
F src/sqliteInt.h da99fe107f8f51d0b624428b773122cfccb49e2a
|
||||
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c cacee9482417b6fc6043f6bb831ff9496d46242d
|
||||
F src/test1.c 55005c9781b157b1d215ba145768783b9abae78c
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
|
||||
F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
|
||||
F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
|
||||
F src/test5.c e1a19845625144caf038031234a12185e40d315c
|
||||
F src/test6.c c7256cc21d2409486d094277d5b017e8eced44ba
|
||||
@@ -193,7 +190,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
||||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
|
||||
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
|
||||
F src/test_config.c 5a11c51af2156e2d07186930b36f2b8239a4393f
|
||||
F src/test_config.c fcafb30c453b5e2bfea7acd3c596bd33417f1361
|
||||
F src/test_demovfs.c 0aed671636735116fc872c5b03706fd5612488b5
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20
|
||||
@@ -213,27 +210,27 @@ F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
|
||||
F src/test_vfs.c 702e52636113f6b9721da90ef1bf26e07fff414d
|
||||
F src/test_vfs.c 367e050ebedac89f741dbfdcade3d584a8061dc9
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
|
||||
F src/trigger.c b8bedb9c0084ceb51a40f54fcca2ce048c8de852
|
||||
F src/update.c 1521162d20c2994af1fdc8833e1a88dae09052c8
|
||||
F src/update.c e85ead70c972dcb0655ee2ce91422b1d50bcb7b0
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
||||
F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
|
||||
F src/vdbe.c 66c262a923915e596379b1d597178e04c5d719e4
|
||||
F src/vdbe.c 5fdbad94b51569c84189a6824ed98d1ec0695174
|
||||
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
|
||||
F src/vdbeInt.h ffd68c4d4229227a5089bec53a1c635146177abc
|
||||
F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4
|
||||
F src/vdbeapi.c d0f4407e465f261780ad725c1caece7d66a6aa35
|
||||
F src/vdbeaux.c c73bcefcebfd3d2cf91bf6a41ef0fb0d884814c6
|
||||
F src/vdbeaux.c 157d62a6a8ca22c3792f5957e887df8bda2d58eb
|
||||
F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
|
||||
F src/vdbemem.c e5673f81a2381b35c60e73ef0a8502be2ab1041e
|
||||
F src/vdbemem.c c9faa98e4127185b0b7be27d0fa79d802a0dc40e
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vtab.c 0e8e0cb30dffb078367e843e84e37ef99236c7e4
|
||||
F src/wal.c 5ac2119e23ee4424599d4275b66dc88d612a0543
|
||||
F src/wal.h 96669b645e27cd5a111ba59f0cae7743a207bc3c
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 7db3e41c2a846f9deeb24f1bbb75461b4010b7b5
|
||||
F src/where.c a4b2ea85eeca3350354570c3b06eee2ce00f8075
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 6745008c144bd2956d58864d21f7b304689c1cce
|
||||
@@ -242,9 +239,11 @@ F test/alter2.test 52096b711afe5f219e575c6db7a70f7a35df4f63
|
||||
F test/alter3.test 25b95a136708f22b87184fa6a4309eea03d65153
|
||||
F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test bf692e7db414f268a136bade16c03a1bdbb9240c
|
||||
F test/analyze2.test 59dac6c399c0c5d1a90a11ee7cc606743fb6db93
|
||||
F test/analyze3.test 6d4f4b0929545a9d1af803a0608a0c51b92a3537
|
||||
F test/analyze.test d21f2143664912a20d04b67baf4bed935e7b1b48
|
||||
F test/analyze2.test ea3df826879dd672031b27c6a845afc3a39f27d9
|
||||
F test/analyze3.test d61f55d8b472fc6e713160b1e577f7a68e63f38b
|
||||
F test/analyze5.test 1de8d66b11aae5a1453aa042d62e834a476bac9c
|
||||
F test/analyze6.test 1ba1aea8fad25a77ffd71f24522d1bb9ecc949fc
|
||||
F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3
|
||||
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
@@ -254,11 +253,11 @@ F test/attach.test ce9660e51768fab93cf129787be886c5d6c4fd81
|
||||
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
|
||||
F test/attach3.test bd9830bc3a0d22ed1310c9bff6896927937017dc
|
||||
F test/attachmalloc.test 38d2da5fdaf09ba0add57296967a3061e5842584
|
||||
F test/auth.test 8f21c160a4562f54f27618e85bac869efcecbcaf
|
||||
F test/auth.test 26cc6f219580191539bf335abe03e55e49310846
|
||||
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46
|
||||
F test/autoindex1.test 7df441bf0e7a88644eb80993339dbf1db3a12c68
|
||||
F test/autoindex1.test 5832aabf500dada692f325251a2231ab6b0e2d9a
|
||||
F test/autovacuum.test bb7c0885e6f8f1d633045de48f2b66082162766d
|
||||
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
@@ -297,7 +296,7 @@ F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
|
||||
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
|
||||
F test/collate3.test d28d2cfab2c3a3d4628ae4b2b7afc9965daa3b4c
|
||||
F test/collate4.test 3d3f123f83fd8ccda6f48d617e44e661b9870c7d
|
||||
F test/collate5.test fe0f43c4740d7b71b959cac668d19e42f2e06e4d
|
||||
F test/collate5.test 67f1d3e848e230ff4802815a79acb0a8b5e69bd7
|
||||
F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907
|
||||
F test/collate7.test fac8db7aac3978466c04ae892cc74dcf2bc031aa
|
||||
F test/collate8.test df26649cfcbddf109c04122b340301616d3a88f6
|
||||
@@ -343,9 +342,10 @@ F test/descidx1.test b1353c1a15cfbee97b13a1dcedaf0fe78163ba6a
|
||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f
|
||||
F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
|
||||
F test/distinct.test b3c4ebe6dbddb31d55b168fdaec08456ef323dc4
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_expr.test 8a35ce2718c61e871970bda09f4f3e549067c1ba
|
||||
F test/e_fkey.test 6721a741c6499b3ab7e5385923233343c8f1ad05
|
||||
F test/e_fkey.test 35a4ec281da928fa8ebc3591a9c957258ecbb8be
|
||||
F test/e_fts3.test 75bb0aee26384ef586165e21018a17f7cd843469
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398
|
||||
@@ -424,7 +424,7 @@ F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3malloc.test 059592c4f37ccd30138bbf8e3e5b7982cb5c8f2e
|
||||
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
|
||||
F test/fts3query.test 2468caf7938dbc3be2e049524320ce4faf2227b3
|
||||
F test/fts3query.test 682cf2855eebdc295f69ae1573b46f388dfac280
|
||||
F test/fts3rnd.test 707533ce943f490443ce5e696236bb1675a37635
|
||||
F test/fts3snippet.test 9f9a4a7e396c5d8ce2898be65ebabc429555430f
|
||||
F test/fts4aa.test eadf85621c0a113d4c7ad3ccbf8441130e007b8f
|
||||
@@ -447,15 +447,15 @@ F test/incrblob_err.test c577c91d4ed9e8336cdb188b15d6ee2a6fe9604e
|
||||
F test/incrvacuum.test 453d1e490d8f5ad2c9b3a54282a0690d6ae56462
|
||||
F test/incrvacuum2.test 9e22a794899c91b7d8c8e12eaacac8df249faafe
|
||||
F test/incrvacuum_ioerr.test 57d2f5777ab13fa03b87b262a4ea1bad5cfc0291
|
||||
F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad
|
||||
F test/index.test 7c104b61d4cce9e9bf4d1eccdc9074befceee6d5
|
||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
|
||||
F test/indexedby.test 5a1180602f2e72c481467bd4cae05dae5dc36f47
|
||||
F test/indexedby.test be501e381b82b2f8ab406309ba7aac46e221f4ad
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
|
||||
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
|
||||
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
|
||||
F test/insert4.test c1469999a58e86a85b74df645a820f4cc7a8273b
|
||||
F test/insert4.test 50e7a074a555663ad8de7a998ccb78ecf1c771c9
|
||||
F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766
|
||||
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1
|
||||
@@ -525,18 +525,18 @@ F test/memsubsys1.test 8fb47b7e2523f94c100f5885c5697505524de4b9
|
||||
F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
|
||||
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
|
||||
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||
F test/minmax3.test 66a60eb0f20281b0753249d347c5de0766954cee
|
||||
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
|
||||
F test/misc1.test e56baf44656dd68d6475a4b44521045a60241e9b
|
||||
F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd
|
||||
F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6
|
||||
F test/misc4.test 91e8ed25c092c2bb4e0bb01864631e2930f8d7de
|
||||
F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd
|
||||
F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
|
||||
F test/misc5.test 9f9338f8211c7f5d1cbe16331fa65d019501aa50
|
||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test c5f4e6a82e04e71820c0f9f64f6733f04c8ae0ae
|
||||
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
|
||||
F test/mutex1.test 5b71777fc127509cd257910c8db799de557a02de
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test a44e04df1486fcfb02d32468cbcd3c8e1e433723
|
||||
F test/nan.test c4b7462e15e0296f16e2ca0e11f3b011dd8d8cbb
|
||||
F test/notify1.test 8433bc74bd952fb8a6e3f8d7a4c2b28dfd69e310
|
||||
F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db
|
||||
F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a
|
||||
@@ -583,12 +583,12 @@ F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test 44aa6e7110592e18110b0b9cf5c024d37d23be17
|
||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
||||
F test/select6.test 2b5e8500d8ec3dd4c8e0c99eb1431b3d11fcc24c
|
||||
F test/select6.test cc25a8650cf9a4d4f74e586c45a75f9836516b18
|
||||
F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343
|
||||
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
||||
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
|
||||
F test/selectB.test 0d072c5846071b569766e6cd7f923f646a8b2bfa
|
||||
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
|
||||
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
||||
F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e
|
||||
@@ -625,7 +625,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
|
||||
F test/tempdb.test 800c36623d67a2ad1f58784b9c5644e0405af6e6
|
||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
||||
F test/tester.tcl 6135019fcfac363ea0e11aee670cc97080ab578e
|
||||
F test/tester.tcl 8a7f88189e7001979cde27877ff4b19781f097a3
|
||||
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
||||
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
||||
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
||||
@@ -643,12 +643,14 @@ F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
|
||||
F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e
|
||||
F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
|
||||
F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
|
||||
F test/tkt-54844eea3f.test a12b851128f46a695e4e378cca67409b9b8f5894
|
||||
F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
|
||||
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
|
||||
F test/tkt-78e04e52ea.test fb5430c675e708f5cbafdf3e7e5593da5145a527
|
||||
F test/tkt-78e04e52ea.test ab52f0c1e2de6e46c910f4cc16b086bba05952b7
|
||||
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
|
||||
F test/tkt-94c04eaadb.test be5ea61cb04dfdc047d19b5c5a9e75fa3da67a7f
|
||||
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
|
||||
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
|
||||
F test/tkt-cbd054fa6b.test f14f97ea43662e6f70c9e63287081e8be5d9d589
|
||||
F test/tkt-d11f09d36e.test fb44f7961aa6d4b632fb7b9768239832210b5fc7
|
||||
F test/tkt-d82e3f3721.test 731359dfdcdb36fea0559cd33fec39dd0ceae8e6
|
||||
@@ -704,7 +706,7 @@ F test/tkt3346.test 6f67c3ed7db94dfc5df4f5f0b63809a1f611e01a
|
||||
F test/tkt3357.test 77c37c6482b526fe89941ce951c22d011f5922ed
|
||||
F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b
|
||||
F test/tkt3424.test 61f831bd2b071bd128fa5d00fbda57e656ca5812
|
||||
F test/tkt3442.test 89d7b41a4ec4d9d9b40ab8575d648579fb13cb4f
|
||||
F test/tkt3442.test 0adb70e9fe9cb750a702065a68ad647409dbc158
|
||||
F test/tkt3457.test edbf54b05cbe5165f00192becbd621038f1615e4
|
||||
F test/tkt3461.test 228ea328a5a21e8663f80ee3d212a6ad92549a19
|
||||
F test/tkt3493.test 1686cbde85f8721fc1bdc0ee72f2ef2f63139218
|
||||
@@ -718,14 +720,14 @@ F test/tkt35xx.test ed9721bd9eb1693b3b4d3cf2a093fa7f92af0c93
|
||||
F test/tkt3630.test 929f64852103054125200bc825c316d5f75d42f7
|
||||
F test/tkt3718.test 3b59dcb5c4e7754dacd91e7fd353a61492cc402a
|
||||
F test/tkt3731.test 0c5f4cbffe102d43c3b2188af91a9e36348f974b
|
||||
F test/tkt3757.test 8f2208930655bbd4f92c14e19e72303a43e098ef
|
||||
F test/tkt3757.test 10cd679a88675c880533083fc79ac04324525595
|
||||
F test/tkt3761.test b95ea9c98f21cf91325f18a984887e62caceab33
|
||||
F test/tkt3762.test 2a9f3b03df44ec49ec0cfa8d5da6574c2a7853df
|
||||
F test/tkt3773.test 430b06567ce40285dfd2c4834a2a61816403efeb
|
||||
F test/tkt3791.test a6624b9a80b216a26cf473607f42f3e51898c267
|
||||
F test/tkt3793.test 754b73f0e6a9349c70dc57e522cf3247272ecd5d
|
||||
F test/tkt3810.test 90fa0635dfa7da9680c8cd3513350a49b3a8ae12
|
||||
F test/tkt3824.test 3da2f5c81b057e3ff355f5dfc9aa0cf0a92e0206
|
||||
F test/tkt3824.test 150aa00bb6220672e5f0eb14dc8eaa36750425f0
|
||||
F test/tkt3832.test 2300d10d57562b89875b72148338ac3e14f8847d
|
||||
F test/tkt3838.test f956f0719b5f805b12dd1dbf19f19d298bacebc3
|
||||
F test/tkt3841.test 4659845bc53f809a5932c61c6ce8c5bb9d6b947f
|
||||
@@ -757,10 +759,11 @@ F test/triggerA.test eaf11a29db2a11967d2d4b49d37f92bce598194e
|
||||
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/triggerC.test 2a23edcc00684d084902ba5ec93e721775c3a70a
|
||||
F test/triggerD.test c6add3817351451e419f6ff9e9a259b02b6e2de7
|
||||
F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
|
||||
F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
|
||||
F test/unordered.test 87ecfbb688f984d4aaf5716a343e260dd1fa2c6e
|
||||
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test 15ae6784e70428b8db64e95c92d84b19e507b719
|
||||
@@ -805,16 +808,17 @@ F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
|
||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||
F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
|
||||
F test/where3.test 3bf8006d441b66a57bee02bb420423f84eb8fde3
|
||||
F test/where3.test 3bd3848a1439e775e6d268e7896151763c8bc4b6
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test a0a92b8ce48d9c027fbdd7b764c7de1e1213575a
|
||||
F test/where8.test a6c740fd286d7883e274e17b6230a9d672a7ab1f
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test be19e1a92f80985c1a121b4678bf7d2123eaa623
|
||||
F test/where9.test 24f19ad14bb1b831564ced5273e681e495662848
|
||||
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereD.test 6b6270480480a30038029dd6cbceef54d009dbc6
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||
@@ -827,9 +831,9 @@ F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c.tcl aff0d53f0e84cf919922c0d02e767bdf5eeafb90
|
||||
F tool/mksqlite3h.tcl eb100dce83f24b501b325b340f8b5eb8e5106b3b
|
||||
F tool/mksqlite3h.tcl 71437ab26219c0414e05231eb9b7d8f50c2cb279
|
||||
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
|
||||
F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a
|
||||
F tool/omittest.tcl ec597b7db5177df7108705961171200d7ffcd786
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/shell1.test 930444cadb71ce9ce78bc6cd14ec21e6b69776ea
|
||||
@@ -849,14 +853,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 21a1e5961bba148fda50cc0b7d472ca74f90808a
|
||||
R aa9cc30f9dbcb7ea427137065cf4e4be
|
||||
P 89d63a0e1db6a86fa173fb8a4e3a3904ef9e488c
|
||||
R 1c2de8c77bbe509e9e60c8893c5a6225
|
||||
U drh
|
||||
Z e73ee740c6593b4458c2d23b6fa7b923
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFMcsNUoxKgR168RlERApyRAKCOHvk0Gn1uE2F8YVm3k/w13/3UugCeOh16
|
||||
bApiXjM1a7FP+Qr1HX5kWTQ=
|
||||
=L2Lf
|
||||
-----END PGP SIGNATURE-----
|
||||
Z d3dad17d9f134d722fd6b0b2a2f50b29
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
42537b60566f288167f1b5864a5435986838e3a3
|
||||
865dfcbaa59431422b5980c66c8e29e80c4ed7c9
|
||||
+87
-27
@@ -113,7 +113,8 @@ static void analyzeOneTable(
|
||||
int i; /* Loop counter */
|
||||
int topOfLoop; /* The top of the loop */
|
||||
int endOfLoop; /* The end of the loop */
|
||||
int addr; /* The address of an instruction */
|
||||
int addr = 0; /* The address of an instruction */
|
||||
int jZeroRows = 0; /* Jump from here if number of rows is zero */
|
||||
int iDb; /* Index of database containing pTab */
|
||||
int regTabname = iMem++; /* Register containing table name */
|
||||
int regIdxname = iMem++; /* Register containing index name */
|
||||
@@ -132,8 +133,15 @@ static void analyzeOneTable(
|
||||
#endif
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 || NEVER(pTab==0) || pTab->pIndex==0 ){
|
||||
/* Do no analysis for tables that have no indices */
|
||||
if( v==0 || NEVER(pTab==0) ){
|
||||
return;
|
||||
}
|
||||
if( pTab->tnum==0 ){
|
||||
/* Do not gather statistics on views or virtual tables */
|
||||
return;
|
||||
}
|
||||
if( memcmp(pTab->zName, "sqlite_", 7)==0 ){
|
||||
/* Do not gather statistics on system tables */
|
||||
return;
|
||||
}
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
@@ -150,6 +158,7 @@ static void analyzeOneTable(
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
||||
iIdxCur = pParse->nTab++;
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int nCol = pIdx->nColumn;
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
@@ -164,10 +173,7 @@ static void analyzeOneTable(
|
||||
(char *)pKey, P4_KEYINFO_HANDOFF);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
|
||||
/* Populate the registers containing the table and index names. */
|
||||
if( pTab->pIndex==pIdx ){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
|
||||
}
|
||||
/* Populate the register containing the index name. */
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0);
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
@@ -227,9 +233,10 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
|
||||
|
||||
for(i=0; i<nCol; i++){
|
||||
CollSeq *pColl;
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
if( i==0 ){
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
/* Check if the record that cursor iIdxCur points to contains a
|
||||
** value that should be stored in the sqlite_stat2 table. If so,
|
||||
** store it. */
|
||||
@@ -258,12 +265,17 @@ static void analyzeOneTable(
|
||||
|
||||
sqlite3VdbeJumpHere(v, ne);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regRecno, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
|
||||
/**** TODO: add collating sequence *****/
|
||||
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
||||
/* Always record the very first row */
|
||||
sqlite3VdbeAddOp1(v, OP_IfNot, iMem+1);
|
||||
}
|
||||
assert( pIdx->azColl!=0 );
|
||||
assert( pIdx->azColl[i]!=0 );
|
||||
pColl = sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
|
||||
sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem+nCol+i+1,
|
||||
(char*)pColl, P4_COLLSEQ);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
/* If a malloc failure has occurred, then the result of the expression
|
||||
@@ -274,7 +286,11 @@ static void analyzeOneTable(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-(nCol*2));
|
||||
int addr2 = sqlite3VdbeCurrentAddr(v) - (nCol*2);
|
||||
if( i==0 ){
|
||||
sqlite3VdbeJumpHere(v, addr2-1); /* Set jump dest for the OP_IfNot */
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr2); /* Set jump dest for the OP_Ne */
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
|
||||
}
|
||||
@@ -302,8 +318,10 @@ static void analyzeOneTable(
|
||||
** If K>0 then it is always the case the D>0 so division by zero
|
||||
** is never possible.
|
||||
*/
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno);
|
||||
if( jZeroRows==0 ){
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
|
||||
}
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno);
|
||||
@@ -317,13 +335,35 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
}
|
||||
|
||||
/* If the table has no indices, create a single sqlite_stat1 entry
|
||||
** containing NULL as the index name and the row count as the content.
|
||||
*/
|
||||
if( pTab->pIndex==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb);
|
||||
VdbeComment((v, "%s", pTab->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regSampleno);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur);
|
||||
}else{
|
||||
assert( jZeroRows>0 );
|
||||
addr = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeJumpHere(v, jZeroRows);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
if( pParse->nMem<regRec ) pParse->nMem = regRec;
|
||||
if( jZeroRows ){
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will cause the most recent index analysis to
|
||||
** be laoded into internal hash tables where is can be used.
|
||||
** be loaded into internal hash tables where is can be used.
|
||||
*/
|
||||
static void loadAnalysis(Parse *pParse, int iDb){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
@@ -453,35 +493,52 @@ struct analysisInfo {
|
||||
** This callback is invoked once for each index when reading the
|
||||
** sqlite_stat1 table.
|
||||
**
|
||||
** argv[0] = name of the index
|
||||
** argv[1] = results of analysis - on integer for each column
|
||||
** argv[0] = name of the table
|
||||
** argv[1] = name of the index (might be NULL)
|
||||
** argv[2] = results of analysis - on integer for each column
|
||||
**
|
||||
** Entries for which argv[1]==NULL simply record the number of rows in
|
||||
** the table.
|
||||
*/
|
||||
static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
analysisInfo *pInfo = (analysisInfo*)pData;
|
||||
Index *pIndex;
|
||||
int i, c;
|
||||
Table *pTable;
|
||||
int i, c, n;
|
||||
unsigned int v;
|
||||
const char *z;
|
||||
|
||||
assert( argc==2 );
|
||||
assert( argc==3 );
|
||||
UNUSED_PARAMETER2(NotUsed, argc);
|
||||
|
||||
if( argv==0 || argv[0]==0 || argv[1]==0 ){
|
||||
if( argv==0 || argv[0]==0 || argv[2]==0 ){
|
||||
return 0;
|
||||
}
|
||||
pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase);
|
||||
if( pIndex==0 ){
|
||||
pTable = sqlite3FindTable(pInfo->db, argv[0], pInfo->zDatabase);
|
||||
if( pTable==0 ){
|
||||
return 0;
|
||||
}
|
||||
z = argv[1];
|
||||
for(i=0; *z && i<=pIndex->nColumn; i++){
|
||||
if( argv[1] ){
|
||||
pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
|
||||
}else{
|
||||
pIndex = 0;
|
||||
}
|
||||
n = pIndex ? pIndex->nColumn : 0;
|
||||
z = argv[2];
|
||||
for(i=0; *z && i<=n; i++){
|
||||
v = 0;
|
||||
while( (c=z[0])>='0' && c<='9' ){
|
||||
v = v*10 + c - '0';
|
||||
z++;
|
||||
}
|
||||
if( i==0 ) pTable->nRowEst = v;
|
||||
if( pIndex==0 ) break;
|
||||
pIndex->aiRowEst[i] = v;
|
||||
if( *z==' ' ) z++;
|
||||
if( memcmp(z, "unordered", 10)==0 ){
|
||||
pIndex->bUnordered = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -555,7 +612,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
|
||||
/* Load new statistics out of the sqlite_stat1 table */
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
|
||||
"SELECT tbl, idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -583,8 +640,11 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char *zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
Index *pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase);
|
||||
char *zIndex; /* Index name */
|
||||
Index *pIdx; /* Pointer to the index object */
|
||||
|
||||
zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
pIdx = zIndex ? sqlite3FindIndex(db, zIndex, sInfo.zDatabase) : 0;
|
||||
if( pIdx ){
|
||||
int iSample = sqlite3_column_int(pStmt, 1);
|
||||
if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){
|
||||
|
||||
+2
-3
@@ -124,9 +124,8 @@ static void attachFunc(
|
||||
** it to obtain the database schema. At this point the schema may
|
||||
** or may not be initialised.
|
||||
*/
|
||||
rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE,
|
||||
db->openFlags | SQLITE_OPEN_MAIN_DB,
|
||||
&aNew->pBt);
|
||||
rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0,
|
||||
db->openFlags | SQLITE_OPEN_MAIN_DB);
|
||||
db->nDb++;
|
||||
if( rc==SQLITE_CONSTRAINT ){
|
||||
rc = SQLITE_ERROR;
|
||||
|
||||
+74
-8
@@ -1672,11 +1672,20 @@ static int btreeInvokeBusyHandler(void *pArg){
|
||||
** Open a database file.
|
||||
**
|
||||
** zFilename is the name of the database file. If zFilename is NULL
|
||||
** a new database with a random name is created. This randomly named
|
||||
** database file will be deleted when sqlite3BtreeClose() is called.
|
||||
** then an ephemeral database is created. The ephemeral database might
|
||||
** be exclusively in memory, or it might use a disk-based memory cache.
|
||||
** Either way, the ephemeral database will be automatically deleted
|
||||
** when sqlite3BtreeClose() is called.
|
||||
**
|
||||
** If zFilename is ":memory:" then an in-memory database is created
|
||||
** that is automatically destroyed when it is closed.
|
||||
**
|
||||
** The "flags" parameter is a bitmask that might contain bits
|
||||
** BTREE_OMIT_JOURNAL and/or BTREE_NO_READLOCK. The BTREE_NO_READLOCK
|
||||
** bit is also set if the SQLITE_NoReadlock flags is set in db->flags.
|
||||
** These flags are passed through into sqlite3PagerOpen() and must
|
||||
** be the same values as PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK.
|
||||
**
|
||||
** If the database is already opened in the same database connection
|
||||
** and we are in shared cache mode, then the open will fail with an
|
||||
** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared
|
||||
@@ -1698,6 +1707,9 @@ int sqlite3BtreeOpen(
|
||||
u8 nReserve; /* Byte of unused space on each page */
|
||||
unsigned char zDbHeader[100]; /* Database header content */
|
||||
|
||||
/* True if opening an ephemeral, temporary database */
|
||||
const int isTempDb = zFilename==0 || zFilename[0]==0;
|
||||
|
||||
/* Set the variable isMemdb to true for an in-memory database, or
|
||||
** false for a file-based database. This symbol is only required if
|
||||
** either of the shared-data or autovacuum features are compiled
|
||||
@@ -1707,13 +1719,30 @@ int sqlite3BtreeOpen(
|
||||
#ifdef SQLITE_OMIT_MEMORYDB
|
||||
const int isMemdb = 0;
|
||||
#else
|
||||
const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
|
||||
const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0)
|
||||
|| (isTempDb && sqlite3TempInMemory(db));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
assert( db!=0 );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
assert( (flags&0xff)==flags ); /* flags fit in 8 bits */
|
||||
|
||||
/* Only a BTREE_SINGLE database can be BTREE_UNORDERED */
|
||||
assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 );
|
||||
|
||||
/* A BTREE_SINGLE database is always a temporary and/or ephemeral */
|
||||
assert( (flags & BTREE_SINGLE)==0 || isTempDb );
|
||||
|
||||
if( db->flags & SQLITE_NoReadlock ){
|
||||
flags |= BTREE_NO_READLOCK;
|
||||
}
|
||||
if( isMemdb ){
|
||||
flags |= BTREE_MEMORY;
|
||||
}
|
||||
if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
|
||||
vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
|
||||
}
|
||||
pVfs = db->pVfs;
|
||||
p = sqlite3MallocZero(sizeof(Btree));
|
||||
if( !p ){
|
||||
@@ -1731,7 +1760,7 @@ int sqlite3BtreeOpen(
|
||||
** If this Btree is a candidate for shared cache, try to find an
|
||||
** existing BtShared object that we can share with
|
||||
*/
|
||||
if( isMemdb==0 && zFilename && zFilename[0] ){
|
||||
if( isMemdb==0 && isTempDb==0 ){
|
||||
if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){
|
||||
int nFullPathname = pVfs->mxPathname+1;
|
||||
char *zFullPathname = sqlite3Malloc(nFullPathname);
|
||||
@@ -1806,6 +1835,7 @@ int sqlite3BtreeOpen(
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto btree_open_out;
|
||||
}
|
||||
pBt->openFlags = flags;
|
||||
pBt->db = db;
|
||||
sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
|
||||
p->pBt = pBt;
|
||||
@@ -1910,6 +1940,14 @@ btree_open_out:
|
||||
sqlite3_free(pBt);
|
||||
sqlite3_free(p);
|
||||
*ppBtree = 0;
|
||||
}else{
|
||||
/* If the B-Tree was successfully opened, set the pager-cache size to the
|
||||
** default value. Except, when opening on an existing shared pager-cache,
|
||||
** do not change the pager-cache size.
|
||||
*/
|
||||
if( sqlite3BtreeSchema(p, 0, 0)==0 ){
|
||||
sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
|
||||
}
|
||||
}
|
||||
if( mutexOpen ){
|
||||
assert( sqlite3_mutex_held(mutexOpen) );
|
||||
@@ -4552,6 +4590,15 @@ int sqlite3BtreeEof(BtCursor *pCur){
|
||||
** successful then set *pRes=0. If the cursor
|
||||
** was already pointing to the last entry in the database before
|
||||
** this routine was called, then set *pRes=1.
|
||||
**
|
||||
** The calling function will set *pRes to 0 or 1. The initial *pRes value
|
||||
** will be 1 if the cursor being stepped corresponds to an SQL index and
|
||||
** if this routine could have been skipped if that SQL index had been
|
||||
** a unique index. Otherwise the caller will have set *pRes to zero.
|
||||
** Zero is the common case. The btree implementation is free to use the
|
||||
** initial *pRes value as a hint to improve performance, but the current
|
||||
** SQLite btree implementation does not. (Note that the comdb2 btree
|
||||
** implementation does use this hint, however.)
|
||||
*/
|
||||
int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
@@ -4559,11 +4606,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
MemPage *pPage;
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pRes!=0 );
|
||||
if( CURSOR_INVALID==pCur->eState ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
@@ -4621,12 +4669,23 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
** successful then set *pRes=0. If the cursor
|
||||
** was already pointing to the first entry in the database before
|
||||
** this routine was called, then set *pRes=1.
|
||||
**
|
||||
** The calling function will set *pRes to 0 or 1. The initial *pRes value
|
||||
** will be 1 if the cursor being stepped corresponds to an SQL index and
|
||||
** if this routine could have been skipped if that SQL index had been
|
||||
** a unique index. Otherwise the caller will have set *pRes to zero.
|
||||
** Zero is the common case. The btree implementation is free to use the
|
||||
** initial *pRes value as a hint to improve performance, but the current
|
||||
** SQLite btree implementation does not. (Note that the comdb2 btree
|
||||
** implementation does use this hint, however.)
|
||||
*/
|
||||
int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
MemPage *pPage;
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
@@ -6778,7 +6837,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
** sub-tree headed by the child page of the cell being deleted. This makes
|
||||
** balancing the tree following the delete operation easier. */
|
||||
if( !pPage->leaf ){
|
||||
int notUsed;
|
||||
int notUsed = 0;
|
||||
rc = sqlite3BtreePrevious(pCur, ¬Used);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
@@ -6860,11 +6919,12 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
|
||||
** BTREE_ZERODATA Used for SQL indices
|
||||
*/
|
||||
static int btreeCreateTable(Btree *p, int *piTable, int flags){
|
||||
static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
BtShared *pBt = p->pBt;
|
||||
MemPage *pRoot;
|
||||
Pgno pgnoRoot;
|
||||
int rc;
|
||||
int ptfFlags; /* Page-type flage for the root page of new table */
|
||||
|
||||
assert( sqlite3BtreeHoldsMutex(p) );
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
@@ -6983,8 +7043,14 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
|
||||
}
|
||||
#endif
|
||||
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
|
||||
zeroPage(pRoot, flags | PTF_LEAF);
|
||||
if( createTabFlags & BTREE_INTKEY ){
|
||||
ptfFlags = PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF;
|
||||
}else{
|
||||
ptfFlags = PTF_ZERODATA | PTF_LEAF;
|
||||
}
|
||||
zeroPage(pRoot, ptfFlags);
|
||||
sqlite3PagerUnref(pRoot->pDbPage);
|
||||
assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
|
||||
*piTable = (int)pgnoRoot;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+13
-8
@@ -67,12 +67,11 @@ int sqlite3BtreeOpen(
|
||||
** NOTE: These values must match the corresponding PAGER_ values in
|
||||
** pager.h.
|
||||
*/
|
||||
#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
|
||||
#define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */
|
||||
#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
|
||||
#define BTREE_MEMORY 4 /* In-memory DB. No argument */
|
||||
#define BTREE_READONLY 8 /* Open the database in read-only mode */
|
||||
#define BTREE_READWRITE 16 /* Open for both reading and writing */
|
||||
#define BTREE_CREATE 32 /* Create the database if it does not exist */
|
||||
#define BTREE_MEMORY 4 /* This is an in-memory DB */
|
||||
#define BTREE_SINGLE 8 /* The file contains at most 1 b-tree */
|
||||
#define BTREE_UNORDERED 16 /* Use of a hash implementation is OK */
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
@@ -108,11 +107,17 @@ int sqlite3BtreeCopyFile(Btree *, Btree *);
|
||||
int sqlite3BtreeIncrVacuum(Btree *);
|
||||
|
||||
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
|
||||
** of the following flags:
|
||||
** of the flags shown below.
|
||||
**
|
||||
** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set.
|
||||
** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data
|
||||
** is stored in the leaves. (BTREE_INTKEY is used for SQL tables.) With
|
||||
** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored
|
||||
** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL
|
||||
** indices.)
|
||||
*/
|
||||
#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
|
||||
#define BTREE_ZERODATA 2 /* Table has keys only - no data */
|
||||
#define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */
|
||||
#define BTREE_BLOBKEY 2 /* Table has keys only - no data */
|
||||
|
||||
int sqlite3BtreeDropTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTable(Btree*, int, int*);
|
||||
|
||||
@@ -409,6 +409,7 @@ struct BtShared {
|
||||
u8 pageSizeFixed; /* True if the page size can no longer be changed */
|
||||
u8 secureDelete; /* True if secure_delete is enabled */
|
||||
u8 initiallyEmpty; /* Database is empty at start of transaction */
|
||||
u8 openFlags; /* Flags to sqlite3BtreeOpen() */
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
||||
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
||||
|
||||
+9
-8
@@ -802,6 +802,7 @@ void sqlite3StartTable(
|
||||
pTable->iPKey = -1;
|
||||
pTable->pSchema = db->aDb[iDb].pSchema;
|
||||
pTable->nRef = 1;
|
||||
pTable->nRowEst = 1000000;
|
||||
assert( pParse->pNewTable==0 );
|
||||
pParse->pNewTable = pTable;
|
||||
|
||||
@@ -2832,14 +2833,14 @@ exit_create_index:
|
||||
void sqlite3DefaultRowEst(Index *pIdx){
|
||||
unsigned *a = pIdx->aiRowEst;
|
||||
int i;
|
||||
unsigned n;
|
||||
assert( a!=0 );
|
||||
a[0] = 1000000;
|
||||
for(i=pIdx->nColumn; i>=5; i--){
|
||||
a[i] = 5;
|
||||
}
|
||||
while( i>=1 ){
|
||||
a[i] = 11 - i;
|
||||
i--;
|
||||
a[0] = pIdx->pTable->nRowEst;
|
||||
if( a[0]<10 ) a[0] = 10;
|
||||
n = 10;
|
||||
for(i=1; i<=pIdx->nColumn; i++){
|
||||
a[i] = n;
|
||||
if( n>5 ) n--;
|
||||
}
|
||||
if( pIdx->onError!=OE_None ){
|
||||
a[pIdx->nColumn] = 1;
|
||||
@@ -3391,7 +3392,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
SQLITE_OPEN_DELETEONCLOSE |
|
||||
SQLITE_OPEN_TEMP_DB;
|
||||
|
||||
rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags, &pBt);
|
||||
rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3ErrorMsg(pParse, "unable to open a temporary database "
|
||||
"file for storing temporary tables");
|
||||
|
||||
@@ -299,6 +299,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
||||
"OMIT_TRUNCATE_OPTIMIZATION",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
"OMIT_UNIQUE_ENFORCEMENT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_UTF16
|
||||
"OMIT_UTF16",
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -362,7 +362,9 @@ void sqlite3DeleteFrom(
|
||||
/* Collect rowids of every row to be deleted.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,WHERE_DUPLICATES_OK);
|
||||
pWInfo = sqlite3WhereBegin(
|
||||
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK, 0
|
||||
);
|
||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
|
||||
|
||||
+28
-89
@@ -896,6 +896,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
||||
pNewItem->jointype = pOldItem->jointype;
|
||||
pNewItem->iCursor = pOldItem->iCursor;
|
||||
pNewItem->isPopulated = pOldItem->isPopulated;
|
||||
pNewItem->isCorrelated = pOldItem->isCorrelated;
|
||||
pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex);
|
||||
pNewItem->notIndexed = pOldItem->notIndexed;
|
||||
pNewItem->pIndex = pOldItem->pIndex;
|
||||
@@ -1535,8 +1536,8 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Generate code for scalar subqueries used as an expression
|
||||
** and IN operators. Examples:
|
||||
** Generate code for scalar subqueries used as a subquery expression, EXISTS,
|
||||
** or IN operators. Examples:
|
||||
**
|
||||
** (SELECT a FROM b) -- subquery
|
||||
** EXISTS (SELECT a FROM b) -- EXISTS subquery
|
||||
@@ -1599,10 +1600,10 @@ int sqlite3CodeSubselect(
|
||||
|
||||
switch( pExpr->op ){
|
||||
case TK_IN: {
|
||||
char affinity;
|
||||
KeyInfo keyInfo;
|
||||
int addr; /* Address of OP_OpenEphemeral instruction */
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
char affinity; /* Affinity of the LHS of the IN */
|
||||
KeyInfo keyInfo; /* Keyinfo for the generated table */
|
||||
int addr; /* Address of OP_OpenEphemeral instruction */
|
||||
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
|
||||
|
||||
if( rMayHaveNull ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
|
||||
@@ -1625,6 +1626,7 @@ int sqlite3CodeSubselect(
|
||||
*/
|
||||
pExpr->iTable = pParse->nTab++;
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
|
||||
if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
memset(&keyInfo, 0, sizeof(keyInfo));
|
||||
keyInfo.nField = 1;
|
||||
|
||||
@@ -2233,73 +2235,6 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
|
||||
}
|
||||
#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
|
||||
|
||||
/*
|
||||
** If the last instruction coded is an ephemeral copy of any of
|
||||
** the registers in the nReg registers beginning with iReg, then
|
||||
** convert the last instruction from OP_SCopy to OP_Copy.
|
||||
*/
|
||||
void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){
|
||||
VdbeOp *pOp;
|
||||
Vdbe *v;
|
||||
|
||||
assert( pParse->db->mallocFailed==0 );
|
||||
v = pParse->pVdbe;
|
||||
assert( v!=0 );
|
||||
pOp = sqlite3VdbeGetOp(v, -1);
|
||||
assert( pOp!=0 );
|
||||
if( pOp->opcode==OP_SCopy && pOp->p1>=iReg && pOp->p1<iReg+nReg ){
|
||||
pOp->opcode = OP_Copy;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to store the value of the iAlias-th alias in register
|
||||
** target. The first time this is called, pExpr is evaluated to compute
|
||||
** the value of the alias. The value is stored in an auxiliary register
|
||||
** and the number of that register is returned. On subsequent calls,
|
||||
** the register number is returned without generating any code.
|
||||
**
|
||||
** Note that in order for this to work, code must be generated in the
|
||||
** same order that it is executed.
|
||||
**
|
||||
** Aliases are numbered starting with 1. So iAlias is in the range
|
||||
** of 1 to pParse->nAlias inclusive.
|
||||
**
|
||||
** pParse->aAlias[iAlias-1] records the register number where the value
|
||||
** of the iAlias-th alias is stored. If zero, that means that the
|
||||
** alias has not yet been computed.
|
||||
*/
|
||||
static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
|
||||
#if 0
|
||||
sqlite3 *db = pParse->db;
|
||||
int iReg;
|
||||
if( pParse->nAliasAlloc<pParse->nAlias ){
|
||||
pParse->aAlias = sqlite3DbReallocOrFree(db, pParse->aAlias,
|
||||
sizeof(pParse->aAlias[0])*pParse->nAlias );
|
||||
testcase( db->mallocFailed && pParse->nAliasAlloc>0 );
|
||||
if( db->mallocFailed ) return 0;
|
||||
memset(&pParse->aAlias[pParse->nAliasAlloc], 0,
|
||||
(pParse->nAlias-pParse->nAliasAlloc)*sizeof(pParse->aAlias[0]));
|
||||
pParse->nAliasAlloc = pParse->nAlias;
|
||||
}
|
||||
assert( iAlias>0 && iAlias<=pParse->nAlias );
|
||||
iReg = pParse->aAlias[iAlias-1];
|
||||
if( iReg==0 ){
|
||||
if( pParse->iCacheLevel>0 ){
|
||||
iReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||
}else{
|
||||
iReg = ++pParse->nMem;
|
||||
sqlite3ExprCode(pParse, pExpr, iReg);
|
||||
pParse->aAlias[iAlias-1] = iReg;
|
||||
}
|
||||
}
|
||||
return iReg;
|
||||
#else
|
||||
UNUSED_PARAMETER(iAlias);
|
||||
return sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code into the current Vdbe to evaluate the given
|
||||
** expression. Attempt to store the results in register "target".
|
||||
@@ -2408,7 +2343,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
break;
|
||||
}
|
||||
case TK_AS: {
|
||||
inReg = codeAlias(pParse, pExpr->iTable, pExpr->pLeft, target);
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
@@ -2840,6 +2775,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
opCompare.op = TK_EQ;
|
||||
opCompare.pLeft = &cacheX;
|
||||
pTest = &opCompare;
|
||||
/* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
|
||||
** The value in regFree1 might get SCopy-ed into the file result.
|
||||
** So make sure that the regFree1 register is not reused for other
|
||||
** purposes and possibly overwritten. */
|
||||
regFree1 = 0;
|
||||
}
|
||||
for(i=0; i<nExpr; i=i+2){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
@@ -2933,10 +2873,14 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
int inReg;
|
||||
|
||||
assert( target>0 && target<=pParse->nMem );
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||
assert( pParse->pVdbe || pParse->db->mallocFailed );
|
||||
if( inReg!=target && pParse->pVdbe ){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
|
||||
if( pExpr && pExpr->op==TK_REGISTER ){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
|
||||
}else{
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||
assert( pParse->pVdbe || pParse->db->mallocFailed );
|
||||
if( inReg!=target && pParse->pVdbe ){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
@@ -3109,19 +3053,14 @@ int sqlite3ExprCodeExprList(
|
||||
int i, n;
|
||||
assert( pList!=0 );
|
||||
assert( target>0 );
|
||||
assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */
|
||||
n = pList->nExpr;
|
||||
for(pItem=pList->a, i=0; i<n; i++, pItem++){
|
||||
if( pItem->iAlias ){
|
||||
int iReg = codeAlias(pParse, pItem->iAlias, pItem->pExpr, target+i);
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( iReg!=target+i ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target+i);
|
||||
}
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pItem->pExpr, target+i);
|
||||
}
|
||||
if( doHardCopy && !pParse->db->mallocFailed ){
|
||||
sqlite3ExprHardCopy(pParse, target, n);
|
||||
Expr *pExpr = pItem->pExpr;
|
||||
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
|
||||
if( inReg!=target+i ){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, doHardCopy ? OP_Copy : OP_SCopy,
|
||||
inReg, target+i);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
||||
+2
-2
@@ -380,7 +380,7 @@ static void fkLookupParent(
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
|
||||
sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[i]+1+regData, regTemp+i);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
|
||||
}
|
||||
|
||||
/* If the parent table is the same as the child table, and we are about
|
||||
@@ -548,7 +548,7 @@ static void fkScanChildren(
|
||||
** clause. If the constraint is not deferred, throw an exception for
|
||||
** each row found. Otherwise, for deferred constraints, increment the
|
||||
** deferred constraint counter by nIncr for each row selected. */
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
|
||||
if( nIncr>0 && pFKey->isDeferred==0 ){
|
||||
sqlite3ParseToplevel(pParse)->mayAbort = 1;
|
||||
}
|
||||
|
||||
@@ -1312,7 +1312,9 @@ void sqlite3GenerateConstraintChecks(
|
||||
*/
|
||||
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
|
||||
int regIdx;
|
||||
#ifndef SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
int regR;
|
||||
#endif
|
||||
|
||||
if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
|
||||
|
||||
@@ -1331,6 +1333,11 @@ void sqlite3GenerateConstraintChecks(
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1);
|
||||
|
||||
#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
|
||||
continue; /* Treat pIdx as if it is not a UNIQUE index */
|
||||
#else
|
||||
|
||||
/* Find out what action to take in case there is an indexing conflict */
|
||||
onError = pIdx->onError;
|
||||
if( onError==OE_None ){
|
||||
@@ -1404,6 +1411,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, j3);
|
||||
sqlite3ReleaseTempReg(pParse, regR);
|
||||
#endif
|
||||
}
|
||||
|
||||
if( pbMayReplace ){
|
||||
|
||||
+2
-57
@@ -1350,60 +1350,6 @@ int sqlite3TempInMemory(const sqlite3 *db){
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called to create a connection to a database BTree
|
||||
** driver. If zFilename is the name of a file, then that file is
|
||||
** opened and used. If zFilename is the magic name ":memory:" then
|
||||
** the database is stored in memory (and is thus forgotten as soon as
|
||||
** the connection is closed.) If zFilename is NULL then the database
|
||||
** is a "virtual" database for transient use only and is deleted as
|
||||
** soon as the connection is closed.
|
||||
**
|
||||
** A virtual database can be either a disk file (that is automatically
|
||||
** deleted when the file is closed) or it an be held entirely in memory.
|
||||
** The sqlite3TempInMemory() function is used to determine which.
|
||||
*/
|
||||
int sqlite3BtreeFactory(
|
||||
sqlite3 *db, /* Main database when opening aux otherwise 0 */
|
||||
const char *zFilename, /* Name of the file containing the BTree database */
|
||||
int omitJournal, /* if TRUE then do not journal this file */
|
||||
int nCache, /* How many pages in the page cache */
|
||||
int vfsFlags, /* Flags passed through to vfsOpen */
|
||||
Btree **ppBtree /* Pointer to new Btree object written here */
|
||||
){
|
||||
int btFlags = 0;
|
||||
int rc;
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
assert( ppBtree != 0);
|
||||
if( omitJournal ){
|
||||
btFlags |= BTREE_OMIT_JOURNAL;
|
||||
}
|
||||
if( db->flags & SQLITE_NoReadlock ){
|
||||
btFlags |= BTREE_NO_READLOCK;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
if( zFilename==0 && sqlite3TempInMemory(db) ){
|
||||
zFilename = ":memory:";
|
||||
}
|
||||
#endif
|
||||
|
||||
if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (zFilename==0 || *zFilename==0) ){
|
||||
vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
|
||||
}
|
||||
rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btFlags, vfsFlags);
|
||||
|
||||
/* If the B-Tree was successfully opened, set the pager-cache size to the
|
||||
** default value. Except, if the call to BtreeOpen() returned a handle
|
||||
** open on an existing shared pager-cache, do not change the pager-cache
|
||||
** size.
|
||||
*/
|
||||
if( rc==SQLITE_OK && 0==sqlite3BtreeSchema(*ppBtree, 0, 0) ){
|
||||
sqlite3BtreeSetCacheSize(*ppBtree, nCache);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return UTF-8 encoded English language explanation of the most recent
|
||||
** error.
|
||||
@@ -1785,9 +1731,8 @@ static int openDatabase(
|
||||
|
||||
/* Open the backend database driver */
|
||||
db->openFlags = flags;
|
||||
rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE,
|
||||
flags | SQLITE_OPEN_MAIN_DB,
|
||||
&db->aDb[0].pBt);
|
||||
rc = sqlite3BtreeOpen(zFilename, db, &db->aDb[0].pBt, 0,
|
||||
flags | SQLITE_OPEN_MAIN_DB);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_IOERR_NOMEM ){
|
||||
rc = SQLITE_NOMEM;
|
||||
|
||||
+9
-11
@@ -4226,6 +4226,13 @@ int sqlite3PagerOpen(
|
||||
/* Set the output variable to NULL in case an error occurs. */
|
||||
*ppPager = 0;
|
||||
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
if( flags & PAGER_MEMORY ){
|
||||
memDb = 1;
|
||||
zFilename = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Compute and store the full pathname in an allocated buffer pointed
|
||||
** to by zPathname, length nPathname. Or, if this is a temporary file,
|
||||
** leave both nPathname and zPathname set to 0.
|
||||
@@ -4236,17 +4243,8 @@ int sqlite3PagerOpen(
|
||||
if( zPathname==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
if( strcmp(zFilename,":memory:")==0 ){
|
||||
memDb = 1;
|
||||
zPathname[0] = 0;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
|
||||
rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
|
||||
}
|
||||
|
||||
zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
|
||||
rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
|
||||
nPathname = sqlite3Strlen30(zPathname);
|
||||
if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
|
||||
/* This branch is taken when the journal path required by
|
||||
|
||||
@@ -59,6 +59,7 @@ typedef struct PgHdr DbPage;
|
||||
*/
|
||||
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
|
||||
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
|
||||
#define PAGER_MEMORY 0x0004 /* In-memory database */
|
||||
|
||||
/*
|
||||
** Valid values for the second argument to sqlite3PagerLockingMode().
|
||||
|
||||
+3
-3
@@ -628,13 +628,13 @@ static int sqlite3Prepare(
|
||||
if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
|
||||
static const char * const azColName[] = {
|
||||
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
|
||||
"order", "from", "detail"
|
||||
"selectid", "order", "from", "detail"
|
||||
};
|
||||
int iFirst, mx;
|
||||
if( pParse->explain==2 ){
|
||||
sqlite3VdbeSetNumCols(pParse->pVdbe, 3);
|
||||
sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
|
||||
iFirst = 8;
|
||||
mx = 11;
|
||||
mx = 12;
|
||||
}else{
|
||||
sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
|
||||
iFirst = 0;
|
||||
|
||||
@@ -996,11 +996,25 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &p->pSrc->a[i];
|
||||
if( pItem->pSelect ){
|
||||
NameContext *pNC; /* Used to iterate name contexts */
|
||||
int nRef = 0; /* Refcount for pOuterNC and outer contexts */
|
||||
const char *zSavedContext = pParse->zAuthContext;
|
||||
|
||||
/* Count the total number of references to pOuterNC and all of its
|
||||
** parent contexts. After resolving references to expressions in
|
||||
** pItem->pSelect, check if this value has changed. If so, then
|
||||
** SELECT statement pItem->pSelect must be correlated. Set the
|
||||
** pItem->isCorrelated flag if this is the case. */
|
||||
for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef;
|
||||
|
||||
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
|
||||
sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
|
||||
pParse->zAuthContext = zSavedContext;
|
||||
if( pParse->nErr || db->mallocFailed ) return WRC_Abort;
|
||||
|
||||
for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef;
|
||||
assert( pItem->isCorrelated==0 && nRef<=0 );
|
||||
pItem->isCorrelated = (nRef!=0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+134
-27
@@ -1302,6 +1302,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
||||
assert( db->lookaside.bEnabled==0 );
|
||||
pTab->nRef = 1;
|
||||
pTab->zName = 0;
|
||||
pTab->nRowEst = 1000000;
|
||||
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
||||
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
|
||||
pTab->iPKey = -1;
|
||||
@@ -1372,6 +1373,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
||||
VdbeComment((v, "LIMIT counter"));
|
||||
if( n==0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
|
||||
}else{
|
||||
if( p->nSelectRow > (double)n ) p->nSelectRow = (double)n;
|
||||
}
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, p->pLimit, iLimit);
|
||||
@@ -1503,6 +1506,7 @@ static int multiSelect(
|
||||
if( dest.eDest==SRT_EphemTab ){
|
||||
assert( p->pEList );
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iParm, p->pEList->nExpr);
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
dest.eDest = SRT_Table;
|
||||
}
|
||||
|
||||
@@ -1528,6 +1532,7 @@ static int multiSelect(
|
||||
switch( p->op ){
|
||||
case TK_ALL: {
|
||||
int addr = 0;
|
||||
int nLimit;
|
||||
assert( !pPrior->pLimit );
|
||||
pPrior->pLimit = p->pLimit;
|
||||
pPrior->pOffset = p->pOffset;
|
||||
@@ -1548,6 +1553,13 @@ static int multiSelect(
|
||||
testcase( rc!=SQLITE_OK );
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->nSelectRow += pPrior->nSelectRow;
|
||||
if( pPrior->pLimit
|
||||
&& sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
|
||||
&& p->nSelectRow > (double)nLimit
|
||||
){
|
||||
p->nSelectRow = (double)nLimit;
|
||||
}
|
||||
if( addr ){
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
@@ -1618,6 +1630,7 @@ static int multiSelect(
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->pOrderBy = 0;
|
||||
if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
|
||||
sqlite3ExprDelete(db, p->pLimit);
|
||||
p->pLimit = pLimit;
|
||||
p->pOffset = pOffset;
|
||||
@@ -1695,6 +1708,7 @@ static int multiSelect(
|
||||
testcase( rc!=SQLITE_OK );
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
|
||||
sqlite3ExprDelete(db, p->pLimit);
|
||||
p->pLimit = pLimit;
|
||||
p->pOffset = pOffset;
|
||||
@@ -2274,6 +2288,7 @@ static int multiSelectOrderBy(
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
|
||||
p->nSelectRow += pPrior->nSelectRow;
|
||||
}
|
||||
|
||||
/* Generate a subroutine to run when the results from select B
|
||||
@@ -2281,6 +2296,7 @@ static int multiSelectOrderBy(
|
||||
*/
|
||||
if( op==TK_INTERSECT ){
|
||||
addrEofB = addrEofA;
|
||||
if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
|
||||
}else{
|
||||
VdbeNoopComment((v, "eof-B subroutine"));
|
||||
addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
||||
@@ -3101,6 +3117,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
||||
selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
|
||||
pTab->iPKey = -1;
|
||||
pTab->nRowEst = 1000000;
|
||||
pTab->tabFlags |= TF_Ephemeral;
|
||||
#endif
|
||||
}else{
|
||||
@@ -3465,7 +3482,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
if( pList ){
|
||||
nArg = pList->nExpr;
|
||||
regAgg = sqlite3GetTempRange(pParse, nArg);
|
||||
sqlite3ExprCodeExprList(pParse, pList, regAgg, 0);
|
||||
sqlite3ExprCodeExprList(pParse, pList, regAgg, 1);
|
||||
}else{
|
||||
nArg = 0;
|
||||
regAgg = 0;
|
||||
@@ -3517,6 +3534,32 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a single OP_Explain instruction to the VDBE to explain a simple
|
||||
** count(*) query ("SELECT count(*) FROM pTab").
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
static void explainSimpleCount(
|
||||
Parse *pParse, /* Parse context */
|
||||
Table *pTab, /* Table being queried */
|
||||
Index *pIdx /* Index used to optimize scan, or NULL */
|
||||
){
|
||||
if( pParse->explain==2 ){
|
||||
char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s %s%s(~%d rows)",
|
||||
pTab->zName,
|
||||
pIdx ? "USING COVERING INDEX " : "",
|
||||
pIdx ? pIdx->zName : "",
|
||||
pTab->nRowEst
|
||||
);
|
||||
sqlite3VdbeAddOp4(
|
||||
pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC
|
||||
);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define explainSimpleCount(a,b,c)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Generate code for the SELECT statement given in the p argument.
|
||||
**
|
||||
@@ -3590,6 +3633,7 @@ int sqlite3Select(
|
||||
int distinct; /* Table to use for the distinct set */
|
||||
int rc = 1; /* Value to return from this function */
|
||||
int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
|
||||
int addrDistinctIndex; /* Address of an OP_OpenEphemeral instruction */
|
||||
AggInfo sAggInfo; /* Information used by aggregate queries */
|
||||
int iEnd; /* Address of the end of the query */
|
||||
sqlite3 *db; /* The database connection */
|
||||
@@ -3658,6 +3702,7 @@ int sqlite3Select(
|
||||
assert( pItem->isPopulated==0 );
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->isPopulated = 1;
|
||||
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
|
||||
}
|
||||
if( /*pParse->nErr ||*/ db->mallocFailed ){
|
||||
goto select_end;
|
||||
@@ -3707,17 +3752,6 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If possible, rewrite the query to use GROUP BY instead of DISTINCT.
|
||||
** GROUP BY might use an index, DISTINCT never does.
|
||||
*/
|
||||
assert( p->pGroupBy==0 || (p->selFlags & SF_Aggregate)!=0 );
|
||||
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ){
|
||||
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
||||
pGroupBy = p->pGroupBy;
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
isDistinct = 0;
|
||||
}
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then disable the ORDER BY clause since the GROUP BY
|
||||
** will cause elements to come out in the correct order. This is
|
||||
@@ -3730,6 +3764,30 @@ int sqlite3Select(
|
||||
pOrderBy = 0;
|
||||
}
|
||||
|
||||
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
||||
** if the select-list is the same as the ORDER BY list, then this query
|
||||
** can be rewritten as a GROUP BY. In other words, this:
|
||||
**
|
||||
** SELECT DISTINCT xyz FROM ... ORDER BY xyz
|
||||
**
|
||||
** is transformed to:
|
||||
**
|
||||
** SELECT xyz FROM ... GROUP BY xyz
|
||||
**
|
||||
** The second form is preferred as a single index (or temp-table) may be
|
||||
** used for both the ORDER BY and DISTINCT processing. As originally
|
||||
** written the query must use a temp-table for at least one of the ORDER
|
||||
** BY and DISTINCT, and an index or separate temp-table for the other.
|
||||
*/
|
||||
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
||||
&& sqlite3ExprListCompare(pOrderBy, p->pEList)==0
|
||||
){
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
||||
pGroupBy = p->pGroupBy;
|
||||
pOrderBy = 0;
|
||||
}
|
||||
|
||||
/* If there is an ORDER BY clause, then this sorting
|
||||
** index might end up being unused if the data can be
|
||||
** extracted in pre-sorted order. If that is the case, then the
|
||||
@@ -3758,28 +3816,30 @@ int sqlite3Select(
|
||||
/* Set the limiter.
|
||||
*/
|
||||
iEnd = sqlite3VdbeMakeLabel(v);
|
||||
p->nSelectRow = (double)LARGEST_INT64;
|
||||
computeLimitRegisters(pParse, p, iEnd);
|
||||
|
||||
/* Open a virtual index to use for the distinct set.
|
||||
*/
|
||||
if( isDistinct ){
|
||||
if( p->selFlags & SF_Distinct ){
|
||||
KeyInfo *pKeyInfo;
|
||||
assert( isAgg || pGroupBy );
|
||||
distinct = pParse->nTab++;
|
||||
pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0,
|
||||
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
|
||||
addrDistinctIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0,
|
||||
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
}else{
|
||||
distinct = -1;
|
||||
}
|
||||
|
||||
/* Aggregate and non-aggregate queries are handled differently */
|
||||
if( !isAgg && pGroupBy==0 ){
|
||||
/* This case is for non-aggregate queries
|
||||
** Begin the database scan
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0);
|
||||
ExprList *pDist = (isDistinct ? p->pEList : 0);
|
||||
|
||||
/* Begin the database scan. */
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0,0);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
|
||||
|
||||
/* If sorting index that was created by a prior OP_OpenEphemeral
|
||||
** instruction ended up not being needed, then change the OP_OpenEphemeral
|
||||
@@ -3790,10 +3850,51 @@ int sqlite3Select(
|
||||
p->addrOpenEphm[2] = -1;
|
||||
}
|
||||
|
||||
/* Use the standard inner loop
|
||||
*/
|
||||
assert(!isDistinct);
|
||||
selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, -1, pDest,
|
||||
if( pWInfo->eDistinct ){
|
||||
VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
|
||||
|
||||
pOp = sqlite3VdbeGetOp(v, addrDistinctIndex);
|
||||
|
||||
assert( isDistinct );
|
||||
assert( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
|
||||
|| pWInfo->eDistinct==WHERE_DISTINCT_UNIQUE
|
||||
);
|
||||
distinct = -1;
|
||||
if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED ){
|
||||
int iJump;
|
||||
int iExpr;
|
||||
int iFlag = ++pParse->nMem;
|
||||
int iBase = pParse->nMem+1;
|
||||
int iBase2 = iBase + pEList->nExpr;
|
||||
pParse->nMem += (pEList->nExpr*2);
|
||||
|
||||
/* Change the OP_OpenEphemeral coded earlier to an OP_Integer. The
|
||||
** OP_Integer initializes the "first row" flag. */
|
||||
pOp->opcode = OP_Integer;
|
||||
pOp->p1 = 1;
|
||||
pOp->p2 = iFlag;
|
||||
|
||||
sqlite3ExprCodeExprList(pParse, pEList, iBase, 1);
|
||||
iJump = sqlite3VdbeCurrentAddr(v) + 1 + pEList->nExpr + 1 + 1;
|
||||
sqlite3VdbeAddOp2(v, OP_If, iFlag, iJump-1);
|
||||
for(iExpr=0; iExpr<pEList->nExpr; iExpr++){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[iExpr].pExpr);
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr);
|
||||
sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iContinue);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iFlag);
|
||||
assert( sqlite3VdbeCurrentAddr(v)==iJump );
|
||||
sqlite3VdbeAddOp3(v, OP_Move, iBase, iBase2, pEList->nExpr);
|
||||
}else{
|
||||
pOp->opcode = OP_Noop;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the standard inner loop. */
|
||||
selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, pDest,
|
||||
pWInfo->iContinue, pWInfo->iBreak);
|
||||
|
||||
/* End the database scan loop.
|
||||
@@ -3824,6 +3925,9 @@ int sqlite3Select(
|
||||
for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
|
||||
pItem->iAlias = 0;
|
||||
}
|
||||
if( p->nSelectRow>(double)100 ) p->nSelectRow = (double)100;
|
||||
}else{
|
||||
p->nSelectRow = (double)1;
|
||||
}
|
||||
|
||||
|
||||
@@ -3900,7 +4004,7 @@ int sqlite3Select(
|
||||
** in the right order to begin with.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0, 0);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( pGroupBy==0 ){
|
||||
/* The optimizer is able to deliver rows in group by order so
|
||||
@@ -4091,11 +4195,13 @@ int sqlite3Select(
|
||||
** and pKeyInfo to the KeyInfo structure required to navigate the
|
||||
** index.
|
||||
**
|
||||
** (2011-04-15) Do not do a full scan of an unordered index.
|
||||
**
|
||||
** In practice the KeyInfo structure will not be used. It is only
|
||||
** passed to keep OP_OpenRead happy.
|
||||
*/
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( !pBest || pIdx->nColumn<pBest->nColumn ){
|
||||
if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
|
||||
pBest = pIdx;
|
||||
}
|
||||
}
|
||||
@@ -4111,6 +4217,7 @@ int sqlite3Select(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
||||
explainSimpleCount(pParse, pTab, pBest);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||
{
|
||||
@@ -4156,7 +4263,7 @@ int sqlite3Select(
|
||||
** of output.
|
||||
*/
|
||||
resetAccumulator(pParse, &sAggInfo);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax,0,flag,0);
|
||||
if( pWInfo==0 ){
|
||||
sqlite3ExprListDelete(db, pDel);
|
||||
goto select_end;
|
||||
|
||||
+22
-6
@@ -1224,6 +1224,7 @@ struct Table {
|
||||
Column *aCol; /* Information about each column */
|
||||
Index *pIndex; /* List of SQL indexes on this table. */
|
||||
int tnum; /* Root BTree node for this table (see note above) */
|
||||
unsigned nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
|
||||
Select *pSelect; /* NULL for tables. Points to definition if a view. */
|
||||
u16 nRef; /* Number of pointers to this Table */
|
||||
u8 tabFlags; /* Mask of TF_* values */
|
||||
@@ -1427,6 +1428,7 @@ struct Index {
|
||||
int tnum; /* Page containing root of this index in database file */
|
||||
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
||||
u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
|
||||
u8 bUnordered; /* Use this index for == or IN queries only */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
Index *pNext; /* The next index associated with the same table */
|
||||
Schema *pSchema; /* Schema containing this index */
|
||||
@@ -1792,6 +1794,10 @@ struct SrcList {
|
||||
u8 isPopulated; /* Temporary table associated with SELECT is populated */
|
||||
u8 jointype; /* Type of join between this able and the previous */
|
||||
u8 notIndexed; /* True if there is a NOT INDEXED clause */
|
||||
u8 isCorrelated; /* True if sub-query is correlated */
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
|
||||
#endif
|
||||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
@@ -1830,6 +1836,7 @@ struct SrcList {
|
||||
struct WherePlan {
|
||||
u32 wsFlags; /* WHERE_* flags that describe the strategy */
|
||||
u32 nEq; /* Number of == constraints */
|
||||
double nRow; /* Estimated number of rows (for EQP) */
|
||||
union {
|
||||
Index *pIdx; /* Index when WHERE_INDEXED is true */
|
||||
struct WhereTerm *pTerm; /* WHERE clause term for OR-search */
|
||||
@@ -1860,8 +1867,8 @@ struct WhereLevel {
|
||||
int addrCont; /* Jump here to continue with the next loop cycle */
|
||||
int addrFirst; /* First instruction of interior of the loop */
|
||||
u8 iFrom; /* Which entry in the FROM clause */
|
||||
u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */
|
||||
int p1, p2; /* Operands of the opcode used to ends the loop */
|
||||
u8 op, p3, p5; /* Opcode, P3, and P5 of the end-of-loop instruction */
|
||||
int p1, p2; /* P1 and P2 operands of the end-of-loop instruction */
|
||||
union { /* Information that depends on plan.wsFlags */
|
||||
struct {
|
||||
int nIn; /* Number of entries in aInLoop[] */
|
||||
@@ -1870,6 +1877,7 @@ struct WhereLevel {
|
||||
int addrInTop; /* Top of the IN loop */
|
||||
} *aInLoop; /* Information about each nested IN operator */
|
||||
} in; /* Used when plan.wsFlags&WHERE_IN_ABLE */
|
||||
Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
|
||||
} u;
|
||||
|
||||
/* The following field is really not part of the current level. But
|
||||
@@ -1907,6 +1915,7 @@ struct WhereInfo {
|
||||
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
|
||||
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
|
||||
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
||||
u8 eDistinct;
|
||||
SrcList *pTabList; /* List of tables in the join */
|
||||
int iTop; /* The very beginning of the WHERE loop */
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
@@ -1914,9 +1923,13 @@ struct WhereInfo {
|
||||
int nLevel; /* Number of nested loop */
|
||||
struct WhereClause *pWC; /* Decomposition of the WHERE clause */
|
||||
double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
|
||||
double nRowOut; /* Estimated number of output rows */
|
||||
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
||||
};
|
||||
|
||||
#define WHERE_DISTINCT_UNIQUE 1
|
||||
#define WHERE_DISTINCT_ORDERED 2
|
||||
|
||||
/*
|
||||
** A NameContext defines a context in which to resolve table and column
|
||||
** names. The context consists of a list of tables (the pSrcList) field and
|
||||
@@ -1989,6 +2002,7 @@ struct Select {
|
||||
Expr *pOffset; /* OFFSET expression. NULL means not used. */
|
||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
|
||||
double nSelectRow; /* Estimated number of result rows */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2184,6 +2198,10 @@ struct Parse {
|
||||
int nHeight; /* Expression tree height of current sub-select */
|
||||
Table *pZombieTab; /* List of Table objects to delete after code gen */
|
||||
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
int iSelectId; /* Subquery ID for query planning */
|
||||
int iNextSelectId; /* Next available subquery ID */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||
@@ -2661,7 +2679,8 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *,
|
||||
#endif
|
||||
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
||||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16);
|
||||
WhereInfo *sqlite3WhereBegin(
|
||||
Parse*,SrcList*,Expr*,ExprList**,ExprList*,u16,int);
|
||||
void sqlite3WhereEnd(WhereInfo*);
|
||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
|
||||
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
|
||||
@@ -2673,7 +2692,6 @@ void sqlite3ExprCachePop(Parse*, int);
|
||||
void sqlite3ExprCacheRemove(Parse*, int, int);
|
||||
void sqlite3ExprCacheClear(Parse*);
|
||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||
void sqlite3ExprHardCopy(Parse*,int,int);
|
||||
int sqlite3ExprCode(Parse*, Expr*, int);
|
||||
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
||||
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
|
||||
@@ -2793,8 +2811,6 @@ void sqlite3DeferForeignKey(Parse*, int);
|
||||
#endif
|
||||
void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
|
||||
void sqlite3Detach(Parse*, Expr*);
|
||||
int sqlite3BtreeFactory(sqlite3 *db, const char *zFilename,
|
||||
int omitJournal, int nCache, int flags, Btree **ppBtree);
|
||||
int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
|
||||
int sqlite3FixSrcList(DbFixer*, SrcList*);
|
||||
int sqlite3FixSelect(DbFixer*, Select*);
|
||||
|
||||
+4
-5
@@ -53,7 +53,7 @@ static sqlite3 sDb;
|
||||
static int nRefSqlite3 = 0;
|
||||
|
||||
/*
|
||||
** Usage: btree_open FILENAME NCACHE FLAGS
|
||||
** Usage: btree_open FILENAME NCACHE
|
||||
**
|
||||
** Open a new database
|
||||
*/
|
||||
@@ -64,22 +64,21 @@ static int btree_open(
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc, nCache, flags;
|
||||
int rc, nCache;
|
||||
char zBuf[100];
|
||||
if( argc!=4 ){
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" FILENAME NCACHE FLAGS\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
|
||||
if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR;
|
||||
nRefSqlite3++;
|
||||
if( nRefSqlite3==1 ){
|
||||
sDb.pVfs = sqlite3_vfs_find(0);
|
||||
sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
|
||||
sqlite3_mutex_enter(sDb.mutex);
|
||||
}
|
||||
rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, flags,
|
||||
rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, 0,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
|
||||
@@ -469,6 +469,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
|
||||
Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
Tcl_SetVar2(interp, "sqlite_options", "unique_enforcement", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "unique_enforcement", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_UTF16
|
||||
Tcl_SetVar2(interp, "sqlite_options", "utf16", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
+12
-40
@@ -81,8 +81,6 @@ struct Testvfs {
|
||||
sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */
|
||||
Tcl_Interp *interp; /* Interpreter to run script in */
|
||||
Tcl_Obj *pScript; /* Script to execute */
|
||||
int nScript; /* Number of elements in array apScript */
|
||||
Tcl_Obj **apScript; /* Array version of pScript */
|
||||
TestvfsBuffer *pBuffer; /* List of shared buffers */
|
||||
int isNoshm;
|
||||
|
||||
@@ -268,48 +266,26 @@ static void tvfsExecTcl(
|
||||
Tcl_Obj *arg3
|
||||
){
|
||||
int rc; /* Return code from Tcl_EvalObj() */
|
||||
int nArg; /* Elements in eval'd list */
|
||||
int nScript;
|
||||
Tcl_Obj ** ap;
|
||||
|
||||
Tcl_Obj *pEval;
|
||||
assert( p->pScript );
|
||||
|
||||
if( !p->apScript ){
|
||||
int nByte;
|
||||
int i;
|
||||
if( TCL_OK!=Tcl_ListObjGetElements(p->interp, p->pScript, &nScript, &ap) ){
|
||||
Tcl_BackgroundError(p->interp);
|
||||
Tcl_ResetResult(p->interp);
|
||||
return;
|
||||
}
|
||||
p->nScript = nScript;
|
||||
nByte = (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *);
|
||||
p->apScript = (Tcl_Obj **)ckalloc(nByte);
|
||||
memset(p->apScript, 0, nByte);
|
||||
for(i=0; i<nScript; i++){
|
||||
p->apScript[i] = ap[i];
|
||||
}
|
||||
}
|
||||
assert( zMethod );
|
||||
assert( p );
|
||||
assert( arg2==0 || arg1!=0 );
|
||||
assert( arg3==0 || arg2!=0 );
|
||||
|
||||
p->apScript[p->nScript] = Tcl_NewStringObj(zMethod, -1);
|
||||
p->apScript[p->nScript+1] = arg1;
|
||||
p->apScript[p->nScript+2] = arg2;
|
||||
p->apScript[p->nScript+3] = arg3;
|
||||
pEval = Tcl_DuplicateObj(p->pScript);
|
||||
Tcl_IncrRefCount(p->pScript);
|
||||
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zMethod, -1));
|
||||
if( arg1 ) Tcl_ListObjAppendElement(p->interp, pEval, arg1);
|
||||
if( arg2 ) Tcl_ListObjAppendElement(p->interp, pEval, arg2);
|
||||
if( arg3 ) Tcl_ListObjAppendElement(p->interp, pEval, arg3);
|
||||
|
||||
for(nArg=p->nScript; p->apScript[nArg]; nArg++){
|
||||
Tcl_IncrRefCount(p->apScript[nArg]);
|
||||
}
|
||||
|
||||
rc = Tcl_EvalObjv(p->interp, nArg, p->apScript, TCL_EVAL_GLOBAL);
|
||||
rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
|
||||
if( rc!=TCL_OK ){
|
||||
Tcl_BackgroundError(p->interp);
|
||||
Tcl_ResetResult(p->interp);
|
||||
}
|
||||
|
||||
for(nArg=p->nScript; p->apScript[nArg]; nArg++){
|
||||
Tcl_DecrRefCount(p->apScript[nArg]);
|
||||
p->apScript[nArg] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1074,9 +1050,6 @@ static int testvfs_obj_cmd(
|
||||
int nByte;
|
||||
if( p->pScript ){
|
||||
Tcl_DecrRefCount(p->pScript);
|
||||
ckfree((char *)p->apScript);
|
||||
p->apScript = 0;
|
||||
p->nScript = 0;
|
||||
p->pScript = 0;
|
||||
}
|
||||
Tcl_GetStringFromObj(objv[2], &nByte);
|
||||
@@ -1230,7 +1203,6 @@ static void testvfs_obj_del(ClientData cd){
|
||||
Testvfs *p = (Testvfs *)cd;
|
||||
if( p->pScript ) Tcl_DecrRefCount(p->pScript);
|
||||
sqlite3_vfs_unregister(p->pVfs);
|
||||
ckfree((char *)p->apScript);
|
||||
ckfree((char *)p->pVfs);
|
||||
ckfree((char *)p);
|
||||
}
|
||||
|
||||
+4
-1
@@ -312,7 +312,9 @@ void sqlite3Update(
|
||||
/* Begin the database scan
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0, WHERE_ONEPASS_DESIRED);
|
||||
pWInfo = sqlite3WhereBegin(
|
||||
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, 0
|
||||
);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
okOnePass = pWInfo->okOnePass;
|
||||
|
||||
@@ -638,6 +640,7 @@ static void updateVirtualTable(
|
||||
assert( v );
|
||||
ephemTab = pParse->nTab++;
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
|
||||
/* fill the ephemeral table
|
||||
*/
|
||||
|
||||
+121
-16
@@ -46,6 +46,17 @@
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** Invoke this macro on memory cells just prior to changing the
|
||||
** value of the cell. This macro verifies that shallow copies are
|
||||
** not misused.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
# define memAboutToChange(P,M) sqlite3VdbeMemPrepareToChange(P,M)
|
||||
#else
|
||||
# define memAboutToChange(P,M)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following global variable is incremented every time a cursor
|
||||
** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test
|
||||
@@ -667,6 +678,7 @@ int sqlite3VdbeExec(
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=p->nMem );
|
||||
pOut = &aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
sqlite3VdbeMemReleaseExternal(pOut);
|
||||
pOut->flags = MEM_Int;
|
||||
}
|
||||
@@ -676,25 +688,30 @@ int sqlite3VdbeExec(
|
||||
if( (pOp->opflags & OPFLG_IN1)!=0 ){
|
||||
assert( pOp->p1>0 );
|
||||
assert( pOp->p1<=p->nMem );
|
||||
assert( memIsValid(&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 );
|
||||
assert( memIsValid(&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 );
|
||||
assert( memIsValid(&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 );
|
||||
memAboutToChange(p, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_OUT3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=p->nMem );
|
||||
memAboutToChange(p, &aMem[pOp->p3]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -756,6 +773,7 @@ case OP_Goto: { /* jump */
|
||||
case OP_Gosub: { /* jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
memAboutToChange(p, pIn1);
|
||||
pIn1->flags = MEM_Int;
|
||||
pIn1->u.i = pc;
|
||||
REGISTER_TRACE(pOp->p1, pIn1);
|
||||
@@ -1019,6 +1037,8 @@ case OP_Move: {
|
||||
while( n-- ){
|
||||
assert( pOut<=&aMem[p->nMem] );
|
||||
assert( pIn1<=&aMem[p->nMem] );
|
||||
assert( memIsValid(pIn1) );
|
||||
memAboutToChange(p, pOut);
|
||||
zMalloc = pOut->zMalloc;
|
||||
pOut->zMalloc = 0;
|
||||
sqlite3VdbeMemMove(pOut, pIn1);
|
||||
@@ -1064,6 +1084,9 @@ case OP_SCopy: { /* in1, out2 */
|
||||
pOut = &aMem[pOp->p2];
|
||||
assert( pOut!=pIn1 );
|
||||
sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
|
||||
#endif
|
||||
REGISTER_TRACE(pOp->p2, pOut);
|
||||
break;
|
||||
}
|
||||
@@ -1122,6 +1145,10 @@ case OP_ResultRow: {
|
||||
*/
|
||||
pMem = p->pResultSet = &aMem[pOp->p1];
|
||||
for(i=0; i<pOp->p2; i++){
|
||||
assert( memIsValid(&pMem[i]) );
|
||||
Deephemeralize(&pMem[i]);
|
||||
assert( (pMem[i].flags & MEM_Ephem)==0
|
||||
|| (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
|
||||
sqlite3VdbeMemNulTerminate(&pMem[i]);
|
||||
sqlite3VdbeMemStoreType(&pMem[i]);
|
||||
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
|
||||
@@ -1347,12 +1374,17 @@ case OP_Function: {
|
||||
n = pOp->p5;
|
||||
apVal = p->apArg;
|
||||
assert( apVal || n==0 );
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
pOut = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pOut);
|
||||
|
||||
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
|
||||
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
|
||||
pArg = &aMem[pOp->p2];
|
||||
for(i=0; i<n; i++, pArg++){
|
||||
assert( memIsValid(pArg) );
|
||||
apVal[i] = pArg;
|
||||
Deephemeralize(pArg);
|
||||
sqlite3VdbeMemStoreType(pArg);
|
||||
REGISTER_TRACE(pOp->p2+i, pArg);
|
||||
}
|
||||
@@ -1366,8 +1398,6 @@ case OP_Function: {
|
||||
ctx.pFunc = ctx.pVdbeFunc->pFunc;
|
||||
}
|
||||
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
pOut = &aMem[pOp->p3];
|
||||
ctx.s.flags = MEM_Null;
|
||||
ctx.s.db = db;
|
||||
ctx.s.xDel = 0;
|
||||
@@ -1487,6 +1517,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
|
||||
*/
|
||||
case OP_AddImm: { /* in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
memAboutToChange(p, pIn1);
|
||||
sqlite3VdbeMemIntegerify(pIn1);
|
||||
pIn1->u.i += pOp->p2;
|
||||
break;
|
||||
@@ -1501,6 +1532,7 @@ case OP_AddImm: { /* in1 */
|
||||
*/
|
||||
case OP_MustBeInt: { /* jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
memAboutToChange(p, pIn1);
|
||||
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
|
||||
if( (pIn1->flags & MEM_Int)==0 ){
|
||||
if( pOp->p2==0 ){
|
||||
@@ -1527,6 +1559,7 @@ case OP_MustBeInt: { /* jump, in1 */
|
||||
*/
|
||||
case OP_RealAffinity: { /* in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
memAboutToChange(p, pIn1);
|
||||
if( pIn1->flags & MEM_Int ){
|
||||
sqlite3VdbeMemRealify(pIn1);
|
||||
}
|
||||
@@ -1546,6 +1579,7 @@ case OP_RealAffinity: { /* in1 */
|
||||
*/
|
||||
case OP_ToText: { /* same as TK_TO_TEXT, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
memAboutToChange(p, pIn1);
|
||||
if( pIn1->flags & MEM_Null ) break;
|
||||
assert( MEM_Str==(MEM_Blob>>3) );
|
||||
pIn1->flags |= (pIn1->flags&MEM_Blob)>>3;
|
||||
@@ -1568,6 +1602,7 @@ case OP_ToText: { /* same as TK_TO_TEXT, in1 */
|
||||
*/
|
||||
case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
memAboutToChange(p, pIn1);
|
||||
if( pIn1->flags & MEM_Null ) break;
|
||||
if( (pIn1->flags & MEM_Blob)==0 ){
|
||||
applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
|
||||
@@ -1592,6 +1627,7 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
|
||||
*/
|
||||
case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
memAboutToChange(p, pIn1);
|
||||
if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
|
||||
sqlite3VdbeMemNumerify(pIn1);
|
||||
}
|
||||
@@ -1610,6 +1646,7 @@ case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
|
||||
*/
|
||||
case OP_ToInt: { /* same as TK_TO_INT, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
memAboutToChange(p, pIn1);
|
||||
if( (pIn1->flags & MEM_Null)==0 ){
|
||||
sqlite3VdbeMemIntegerify(pIn1);
|
||||
}
|
||||
@@ -1628,6 +1665,7 @@ case OP_ToInt: { /* same as TK_TO_INT, in1 */
|
||||
*/
|
||||
case OP_ToReal: { /* same as TK_TO_REAL, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
memAboutToChange(p, pIn1);
|
||||
if( (pIn1->flags & MEM_Null)==0 ){
|
||||
sqlite3VdbeMemRealify(pIn1);
|
||||
}
|
||||
@@ -1720,6 +1758,8 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pIn1);
|
||||
memAboutToChange(p, pIn3);
|
||||
flags1 = pIn1->flags;
|
||||
flags3 = pIn3->flags;
|
||||
if( (pIn1->flags | pIn3->flags)&MEM_Null ){
|
||||
@@ -1770,6 +1810,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
|
||||
if( pOp->p5 & SQLITE_STOREP2 ){
|
||||
pOut = &aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
MemSetTypeFlag(pOut, MEM_Int);
|
||||
pOut->u.i = res;
|
||||
REGISTER_TRACE(pOp->p2, pOut);
|
||||
@@ -1842,6 +1883,8 @@ case OP_Compare: {
|
||||
#endif /* SQLITE_DEBUG */
|
||||
for(i=0; i<n; i++){
|
||||
idx = aPermute ? aPermute[i] : i;
|
||||
assert( memIsValid(&aMem[p1+idx]) );
|
||||
assert( memIsValid(&aMem[p2+idx]) );
|
||||
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
|
||||
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
|
||||
assert( i<pKeyInfo->nField );
|
||||
@@ -2067,6 +2110,7 @@ case OP_Column: {
|
||||
assert( p1<p->nCursor );
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
MemSetTypeFlag(pDest, MEM_Null);
|
||||
zRec = 0;
|
||||
|
||||
@@ -2114,6 +2158,7 @@ case OP_Column: {
|
||||
}else if( pC->pseudoTableReg>0 ){
|
||||
pReg = &aMem[pC->pseudoTableReg];
|
||||
assert( pReg->flags & MEM_Blob );
|
||||
assert( memIsValid(pReg) );
|
||||
payloadSize = pReg->n;
|
||||
zRec = pReg->z;
|
||||
pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
|
||||
@@ -2336,6 +2381,8 @@ case OP_Affinity: {
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
while( (cAff = *(zAffinity++))!=0 ){
|
||||
assert( pIn1 <= &p->aMem[p->nMem] );
|
||||
assert( memIsValid(pIn1) );
|
||||
memAboutToChange(p, pIn1);
|
||||
ExpandBlob(pIn1);
|
||||
applyAffinity(pIn1, cAff, encoding);
|
||||
pIn1++;
|
||||
@@ -2405,11 +2452,18 @@ case OP_MakeRecord: {
|
||||
pLast = &pData0[nField-1];
|
||||
file_format = p->minWriteFileFormat;
|
||||
|
||||
/* Identify the output register */
|
||||
assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
|
||||
pOut = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pOut);
|
||||
|
||||
/* Loop through the elements that will make up the record to figure
|
||||
** out how much space is required for the new record.
|
||||
*/
|
||||
for(pRec=pData0; pRec<=pLast; pRec++){
|
||||
assert( memIsValid(pRec) );
|
||||
if( zAffinity ){
|
||||
memAboutToChange(p, pRec);
|
||||
applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
|
||||
}
|
||||
if( pRec->flags&MEM_Zero && pRec->n>0 ){
|
||||
@@ -2443,8 +2497,6 @@ case OP_MakeRecord: {
|
||||
** be one of the input registers (because the following call to
|
||||
** sqlite3VdbeMemGrow() could clobber the value before it is used).
|
||||
*/
|
||||
assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
|
||||
pOut = &aMem[pOp->p3];
|
||||
if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){
|
||||
goto no_mem;
|
||||
}
|
||||
@@ -2991,6 +3043,8 @@ case OP_OpenWrite: {
|
||||
assert( p2>0 );
|
||||
assert( p2<=p->nMem );
|
||||
pIn2 = &aMem[p2];
|
||||
assert( memIsValid(pIn2) );
|
||||
assert( (pIn2->flags & MEM_Int)!=0 );
|
||||
sqlite3VdbeMemIntegerify(pIn2);
|
||||
p2 = (int)pIn2->u.i;
|
||||
/* The p2 value always comes from a prior OP_CreateTable opcode and
|
||||
@@ -3013,6 +3067,7 @@ case OP_OpenWrite: {
|
||||
pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
|
||||
if( pCur==0 ) goto no_mem;
|
||||
pCur->nullRow = 1;
|
||||
pCur->isOrdered = 1;
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
|
||||
pCur->pKeyInfo = pKeyInfo;
|
||||
|
||||
@@ -3063,7 +3118,7 @@ case OP_OpenWrite: {
|
||||
case OP_OpenAutoindex:
|
||||
case OP_OpenEphemeral: {
|
||||
VdbeCursor *pCx;
|
||||
static const int openFlags =
|
||||
static const int vfsFlags =
|
||||
SQLITE_OPEN_READWRITE |
|
||||
SQLITE_OPEN_CREATE |
|
||||
SQLITE_OPEN_EXCLUSIVE |
|
||||
@@ -3074,21 +3129,21 @@ case OP_OpenEphemeral: {
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags,
|
||||
&pCx->pBt);
|
||||
rc = sqlite3BtreeOpen(0, db, &pCx->pBt,
|
||||
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
/* If a transient index is required, create it by calling
|
||||
** sqlite3BtreeCreateTable() with the BTREE_ZERODATA flag before
|
||||
** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
|
||||
** opening it. If a transient table is required, just use the
|
||||
** automatically created table with root-page 1 (an INTKEY table).
|
||||
** automatically created table with root-page 1 (an BLOB_INTKEY table).
|
||||
*/
|
||||
if( pOp->p4.pKeyInfo ){
|
||||
int pgno;
|
||||
assert( pOp->p4type==P4_KEYINFO );
|
||||
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
|
||||
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pgno==MASTER_ROOT+1 );
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1,
|
||||
@@ -3102,6 +3157,7 @@ case OP_OpenEphemeral: {
|
||||
pCx->isTable = 1;
|
||||
}
|
||||
}
|
||||
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
|
||||
pCx->isIndex = !pCx->isTable;
|
||||
break;
|
||||
}
|
||||
@@ -3217,6 +3273,7 @@ case OP_SeekGt: { /* jump, in3 */
|
||||
assert( OP_SeekLe == OP_SeekLt+1 );
|
||||
assert( OP_SeekGe == OP_SeekLt+2 );
|
||||
assert( OP_SeekGt == OP_SeekLt+3 );
|
||||
assert( pC->isOrdered );
|
||||
if( pC->pCursor!=0 ){
|
||||
oc = pOp->opcode;
|
||||
pC->nullRow = 0;
|
||||
@@ -3299,6 +3356,9 @@ case OP_SeekGt: { /* jump, in3 */
|
||||
assert( oc!=OP_SeekLt || r.flags==0 );
|
||||
|
||||
r.aMem = &aMem[pOp->p3];
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
||||
#endif
|
||||
ExpandBlob(r.aMem);
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -3313,6 +3373,7 @@ case OP_SeekGt: { /* jump, in3 */
|
||||
#endif
|
||||
if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt );
|
||||
if( res<0 || (res==0 && oc==OP_SeekGt) ){
|
||||
res = 0;
|
||||
rc = sqlite3BtreeNext(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
pC->rowidIsValid = 0;
|
||||
@@ -3322,6 +3383,7 @@ case OP_SeekGt: { /* jump, in3 */
|
||||
}else{
|
||||
assert( oc==OP_SeekLt || oc==OP_SeekLe );
|
||||
if( res>0 || (res==0 && oc==OP_SeekLt) ){
|
||||
res = 0;
|
||||
rc = sqlite3BtreePrevious(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
pC->rowidIsValid = 0;
|
||||
@@ -3423,11 +3485,14 @@ case OP_Found: { /* jump, in3 */
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
r.nField = (u16)pOp->p4.i;
|
||||
r.aMem = pIn3;
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
||||
#endif
|
||||
r.flags = UNPACKED_PREFIX_MATCH;
|
||||
pIdxKey = &r;
|
||||
}else{
|
||||
assert( pIn3->flags & MEM_Blob );
|
||||
ExpandBlob(pIn3);
|
||||
assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
|
||||
pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z,
|
||||
aTempRec, sizeof(aTempRec));
|
||||
if( pIdxKey==0 ){
|
||||
@@ -3520,6 +3585,9 @@ case OP_IsUnique: { /* jump, in3 */
|
||||
r.nField = nField + 1;
|
||||
r.flags = UNPACKED_PREFIX_SEARCH;
|
||||
r.aMem = aMx;
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
||||
#endif
|
||||
|
||||
/* Extract the value of R from register P3. */
|
||||
sqlite3VdbeMemIntegerify(pIn3);
|
||||
@@ -3696,7 +3764,9 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
/* Assert that P3 is a valid memory cell. */
|
||||
assert( pOp->p3<=p->nMem );
|
||||
pMem = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pMem);
|
||||
}
|
||||
assert( memIsValid(pMem) );
|
||||
|
||||
REGISTER_TRACE(pOp->p3, pMem);
|
||||
sqlite3VdbeMemIntegerify(pMem);
|
||||
@@ -3805,6 +3875,7 @@ case OP_InsertInt: {
|
||||
|
||||
pData = &aMem[pOp->p2];
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( memIsValid(pData) );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pCursor!=0 );
|
||||
@@ -3815,6 +3886,7 @@ case OP_InsertInt: {
|
||||
if( pOp->opcode==OP_Insert ){
|
||||
pKey = &aMem[pOp->p3];
|
||||
assert( pKey->flags & MEM_Int );
|
||||
assert( memIsValid(pKey) );
|
||||
REGISTER_TRACE(pOp->p3, pKey);
|
||||
iKey = pKey->u.i;
|
||||
}else{
|
||||
@@ -3962,6 +4034,7 @@ case OP_RowData: {
|
||||
i64 n64;
|
||||
|
||||
pOut = &aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
|
||||
/* Note that RowKey and RowData are really exactly the same instruction */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
@@ -4166,7 +4239,7 @@ case OP_Rewind: { /* jump */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Next P1 P2 * * P5
|
||||
/* Opcode: Next P1 P2 P3 * P5
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
** table or index. If there are no more key/value pairs then fall through
|
||||
@@ -4178,9 +4251,14 @@ case OP_Rewind: { /* jump */
|
||||
** If P5 is positive and the jump is taken, then event counter
|
||||
** number P5-1 in the prepared statement is incremented.
|
||||
**
|
||||
** The P3 value is a hint to the btree implementation. If P3==1, that
|
||||
** means P1 is an SQL index and that this instruction could have been
|
||||
** omitted if that index had been unique. P3 is usually 0. P3 is
|
||||
** always either 0 or 1.
|
||||
**
|
||||
** See also: Prev
|
||||
*/
|
||||
/* Opcode: Prev P1 P2 * * P5
|
||||
/* Opcode: Prev P1 P2 P3 * P5
|
||||
**
|
||||
** Back up cursor P1 so that it points to the previous key/data pair in its
|
||||
** table or index. If there is no previous key/value pairs then fall through
|
||||
@@ -4191,6 +4269,11 @@ case OP_Rewind: { /* jump */
|
||||
**
|
||||
** If P5 is positive and the jump is taken, then event counter
|
||||
** number P5-1 in the prepared statement is incremented.
|
||||
**
|
||||
** The P3 value is a hint to the btree implementation. If P3==1, that
|
||||
** means P1 is an SQL index and that this instruction could have been
|
||||
** omitted if that index had been unique. P3 is usually 0. P3 is
|
||||
** always either 0 or 1.
|
||||
*/
|
||||
case OP_Prev: /* jump */
|
||||
case OP_Next: { /* jump */
|
||||
@@ -4201,6 +4284,7 @@ case OP_Next: { /* jump */
|
||||
CHECK_FOR_INTERRUPT;
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( pOp->p5<=ArraySize(p->aCounter) );
|
||||
assert( pOp->p3==0 || pOp->p3==1 );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
if( pC==0 ){
|
||||
break; /* See ticket #2273 */
|
||||
@@ -4210,7 +4294,10 @@ case OP_Next: { /* jump */
|
||||
pC->nullRow = 1;
|
||||
break;
|
||||
}
|
||||
res = 1;
|
||||
res = pOp->p3;
|
||||
assert( res==0 || pC->isIndex==1 );
|
||||
testcase( res==1 );
|
||||
testcase( res==0 );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
|
||||
sqlite3BtreePrevious(pCrsr, &res);
|
||||
@@ -4290,6 +4377,9 @@ case OP_IdxDelete: {
|
||||
r.nField = (u16)pOp->p3;
|
||||
r.flags = 0;
|
||||
r.aMem = &aMem[pOp->p2];
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
||||
#endif
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
|
||||
if( rc==SQLITE_OK && res==0 ){
|
||||
rc = sqlite3BtreeDelete(pCrsr);
|
||||
@@ -4370,6 +4460,7 @@ case OP_IdxGE: { /* jump */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->isOrdered );
|
||||
if( ALWAYS(pC->pCursor!=0) ){
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pOp->p5==0 || pOp->p5==1 );
|
||||
@@ -4382,6 +4473,9 @@ case OP_IdxGE: { /* jump */
|
||||
r.flags = UNPACKED_IGNORE_ROWID;
|
||||
}
|
||||
r.aMem = &aMem[pOp->p3];
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
||||
#endif
|
||||
rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res);
|
||||
if( pOp->opcode==OP_IdxLT ){
|
||||
res = -res;
|
||||
@@ -4481,6 +4575,8 @@ case OP_Clear: {
|
||||
if( pOp->p3 ){
|
||||
p->nChange += nChange;
|
||||
if( pOp->p3>0 ){
|
||||
assert( memIsValid(&aMem[pOp->p3]) );
|
||||
memAboutToChange(p, &aMem[pOp->p3]);
|
||||
aMem[pOp->p3].u.i += nChange;
|
||||
}
|
||||
}
|
||||
@@ -4522,9 +4618,9 @@ case OP_CreateTable: { /* out2-prerelease */
|
||||
assert( pDb->pBt!=0 );
|
||||
if( pOp->opcode==OP_CreateTable ){
|
||||
/* flags = BTREE_INTKEY; */
|
||||
flags = BTREE_LEAFDATA|BTREE_INTKEY;
|
||||
flags = BTREE_INTKEY;
|
||||
}else{
|
||||
flags = BTREE_ZERODATA;
|
||||
flags = BTREE_BLOBKEY;
|
||||
}
|
||||
rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
|
||||
pOut->u.i = pgno;
|
||||
@@ -4843,6 +4939,7 @@ case OP_Program: { /* jump */
|
||||
|
||||
pProgram = pOp->p4.pProgram;
|
||||
pRt = &aMem[pOp->p3];
|
||||
assert( memIsValid(pRt) );
|
||||
assert( pProgram->nOp>0 );
|
||||
|
||||
/* If the p5 flag is clear, then recursive invocation of triggers is
|
||||
@@ -5012,6 +5109,7 @@ case OP_MemMax: { /* in2 */
|
||||
}else{
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
}
|
||||
assert( memIsValid(pIn1) );
|
||||
sqlite3VdbeMemIntegerify(pIn1);
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
sqlite3VdbeMemIntegerify(pIn2);
|
||||
@@ -5096,7 +5194,9 @@ case OP_AggStep: {
|
||||
apVal = p->apArg;
|
||||
assert( apVal || n==0 );
|
||||
for(i=0; i<n; i++, pRec++){
|
||||
assert( memIsValid(pRec) );
|
||||
apVal[i] = pRec;
|
||||
memAboutToChange(p, pRec);
|
||||
sqlite3VdbeMemStoreType(pRec);
|
||||
}
|
||||
ctx.pFunc = pOp->p4.pFunc;
|
||||
@@ -5491,6 +5591,7 @@ case OP_VFilter: { /* jump */
|
||||
pQuery = &aMem[pOp->p3];
|
||||
pArgc = &pQuery[1];
|
||||
pCur = p->apCsr[pOp->p1];
|
||||
assert( memIsValid(pQuery) );
|
||||
REGISTER_TRACE(pOp->p3, pQuery);
|
||||
assert( pCur->pVtabCursor );
|
||||
pVtabCursor = pCur->pVtabCursor;
|
||||
@@ -5546,6 +5647,7 @@ case OP_VColumn: {
|
||||
assert( pCur->pVtabCursor );
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
if( pCur->nullRow ){
|
||||
sqlite3VdbeMemSetNull(pDest);
|
||||
break;
|
||||
@@ -5644,6 +5746,7 @@ case OP_VRename: {
|
||||
pVtab = pOp->p4.pVtab->pVtab;
|
||||
pName = &aMem[pOp->p1];
|
||||
assert( pVtab->pModule->xRename );
|
||||
assert( memIsValid(pName) );
|
||||
REGISTER_TRACE(pOp->p1, pName);
|
||||
assert( pName->flags & MEM_Str );
|
||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||
@@ -5694,6 +5797,8 @@ case OP_VUpdate: {
|
||||
apArg = p->apArg;
|
||||
pX = &aMem[pOp->p3];
|
||||
for(i=0; i<nArg; i++){
|
||||
assert( memIsValid(pX) );
|
||||
memAboutToChange(p, pX);
|
||||
sqlite3VdbeMemStoreType(pX);
|
||||
apArg[i] = pX;
|
||||
pX++;
|
||||
|
||||
+18
-2
@@ -57,6 +57,7 @@ struct VdbeCursor {
|
||||
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
Bool isTable; /* True if a table requiring integer keys */
|
||||
Bool isIndex; /* True if an index containing keys only - no data */
|
||||
Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
int pseudoTableReg; /* Register holding pseudotable content. */
|
||||
@@ -151,6 +152,10 @@ struct Mem {
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
|
||||
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
||||
#ifdef SQLITE_DEBUG
|
||||
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
|
||||
void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
|
||||
#endif
|
||||
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
|
||||
char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
|
||||
};
|
||||
@@ -177,6 +182,7 @@ struct Mem {
|
||||
#define MEM_Blob 0x0010 /* Value is a BLOB */
|
||||
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
|
||||
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
|
||||
#define MEM_Invalid 0x0080 /* Value is undefined */
|
||||
#define MEM_TypeMask 0x00ff /* Mask of type bits */
|
||||
|
||||
/* Whenever Mem contains a valid string or blob representation, one of
|
||||
@@ -190,19 +196,25 @@ struct Mem {
|
||||
#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
|
||||
#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */
|
||||
#define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */
|
||||
|
||||
#ifdef SQLITE_OMIT_INCRBLOB
|
||||
#undef MEM_Zero
|
||||
#define MEM_Zero 0x0000
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Clear any existing type flags from a Mem and replace them with f
|
||||
*/
|
||||
#define MemSetTypeFlag(p, f) \
|
||||
((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
|
||||
|
||||
/*
|
||||
** Return true if a memory cell is not marked as invalid. This macro
|
||||
** is for use inside assert() statements only.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
|
||||
#endif
|
||||
|
||||
|
||||
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
|
||||
** additional information about auxiliary information bound to arguments
|
||||
@@ -391,6 +403,10 @@ void sqlite3VdbeFrameDelete(VdbeFrame*);
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *);
|
||||
void sqlite3VdbeMemStoreType(Mem *pMem);
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
int sqlite3VdbeCheckFk(Vdbe *, int);
|
||||
#else
|
||||
|
||||
+5
-7
@@ -1182,12 +1182,10 @@ int sqlite3VdbeList(
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem++;
|
||||
|
||||
if( p->explain==1 ){
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p3; /* P3 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem++;
|
||||
}
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p3; /* P3 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem++;
|
||||
|
||||
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
|
||||
assert( p->db->mallocFailed );
|
||||
@@ -1232,7 +1230,7 @@ int sqlite3VdbeList(
|
||||
}
|
||||
}
|
||||
|
||||
p->nResColumn = 8 - 5*(p->explain-1);
|
||||
p->nResColumn = 8 - 4*(p->explain-1);
|
||||
p->rc = SQLITE_OK;
|
||||
rc = SQLITE_ROW;
|
||||
}
|
||||
|
||||
@@ -132,6 +132,9 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
||||
pMem->z[pMem->n] = 0;
|
||||
pMem->z[pMem->n+1] = 0;
|
||||
pMem->flags |= MEM_Term;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pMem->pScopyFrom = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
@@ -593,6 +596,28 @@ int sqlite3VdbeMemTooBig(Mem *p){
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** This routine prepares a memory cell for modication by breaking
|
||||
** its link to a shallow copy and by marking any current shallow
|
||||
** copies of this cell as invalid.
|
||||
**
|
||||
** This is used for testing and debugging only - to make sure shallow
|
||||
** copies are not misused.
|
||||
*/
|
||||
void sqlite3VdbeMemPrepareToChange(Vdbe *pVdbe, Mem *pMem){
|
||||
int i;
|
||||
Mem *pX;
|
||||
for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
|
||||
if( pX->pScopyFrom==pMem ){
|
||||
pX->flags |= MEM_Invalid;
|
||||
pX->pScopyFrom = 0;
|
||||
}
|
||||
}
|
||||
pMem->pScopyFrom = 0;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Size of struct Mem not including the Mem.zMalloc member.
|
||||
*/
|
||||
@@ -1051,6 +1076,9 @@ int sqlite3ValueFromExpr(
|
||||
/* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
pVal->r = (double)-1 * pVal->r;
|
||||
}
|
||||
}else if( op==TK_NULL ){
|
||||
pVal = sqlite3ValueNew(db);
|
||||
if( pVal==0 ) goto no_mem;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||
else if( op==TK_BLOB ){
|
||||
|
||||
+885
-201
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -96,7 +96,7 @@ do_test analyze-1.11 {
|
||||
execsql {
|
||||
SELECT * FROM sqlite_stat1
|
||||
}
|
||||
} {}
|
||||
} {t1 {} 0}
|
||||
do_test analyze-1.12 {
|
||||
catchsql {
|
||||
ANALYZE t1;
|
||||
@@ -106,7 +106,7 @@ do_test analyze-1.13 {
|
||||
execsql {
|
||||
SELECT * FROM sqlite_stat1
|
||||
}
|
||||
} {}
|
||||
} {t1 {} 0}
|
||||
|
||||
# Create some indices that can be analyzed. But do not yet add
|
||||
# data. Without data in the tables, no analysis is done.
|
||||
@@ -117,21 +117,21 @@ do_test analyze-2.1 {
|
||||
ANALYZE main.t1;
|
||||
SELECT * FROM sqlite_stat1 ORDER BY idx;
|
||||
}
|
||||
} {}
|
||||
} {t1 {} 0}
|
||||
do_test analyze-2.2 {
|
||||
execsql {
|
||||
CREATE INDEX t1i2 ON t1(b);
|
||||
ANALYZE t1;
|
||||
SELECT * FROM sqlite_stat1 ORDER BY idx;
|
||||
}
|
||||
} {}
|
||||
} {t1 {} 0}
|
||||
do_test analyze-2.3 {
|
||||
execsql {
|
||||
CREATE INDEX t1i3 ON t1(a,b);
|
||||
ANALYZE main;
|
||||
SELECT * FROM sqlite_stat1 ORDER BY idx;
|
||||
}
|
||||
} {}
|
||||
} {t1 {} 0}
|
||||
|
||||
# Start adding data to the table. Verify that the analysis
|
||||
# is done correctly.
|
||||
|
||||
+123
-79
@@ -22,6 +22,8 @@ ifcapable !stat2 {
|
||||
return
|
||||
}
|
||||
|
||||
set testprefix analyze2
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
@@ -119,36 +121,56 @@ do_test analyze2-2.1 {
|
||||
execsql COMMIT
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_test analyze2-2.2 {
|
||||
eqp "SELECT * FROM t1 WHERE x>500 AND y>700"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-2.3 {
|
||||
eqp "SELECT * FROM t1 WHERE x>700 AND y>500"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-2.3 {
|
||||
eqp "SELECT * FROM t1 WHERE y>700 AND x>500"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-2.4 {
|
||||
eqp "SELECT * FROM t1 WHERE y>500 AND x>700"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-2.5 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 200 AND y BETWEEN 400 AND 700"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-2.6 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 400 AND 700"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-2.7 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN -400 AND -300 AND y BETWEEN 100 AND 300"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-2.8 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN -400 AND -300"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-2.9 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 500 AND 100 AND y BETWEEN 100 AND 300"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-2.10 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN 500 AND 100"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_eqp_test analyze2-2.2 {
|
||||
SELECT * FROM t1 WHERE x>500 AND y>700
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~100 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.3 {
|
||||
SELECT * FROM t1 WHERE x>700 AND y>500
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>?) (~100 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.3 {
|
||||
SELECT * FROM t1 WHERE y>700 AND x>500
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~100 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.4 {
|
||||
SELECT * FROM t1 WHERE y>500 AND x>700
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>?) (~100 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.5 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN 100 AND 200 AND y BETWEEN 400 AND 700
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~25 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.6 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 400 AND 700
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~75 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.7 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN -400 AND -300 AND y BETWEEN 100 AND 300
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~12 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.8 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN -400 AND -300
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~12 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.9 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN 500 AND 100 AND y BETWEEN 100 AND 300
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~12 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-2.10 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN 500 AND 100
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~12 rows)}
|
||||
}
|
||||
|
||||
do_test analyze2-3.1 {
|
||||
set alphabet [list a b c d e f g h i j]
|
||||
@@ -177,21 +199,31 @@ do_test analyze2-3.2 {
|
||||
}
|
||||
} {t1 t1_y {100 299 499 699 899 ajj cjj ejj gjj ijj}}
|
||||
|
||||
do_test analyze2-3.3 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 'a' AND 'b'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-3.4 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 400 AND y BETWEEN 'a' AND 'h'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-3.5 {
|
||||
eqp "SELECT * FROM t1 WHERE x<'a' AND y>'h'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-3.6 {
|
||||
eqp "SELECT * FROM t1 WHERE x<444 AND y>'h'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-3.7 {
|
||||
eqp "SELECT * FROM t1 WHERE x<221 AND y>'g'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_eqp_test analyze2-3.3 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 'a' AND 'b'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~50 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-3.4 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN 100 AND 400 AND y BETWEEN 'a' AND 'h'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~100 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-3.5 {
|
||||
SELECT * FROM t1 WHERE x<'a' AND y>'h'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~66 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-3.6 {
|
||||
SELECT * FROM t1 WHERE x<444 AND y>'h'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~66 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-3.7 {
|
||||
SELECT * FROM t1 WHERE x<221 AND y>'g'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x<?) (~66 rows)}
|
||||
}
|
||||
|
||||
do_test analyze2-4.1 {
|
||||
execsql { CREATE TABLE t3(a COLLATE nocase, b) }
|
||||
@@ -210,10 +242,12 @@ do_test analyze2-4.1 {
|
||||
} {}
|
||||
do_test analyze2-4.2 {
|
||||
execsql {
|
||||
PRAGMA automatic_index=OFF;
|
||||
SELECT tbl,idx,group_concat(sample,' ')
|
||||
FROM sqlite_stat2
|
||||
WHERE idx = 't3a'
|
||||
GROUP BY tbl,idx
|
||||
GROUP BY tbl,idx;
|
||||
PRAGMA automatic_index=ON;
|
||||
}
|
||||
} {t3 t3a {AfA bEj CEj dEj EEj fEj GEj hEj IEj jEj}}
|
||||
do_test analyze2-4.3 {
|
||||
@@ -225,12 +259,16 @@ do_test analyze2-4.3 {
|
||||
}
|
||||
} {t3 t3b {AbA CIj EIj GIj IIj bIj dIj fIj hIj jIj}}
|
||||
|
||||
do_test analyze2-4.4 {
|
||||
eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'C' AND b > 'A' AND b < 'C'"
|
||||
} {0 0 {TABLE t3 WITH INDEX t3b}}
|
||||
do_test analyze2-4.5 {
|
||||
eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'c' AND b > 'A' AND b < 'c'"
|
||||
} {0 0 {TABLE t3 WITH INDEX t3a}}
|
||||
do_eqp_test analyze2-4.4 {
|
||||
SELECT * FROM t3 WHERE a > 'A' AND a < 'C' AND b > 'A' AND b < 'C'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t3 USING INDEX t3b (b>? AND b<?) (~11 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-4.5 {
|
||||
SELECT * FROM t3 WHERE a > 'A' AND a < 'c' AND b > 'A' AND b < 'c'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t3 USING INDEX t3a (a>? AND a<?) (~22 rows)}
|
||||
}
|
||||
|
||||
ifcapable utf16 {
|
||||
proc test_collate {enc lhs rhs} {
|
||||
@@ -260,15 +298,21 @@ ifcapable utf16 {
|
||||
GROUP BY tbl,idx
|
||||
}
|
||||
} {t4 t4x {afa bej cej dej eej fej gej hej iej jej}}
|
||||
do_test analyze2-5.3 {
|
||||
eqp "SELECT * FROM t4 WHERE x>'ccc'"
|
||||
} {0 0 {TABLE t4 WITH INDEX t4x}}
|
||||
do_test analyze2-5.4 {
|
||||
eqp "SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ccc' AND t42.x>'ggg'"
|
||||
} {0 1 {TABLE t4 AS t42 WITH INDEX t4x} 1 0 {TABLE t4 AS t41 WITH INDEX t4x}}
|
||||
do_test analyze2-5.5 {
|
||||
eqp "SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'"
|
||||
} {0 0 {TABLE t4 AS t41 WITH INDEX t4x} 1 1 {TABLE t4 AS t42 WITH INDEX t4x}}
|
||||
do_eqp_test analyze2-5.3 {
|
||||
SELECT * FROM t4 WHERE x>'ccc'
|
||||
} {0 0 0 {SEARCH TABLE t4 USING COVERING INDEX t4x (x>?) (~800 rows)}}
|
||||
do_eqp_test analyze2-5.4 {
|
||||
SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ccc' AND t42.x>'ggg'
|
||||
} {
|
||||
0 0 1 {SEARCH TABLE t4 AS t42 USING COVERING INDEX t4x (x>?) (~300 rows)}
|
||||
0 1 0 {SEARCH TABLE t4 AS t41 USING COVERING INDEX t4x (x>?) (~800 rows)}
|
||||
}
|
||||
do_eqp_test analyze2-5.5 {
|
||||
SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t4 AS t41 USING COVERING INDEX t4x (x>?) (~700 rows)}
|
||||
0 1 1 {SEARCH TABLE t4 AS t42 USING COVERING INDEX t4x (x>?) (~800 rows)}
|
||||
}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
@@ -306,7 +350,7 @@ do_test analyze2-6.1.1 {
|
||||
t5.a = 1 AND
|
||||
t6.a = 1 AND t6.b = 1
|
||||
}
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a=? AND b=?) (~9 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.1.2 {
|
||||
db cache flush
|
||||
execsql ANALYZE
|
||||
@@ -314,14 +358,14 @@ do_test analyze2-6.1.2 {
|
||||
t5.a = 1 AND
|
||||
t6.a = 1 AND t6.b = 1
|
||||
}
|
||||
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.1.3 {
|
||||
sqlite3 db test.db
|
||||
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
|
||||
t5.a = 1 AND
|
||||
t6.a = 1 AND t6.b = 1
|
||||
}
|
||||
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.1.4 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
@@ -332,7 +376,7 @@ do_test analyze2-6.1.4 {
|
||||
t5.a = 1 AND
|
||||
t6.a = 1 AND t6.b = 1
|
||||
}
|
||||
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.1.5 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
@@ -343,7 +387,7 @@ do_test analyze2-6.1.5 {
|
||||
t5.a = 1 AND
|
||||
t6.a = 1 AND t6.b = 1
|
||||
}
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a=? AND b=?) (~9 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.1.6 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
@@ -354,7 +398,7 @@ do_test analyze2-6.1.6 {
|
||||
t5.a = 1 AND
|
||||
t6.a = 1 AND t6.b = 1
|
||||
}
|
||||
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
|
||||
do_test analyze2-6.2.1 {
|
||||
execsql {
|
||||
@@ -366,7 +410,7 @@ do_test analyze2-6.2.1 {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
}
|
||||
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.2.2 {
|
||||
db cache flush
|
||||
execsql ANALYZE
|
||||
@@ -374,14 +418,14 @@ do_test analyze2-6.2.2 {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
}
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.2.3 {
|
||||
sqlite3 db test.db
|
||||
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
}
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.2.4 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
@@ -392,7 +436,7 @@ do_test analyze2-6.2.4 {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
}
|
||||
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.2.5 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
@@ -403,7 +447,7 @@ do_test analyze2-6.2.5 {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
}
|
||||
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-6.2.6 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
@@ -415,7 +459,7 @@ do_test analyze2-6.2.6 {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
}
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# These tests, analyze2-7.*, test that the sqlite_stat2 functionality
|
||||
@@ -459,7 +503,7 @@ ifcapable shared_cache {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
} db1
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-7.6 {
|
||||
incr_schema_cookie test.db
|
||||
execsql { SELECT * FROM sqlite_master } db2
|
||||
@@ -467,7 +511,7 @@ ifcapable shared_cache {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
} db2
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-7.7 {
|
||||
incr_schema_cookie test.db
|
||||
execsql { SELECT * FROM sqlite_master } db1
|
||||
@@ -475,7 +519,7 @@ ifcapable shared_cache {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
} db1
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
|
||||
do_test analyze2-7.8 {
|
||||
execsql { DELETE FROM sqlite_stat2 } db2
|
||||
@@ -484,14 +528,14 @@ ifcapable shared_cache {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
} db1
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test analyze2-7.9 {
|
||||
execsql { SELECT * FROM sqlite_master } db2
|
||||
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
} db2
|
||||
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
|
||||
do_test analyze2-7.10 {
|
||||
incr_schema_cookie test.db
|
||||
@@ -500,7 +544,7 @@ ifcapable shared_cache {
|
||||
t5.a>1 AND t5.a<15 AND
|
||||
t6.a>1
|
||||
} db1
|
||||
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
|
||||
db1 close
|
||||
db2 close
|
||||
|
||||
+24
-24
@@ -95,12 +95,12 @@ do_test analyze3-1.1.1 {
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test analyze3-1.1.2 {
|
||||
eqp { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test analyze3-1.1.3 {
|
||||
eqp { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 }
|
||||
} {0 0 {TABLE t1}}
|
||||
do_eqp_test analyze3-1.1.2 {
|
||||
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?) (~100 rows)}}
|
||||
do_eqp_test analyze3-1.1.3 {
|
||||
SELECT sum(y) FROM t1 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SCAN TABLE t1 (~111 rows)}}
|
||||
|
||||
do_test analyze3-1.1.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 }
|
||||
@@ -144,12 +144,12 @@ do_test analyze3-1.2.1 {
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
do_test analyze3-1.2.2 {
|
||||
eqp { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 }
|
||||
} {0 0 {TABLE t2 WITH INDEX i2}}
|
||||
do_test analyze3-1.2.3 {
|
||||
eqp { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 }
|
||||
} {0 0 {TABLE t2}}
|
||||
do_eqp_test analyze3-1.2.2 {
|
||||
SELECT sum(y) FROM t2 WHERE x>1 AND x<2
|
||||
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?) (~200 rows)}}
|
||||
do_eqp_test analyze3-1.2.3 {
|
||||
SELECT sum(y) FROM t2 WHERE x>0 AND x<99
|
||||
} {0 0 0 {SCAN TABLE t2 (~111 rows)}}
|
||||
do_test analyze3-1.2.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 }
|
||||
} {161 0 4760}
|
||||
@@ -191,12 +191,12 @@ do_test analyze3-1.3.1 {
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
do_test analyze3-1.3.2 {
|
||||
eqp { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 }
|
||||
} {0 0 {TABLE t3 WITH INDEX i3}}
|
||||
do_test analyze3-1.3.3 {
|
||||
eqp { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 }
|
||||
} {0 0 {TABLE t3}}
|
||||
do_eqp_test analyze3-1.3.2 {
|
||||
SELECT sum(y) FROM t3 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?) (~100 rows)}}
|
||||
do_eqp_test analyze3-1.3.3 {
|
||||
SELECT sum(y) FROM t3 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SCAN TABLE t3 (~111 rows)}}
|
||||
|
||||
do_test analyze3-1.3.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 }
|
||||
@@ -246,12 +246,12 @@ do_test analyze3-2.1 {
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
do_test analyze3-2.2 {
|
||||
eqp { SELECT count(a) FROM t1 WHERE b LIKE 'a%' }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test analyze3-2.3 {
|
||||
eqp { SELECT count(a) FROM t1 WHERE b LIKE '%a' }
|
||||
} {0 0 {TABLE t1}}
|
||||
do_eqp_test analyze3-2.2 {
|
||||
SELECT count(a) FROM t1 WHERE b LIKE 'a%'
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?) (~30000 rows)}}
|
||||
do_eqp_test analyze3-2.3 {
|
||||
SELECT count(a) FROM t1 WHERE b LIKE '%a'
|
||||
} {0 0 0 {SCAN TABLE t1 (~500000 rows)}}
|
||||
|
||||
do_test analyze3-2.4 {
|
||||
sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE 'a%' }
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
# 2011 January 19
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements tests for SQLite library. The focus of the tests
|
||||
# in this file is the use of the sqlite_stat2 histogram data on tables
|
||||
# with many repeated values and only a few distinct values.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat2 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set testprefix analyze5
|
||||
|
||||
proc eqp {sql {db db}} {
|
||||
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
|
||||
}
|
||||
|
||||
unset -nocomplain i t u v w x y z
|
||||
do_test analyze5-1.0 {
|
||||
db eval {CREATE TABLE t1(t,u,v TEXT COLLATE nocase,w,x,y,z)}
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
set y [expr {$i>=25 && $i<=50}]
|
||||
set z [expr {($i>=400) + ($i>=700) + ($i>=875)}]
|
||||
set x $z
|
||||
set w $z
|
||||
set t [expr {$z+0.5}]
|
||||
switch $z {
|
||||
0 {set u "alpha"; unset x}
|
||||
1 {set u "bravo"}
|
||||
2 {set u "charlie"}
|
||||
3 {set u "delta"; unset w}
|
||||
}
|
||||
if {$i%2} {set v $u} {set v [string toupper $u]}
|
||||
db eval {INSERT INTO t1 VALUES($t,$u,$v,$w,$x,$y,$z)}
|
||||
}
|
||||
db eval {
|
||||
CREATE INDEX t1t ON t1(t); -- 0.5, 1.5, 2.5, and 3.5
|
||||
CREATE INDEX t1u ON t1(u); -- text
|
||||
CREATE INDEX t1v ON t1(v); -- mixed case text
|
||||
CREATE INDEX t1w ON t1(w); -- integers 0, 1, 2 and a few NULLs
|
||||
CREATE INDEX t1x ON t1(x); -- integers 1, 2, 3 and many NULLs
|
||||
CREATE INDEX t1y ON t1(y); -- integers 0 and very few 1s
|
||||
CREATE INDEX t1z ON t1(z); -- integers 0, 1, 2, and 3
|
||||
ANALYZE;
|
||||
SELECT sample FROM sqlite_stat2 WHERE idx='t1u' ORDER BY sampleno;
|
||||
}
|
||||
} {alpha alpha alpha alpha bravo bravo bravo charlie charlie delta}
|
||||
do_test analyze5-1.1 {
|
||||
string tolower \
|
||||
[db eval {SELECT sample from sqlite_stat2 WHERE idx='t1v' ORDER BY sampleno}]
|
||||
} {alpha alpha alpha alpha bravo bravo bravo charlie charlie delta}
|
||||
do_test analyze5-1.2 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1w' ORDER BY sampleno}
|
||||
} {{} 0 0 0 0 1 1 1 2 2}
|
||||
do_test analyze5-1.3 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1x' ORDER BY sampleno}
|
||||
} {{} {} {} {} 1 1 1 2 2 3}
|
||||
do_test analyze5-1.4 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1y' ORDER BY sampleno}
|
||||
} {0 0 0 0 0 0 0 0 0 0}
|
||||
do_test analyze5-1.5 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1z' ORDER BY sampleno}
|
||||
} {0 0 0 0 1 1 1 2 2 3}
|
||||
do_test analyze5-1.6 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1t' ORDER BY sampleno}
|
||||
} {0.5 0.5 0.5 0.5 1.5 1.5 1.5 2.5 2.5 3.5}
|
||||
|
||||
|
||||
# Verify that range queries generate the correct row count estimates
|
||||
#
|
||||
foreach {testid where index rows} {
|
||||
1 {z>=0 AND z<=0} t1z 400
|
||||
2 {z>=1 AND z<=1} t1z 300
|
||||
3 {z>=2 AND z<=2} t1z 200
|
||||
4 {z>=3 AND z<=3} t1z 100
|
||||
5 {z>=4 AND z<=4} t1z 50
|
||||
6 {z>=-1 AND z<=-1} t1z 50
|
||||
7 {z>1 AND z<3} t1z 200
|
||||
8 {z>0 AND z<100} t1z 600
|
||||
9 {z>=1 AND z<100} t1z 600
|
||||
10 {z>1 AND z<100} t1z 300
|
||||
11 {z>=2 AND z<100} t1z 300
|
||||
12 {z>2 AND z<100} t1z 100
|
||||
13 {z>=3 AND z<100} t1z 100
|
||||
14 {z>3 AND z<100} t1z 50
|
||||
15 {z>=4 AND z<100} t1z 50
|
||||
16 {z>=-100 AND z<=-1} t1z 50
|
||||
17 {z>=-100 AND z<=0} t1z 400
|
||||
18 {z>=-100 AND z<0} t1z 50
|
||||
19 {z>=-100 AND z<=1} t1z 700
|
||||
20 {z>=-100 AND z<2} t1z 700
|
||||
21 {z>=-100 AND z<=2} t1z 900
|
||||
22 {z>=-100 AND z<3} t1z 900
|
||||
|
||||
31 {z>=0.0 AND z<=0.0} t1z 400
|
||||
32 {z>=1.0 AND z<=1.0} t1z 300
|
||||
33 {z>=2.0 AND z<=2.0} t1z 200
|
||||
34 {z>=3.0 AND z<=3.0} t1z 100
|
||||
35 {z>=4.0 AND z<=4.0} t1z 50
|
||||
36 {z>=-1.0 AND z<=-1.0} t1z 50
|
||||
37 {z>1.5 AND z<3.0} t1z 200
|
||||
38 {z>0.5 AND z<100} t1z 600
|
||||
39 {z>=1.0 AND z<100} t1z 600
|
||||
40 {z>1.5 AND z<100} t1z 300
|
||||
41 {z>=2.0 AND z<100} t1z 300
|
||||
42 {z>2.1 AND z<100} t1z 100
|
||||
43 {z>=3.0 AND z<100} t1z 100
|
||||
44 {z>3.2 AND z<100} t1z 50
|
||||
45 {z>=4.0 AND z<100} t1z 50
|
||||
46 {z>=-100 AND z<=-1.0} t1z 50
|
||||
47 {z>=-100 AND z<=0.0} t1z 400
|
||||
48 {z>=-100 AND z<0.0} t1z 50
|
||||
49 {z>=-100 AND z<=1.0} t1z 700
|
||||
50 {z>=-100 AND z<2.0} t1z 700
|
||||
51 {z>=-100 AND z<=2.0} t1z 900
|
||||
52 {z>=-100 AND z<3.0} t1z 900
|
||||
|
||||
101 {z=-1} t1z 50
|
||||
102 {z=0} t1z 400
|
||||
103 {z=1} t1z 300
|
||||
104 {z=2} t1z 200
|
||||
105 {z=3} t1z 100
|
||||
106 {z=4} t1z 50
|
||||
107 {z=-10.0} t1z 50
|
||||
108 {z=0.0} t1z 400
|
||||
109 {z=1.0} t1z 300
|
||||
110 {z=2.0} t1z 200
|
||||
111 {z=3.0} t1z 100
|
||||
112 {z=4.0} t1z 50
|
||||
113 {z=1.5} t1z 50
|
||||
114 {z=2.5} t1z 50
|
||||
|
||||
201 {z IN (-1)} t1z 50
|
||||
202 {z IN (0)} t1z 400
|
||||
203 {z IN (1)} t1z 300
|
||||
204 {z IN (2)} t1z 200
|
||||
205 {z IN (3)} t1z 100
|
||||
206 {z IN (4)} t1z 50
|
||||
207 {z IN (0.5)} t1z 50
|
||||
208 {z IN (0,1)} t1z 700
|
||||
209 {z IN (0,1,2)} t1z 900
|
||||
210 {z IN (0,1,2,3)} {} 100
|
||||
211 {z IN (0,1,2,3,4,5)} {} 100
|
||||
212 {z IN (1,2)} t1z 500
|
||||
213 {z IN (2,3)} t1z 300
|
||||
214 {z=3 OR z=2} t1z 300
|
||||
215 {z IN (-1,3)} t1z 150
|
||||
216 {z=-1 OR z=3} t1z 150
|
||||
|
||||
300 {y=0} {} 100
|
||||
301 {y=1} t1y 50
|
||||
302 {y=0.1} t1y 50
|
||||
|
||||
400 {x IS NULL} t1x 400
|
||||
|
||||
} {
|
||||
# Verify that the expected index is used with the expected row count
|
||||
do_test analyze5-1.${testid}a {
|
||||
set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3]
|
||||
set idx {}
|
||||
regexp {INDEX (t1.) } $x all idx
|
||||
regexp {~([0-9]+) rows} $x all nrow
|
||||
list $idx $nrow
|
||||
} [list $index $rows]
|
||||
|
||||
# Verify that the same result is achieved regardless of whether or not
|
||||
# the index is used
|
||||
do_test analyze5-1.${testid}b {
|
||||
set w2 [string map {y +y z +z} $where]
|
||||
set a1 [db eval "SELECT rowid FROM t1 NOT INDEXED WHERE $w2\
|
||||
ORDER BY +rowid"]
|
||||
set a2 [db eval "SELECT rowid FROM t1 WHERE $where ORDER BY +rowid"]
|
||||
if {$a1==$a2} {
|
||||
set res ok
|
||||
} else {
|
||||
set res "a1=\[$a1\] a2=\[$a2\]"
|
||||
}
|
||||
set res
|
||||
} {ok}
|
||||
}
|
||||
|
||||
# Increase the number of NULLs in column x
|
||||
#
|
||||
db eval {
|
||||
UPDATE t1 SET x=NULL;
|
||||
UPDATE t1 SET x=rowid
|
||||
WHERE rowid IN (SELECT rowid FROM t1 ORDER BY random() LIMIT 5);
|
||||
ANALYZE;
|
||||
}
|
||||
|
||||
# Verify that range queries generate the correct row count estimates
|
||||
#
|
||||
foreach {testid where index rows} {
|
||||
500 {x IS NULL AND u='charlie'} t1u 20
|
||||
501 {x=1 AND u='charlie'} t1x 5
|
||||
502 {x IS NULL} {} 100
|
||||
503 {x=1} t1x 50
|
||||
504 {x IS NOT NULL} t1x 25
|
||||
505 {+x IS NOT NULL} {} 500
|
||||
506 {upper(x) IS NOT NULL} {} 500
|
||||
|
||||
} {
|
||||
# Verify that the expected index is used with the expected row count
|
||||
do_test analyze5-1.${testid}a {
|
||||
set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3]
|
||||
set idx {}
|
||||
regexp {INDEX (t1.) } $x all idx
|
||||
regexp {~([0-9]+) rows} $x all nrow
|
||||
list $idx $nrow
|
||||
} [list $index $rows]
|
||||
|
||||
# Verify that the same result is achieved regardless of whether or not
|
||||
# the index is used
|
||||
do_test analyze5-1.${testid}b {
|
||||
set w2 [string map {y +y z +z} $where]
|
||||
set a1 [db eval "SELECT rowid FROM t1 NOT INDEXED WHERE $w2\
|
||||
ORDER BY +rowid"]
|
||||
set a2 [db eval "SELECT rowid FROM t1 WHERE $where ORDER BY +rowid"]
|
||||
if {$a1==$a2} {
|
||||
set res ok
|
||||
} else {
|
||||
set res "a1=\[$a1\] a2=\[$a2\]"
|
||||
}
|
||||
set res
|
||||
} {ok}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,74 @@
|
||||
# 2011 March 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements tests for SQLite library. The focus of the tests
|
||||
# in this file a corner-case query planner optimization involving the
|
||||
# join order of two tables of different sizes.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat2 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set testprefix analyze6
|
||||
|
||||
proc eqp {sql {db db}} {
|
||||
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
|
||||
}
|
||||
|
||||
do_test analyze6-1.0 {
|
||||
db eval {
|
||||
CREATE TABLE cat(x INT);
|
||||
CREATE UNIQUE INDEX catx ON cat(x);
|
||||
/* Give cat 16 unique integers */
|
||||
INSERT INTO cat VALUES(1);
|
||||
INSERT INTO cat VALUES(2);
|
||||
INSERT INTO cat SELECT x+2 FROM cat;
|
||||
INSERT INTO cat SELECT x+4 FROM cat;
|
||||
INSERT INTO cat SELECT x+8 FROM cat;
|
||||
|
||||
CREATE TABLE ev(y INT);
|
||||
CREATE INDEX evy ON ev(y);
|
||||
/* ev will hold 32 copies of 16 integers found in cat */
|
||||
INSERT INTO ev SELECT x FROM cat;
|
||||
INSERT INTO ev SELECT x FROM cat;
|
||||
INSERT INTO ev SELECT y FROM ev;
|
||||
INSERT INTO ev SELECT y FROM ev;
|
||||
INSERT INTO ev SELECT y FROM ev;
|
||||
INSERT INTO ev SELECT y FROM ev;
|
||||
ANALYZE;
|
||||
SELECT count(*) FROM cat;
|
||||
SELECT count(*) FROM ev;
|
||||
}
|
||||
} {16 512}
|
||||
|
||||
# The lowest cost plan is to scan CAT and for each integer there, do a single
|
||||
# lookup of the first corresponding entry in EV then read off the equal values
|
||||
# in EV. (Prior to the 2011-03-04 enhancement to where.c, this query would
|
||||
# have used EV for the outer loop instead of CAT - which was about 3x slower.)
|
||||
#
|
||||
do_test analyze6-1.1 {
|
||||
eqp {SELECT count(*) FROM ev, cat WHERE x=y}
|
||||
} {0 0 1 {SCAN TABLE cat (~16 rows)} 0 1 0 {SEARCH TABLE ev USING COVERING INDEX evy (y=?) (~32 rows)}}
|
||||
|
||||
# The same plan is chosen regardless of the order of the tables in the
|
||||
# FROM clause.
|
||||
#
|
||||
do_test analyze6-1.2 {
|
||||
eqp {SELECT count(*) FROM cat, ev WHERE x=y}
|
||||
} {0 0 0 {SCAN TABLE cat (~16 rows)} 0 1 1 {SEARCH TABLE ev USING COVERING INDEX evy (y=?) (~32 rows)}}
|
||||
|
||||
|
||||
finish_test
|
||||
+3
-3
@@ -1976,12 +1976,12 @@ ifcapable analyze {
|
||||
ANALYZE;
|
||||
}
|
||||
set ::authargs
|
||||
} {t4 {} main {}}
|
||||
} {t4 {} main {} t2 {} main {}}
|
||||
do_test auth-1.295 {
|
||||
execsql {
|
||||
SELECT count(*) FROM sqlite_stat1;
|
||||
}
|
||||
} 2
|
||||
} 3
|
||||
proc auth {code args} {
|
||||
if {$code=="SQLITE_ANALYZE"} {
|
||||
set ::authargs [concat $::authargs $args]
|
||||
@@ -1999,7 +1999,7 @@ ifcapable analyze {
|
||||
execsql {
|
||||
SELECT count(*) FROM sqlite_stat1;
|
||||
}
|
||||
} 2
|
||||
} 3
|
||||
} ;# ifcapable analyze
|
||||
|
||||
|
||||
|
||||
+12
-4
@@ -148,14 +148,14 @@ do_test autoindex1-500 {
|
||||
SELECT b FROM t501
|
||||
WHERE t501.a IN (SELECT x FROM t502 WHERE y=?);
|
||||
}
|
||||
} {0 0 {TABLE t501 USING PRIMARY KEY} 0 0 {TABLE t502}}
|
||||
} {0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) (~25 rows)} 0 0 0 {SCAN TABLE t502 (~100000 rows)}}
|
||||
do_test autoindex1-501 {
|
||||
db eval {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT b FROM t501
|
||||
WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b);
|
||||
}
|
||||
} {0 0 {TABLE t501} 0 0 {TABLE t502 WITH AUTOMATIC INDEX}}
|
||||
} {0 0 0 {SCAN TABLE t501 (~500000 rows)} 0 0 0 {SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?) (~7 rows)}}
|
||||
do_test autoindex1-502 {
|
||||
db eval {
|
||||
EXPLAIN QUERY PLAN
|
||||
@@ -163,7 +163,15 @@ do_test autoindex1-502 {
|
||||
WHERE t501.a=123
|
||||
AND t501.a IN (SELECT x FROM t502 WHERE y=t501.b);
|
||||
}
|
||||
} {0 0 {TABLE t501 USING PRIMARY KEY} 0 0 {TABLE t502}}
|
||||
|
||||
} {0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} 0 0 0 {SCAN TABLE t502 (~100000 rows)}}
|
||||
|
||||
|
||||
do_execsql_test autoindex1-700 {
|
||||
CREATE TABLE t5(a, b, c);
|
||||
EXPLAIN QUERY PLAN SELECT a FROM t5 WHERE b=10 ORDER BY c;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t5 (~100000 rows)}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+3
-3
@@ -57,17 +57,17 @@ do_test collate5-1.1 {
|
||||
execsql {
|
||||
SELECT DISTINCT a FROM collate5t1;
|
||||
}
|
||||
} {A B N}
|
||||
} {a b n}
|
||||
do_test collate5-1.2 {
|
||||
execsql {
|
||||
SELECT DISTINCT b FROM collate5t1;
|
||||
}
|
||||
} {{} Apple apple banana}
|
||||
} {apple Apple banana {}}
|
||||
do_test collate5-1.3 {
|
||||
execsql {
|
||||
SELECT DISTINCT a, b FROM collate5t1;
|
||||
}
|
||||
} {A Apple a apple B banana N {}}
|
||||
} {a apple A Apple b banana n {}}
|
||||
|
||||
# Ticket #3376
|
||||
#
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
# 2011 July 1
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is the DISTINCT modifier.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
set testprefix distinct
|
||||
|
||||
proc do_execsql_test {testname sql {result {}}} {
|
||||
uplevel do_test $testname [list "execsql {$sql}"] [list [list {*}$result]]
|
||||
}
|
||||
|
||||
|
||||
proc is_distinct_noop {sql} {
|
||||
set sql1 $sql
|
||||
set sql2 [string map {DISTINCT ""} $sql]
|
||||
|
||||
set program1 [list]
|
||||
set program2 [list]
|
||||
db eval "EXPLAIN $sql1" {
|
||||
if {$opcode != "Noop"} { lappend program1 $opcode }
|
||||
}
|
||||
db eval "EXPLAIN $sql2" {
|
||||
if {$opcode != "Noop"} { lappend program2 $opcode }
|
||||
}
|
||||
|
||||
return [expr {$program1==$program2}]
|
||||
}
|
||||
|
||||
proc do_distinct_noop_test {tn sql} {
|
||||
uplevel [list do_test $tn [list is_distinct_noop $sql] 1]
|
||||
}
|
||||
proc do_distinct_not_noop_test {tn sql} {
|
||||
uplevel [list do_test $tn [list is_distinct_noop $sql] 0]
|
||||
}
|
||||
|
||||
proc do_temptables_test {tn sql temptables} {
|
||||
uplevel [list do_test $tn [subst -novar {
|
||||
set ret ""
|
||||
db eval "EXPLAIN [set sql]" {
|
||||
if {$opcode == "OpenEphemeral"} {
|
||||
if {$p5 != "10" && $p5!="00"} { error "p5 = $p5" }
|
||||
if {$p5 == "10"} {
|
||||
lappend ret hash
|
||||
} else {
|
||||
lappend ret btree
|
||||
}
|
||||
}
|
||||
}
|
||||
set ret
|
||||
}] $temptables]
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - distinct-1.* - check that the planner correctly
|
||||
# detects cases where a UNIQUE index means that a DISTINCT clause is
|
||||
# redundant. Currently the planner only detects such cases when there
|
||||
# is a single table in the FROM clause.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c, d);
|
||||
CREATE UNIQUE INDEX i1 ON t1(b, c);
|
||||
CREATE UNIQUE INDEX i2 ON t1(d COLLATE nocase);
|
||||
|
||||
CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
|
||||
|
||||
CREATE TABLE t3(c1 PRIMARY KEY, c2);
|
||||
CREATE INDEX i3 ON t3(c2);
|
||||
}
|
||||
foreach {tn noop sql} {
|
||||
|
||||
1 1 "SELECT DISTINCT b, c FROM t1"
|
||||
2 1 "SELECT DISTINCT c FROM t1 WHERE b = ?"
|
||||
3 1 "SELECT DISTINCT rowid FROM t1"
|
||||
4 1 "SELECT DISTINCT rowid, a FROM t1"
|
||||
5 1 "SELECT DISTINCT x FROM t2"
|
||||
6 1 "SELECT DISTINCT * FROM t2"
|
||||
7 1 "SELECT DISTINCT * FROM (SELECT * FROM t2)"
|
||||
|
||||
8 1 "SELECT DISTINCT * FROM t1"
|
||||
|
||||
8 0 "SELECT DISTINCT a, b FROM t1"
|
||||
|
||||
9 0 "SELECT DISTINCT c FROM t1 WHERE b IN (1,2)"
|
||||
10 0 "SELECT DISTINCT c FROM t1"
|
||||
11 0 "SELECT DISTINCT b FROM t1"
|
||||
|
||||
12 0 "SELECT DISTINCT a, d FROM t1"
|
||||
13 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t1"
|
||||
14 1 "SELECT DISTINCT a, d COLLATE nocase FROM t1"
|
||||
15 0 "SELECT DISTINCT a, d COLLATE binary FROM t1"
|
||||
16 1 "SELECT DISTINCT a, b, c COLLATE binary FROM t1"
|
||||
|
||||
16 0 "SELECT DISTINCT t1.rowid FROM t1, t2"
|
||||
17 0 { /* Technically, it would be possible to detect that DISTINCT
|
||||
** is a no-op in cases like the following. But SQLite does not
|
||||
** do so. */
|
||||
SELECT DISTINCT t1.rowid FROM t1, t2 WHERE t1.rowid=t2.rowid }
|
||||
|
||||
18 1 "SELECT DISTINCT c1, c2 FROM t3"
|
||||
19 1 "SELECT DISTINCT c1 FROM t3"
|
||||
20 1 "SELECT DISTINCT * FROM t3"
|
||||
21 0 "SELECT DISTINCT c2 FROM t3"
|
||||
|
||||
22 0 "SELECT DISTINCT * FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
|
||||
23 1 "SELECT DISTINCT rowid FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
|
||||
|
||||
24 0 "SELECT DISTINCT rowid/2 FROM t1"
|
||||
25 1 "SELECT DISTINCT rowid/2, rowid FROM t1"
|
||||
26 1 "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?"
|
||||
} {
|
||||
if {$noop} {
|
||||
do_distinct_noop_test 1.$tn $sql
|
||||
} else {
|
||||
do_distinct_not_noop_test 1.$tn $sql
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - distinct-2.* - test cases where an index is
|
||||
# used to deliver results in order of the DISTINCT expressions.
|
||||
#
|
||||
drop_all_tables
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
CREATE INDEX i2 ON t1(b COLLATE nocase, c COLLATE nocase);
|
||||
|
||||
INSERT INTO t1 VALUES('a', 'b', 'c');
|
||||
INSERT INTO t1 VALUES('A', 'B', 'C');
|
||||
INSERT INTO t1 VALUES('a', 'b', 'c');
|
||||
INSERT INTO t1 VALUES('A', 'B', 'C');
|
||||
}
|
||||
|
||||
foreach {tn sql temptables res} {
|
||||
1 "a, b FROM t1" {} {A B a b}
|
||||
2 "b, a FROM t1" {} {B A b a}
|
||||
3 "a, b, c FROM t1" {hash} {a b c A B C}
|
||||
4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
|
||||
5 "b FROM t1 WHERE a = 'a'" {} {b}
|
||||
6 "b FROM t1" {hash} {b B}
|
||||
7 "a FROM t1" {} {A a}
|
||||
8 "b COLLATE nocase FROM t1" {} {b}
|
||||
9 "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {} {B}
|
||||
} {
|
||||
do_execsql_test 2.$tn.1 "SELECT DISTINCT $sql" $res
|
||||
do_temptables_test 2.$tn.2 "SELECT DISTINCT $sql" $temptables
|
||||
}
|
||||
|
||||
do_execsql_test 2.A {
|
||||
SELECT (SELECT DISTINCT o.a FROM t1 AS i) FROM t1 AS o;
|
||||
} {a A a A}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
+7
-7
@@ -974,13 +974,13 @@ do_test e_fkey-25.2 {
|
||||
EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1;
|
||||
EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?;
|
||||
}
|
||||
} {0 0 {TABLE artist} 0 0 {TABLE track}}
|
||||
} {0 0 0 {SCAN TABLE artist (~1000000 rows)} 0 0 0 {SCAN TABLE track (~100000 rows)}}
|
||||
do_test e_fkey-25.3 {
|
||||
execsql {
|
||||
PRAGMA foreign_keys = ON;
|
||||
EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1;
|
||||
}
|
||||
} {0 0 {TABLE artist} 0 0 {TABLE track}}
|
||||
} {0 0 0 {SCAN TABLE artist (~1000000 rows)} 0 0 0 {SCAN TABLE track (~100000 rows)}}
|
||||
do_test e_fkey-25.4 {
|
||||
execsql {
|
||||
INSERT INTO artist VALUES(5, 'artist 5');
|
||||
@@ -1096,15 +1096,15 @@ do_test e_fkey-27.2 {
|
||||
do_test e_fkey-27.3 {
|
||||
eqp { UPDATE artist SET artistid = ?, artistname = ? }
|
||||
} [list \
|
||||
0 0 {TABLE artist} \
|
||||
0 0 {TABLE track WITH INDEX trackindex} \
|
||||
0 0 {TABLE track WITH INDEX trackindex}
|
||||
0 0 0 {SCAN TABLE artist (~1000000 rows)} \
|
||||
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)} \
|
||||
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)}
|
||||
]
|
||||
do_test e_fkey-27.4 {
|
||||
eqp { DELETE FROM artist }
|
||||
} [list \
|
||||
0 0 {TABLE artist} \
|
||||
0 0 {TABLE track WITH INDEX trackindex}
|
||||
0 0 0 {SCAN TABLE artist (~1000000 rows)} \
|
||||
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)}
|
||||
]
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -116,6 +116,7 @@ do_test fts3query-4.1 {
|
||||
CREATE TABLE bt(title);
|
||||
}
|
||||
} {}
|
||||
if 0 {
|
||||
do_test fts3query-4.2 {
|
||||
eqp "SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date"
|
||||
} {0 0 {TABLE t1 WITH INDEX i1 ORDER BY} 1 1 {TABLE ft VIRTUAL TABLE INDEX 1:}}
|
||||
@@ -128,7 +129,6 @@ do_test fts3query-4.4 {
|
||||
do_test fts3query-4.5 {
|
||||
eqp "SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date"
|
||||
} {0 1 {TABLE t1 WITH INDEX i1 ORDER BY} 1 0 {TABLE bt USING PRIMARY KEY}}
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+1
-1
@@ -354,7 +354,7 @@ do_test index-11.1 {
|
||||
}
|
||||
set sqlite_search_count 0
|
||||
concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count
|
||||
} {0.1 3}
|
||||
} {0.1 2}
|
||||
integrity_check index-11.2
|
||||
|
||||
|
||||
|
||||
+88
-75
@@ -40,15 +40,18 @@ proc EQP {sql} {
|
||||
|
||||
# These tests are to check that "EXPLAIN QUERY PLAN" is working as expected.
|
||||
#
|
||||
do_test indexedby-1.2 {
|
||||
EQP { select * from t1 WHERE a = 10; }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-1.3 {
|
||||
EQP { select * from t1 ; }
|
||||
} {0 0 {TABLE t1}}
|
||||
do_test indexedby-1.4 {
|
||||
EQP { select * from t1, t2 WHERE c = 10; }
|
||||
} {0 1 {TABLE t2 WITH INDEX i3} 1 0 {TABLE t1}}
|
||||
do_execsql_test indexedby-1.2 {
|
||||
EXPLAIN QUERY PLAN select * from t1 WHERE a = 10;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)}}
|
||||
do_execsql_test indexedby-1.3 {
|
||||
EXPLAIN QUERY PLAN select * from t1 ;
|
||||
} {0 0 0 {SCAN TABLE t1 (~1000000 rows)}}
|
||||
do_execsql_test indexedby-1.4 {
|
||||
EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10;
|
||||
} {
|
||||
0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?) (~10 rows)}
|
||||
0 1 0 {SCAN TABLE t1 (~1000000 rows)}
|
||||
}
|
||||
|
||||
# Parser tests. Test that an INDEXED BY or NOT INDEX clause can be
|
||||
# attached to a table in the FROM clause, but not to a sub-select or
|
||||
@@ -80,15 +83,17 @@ do_test indexedby-2.7 {
|
||||
|
||||
# Tests for single table cases.
|
||||
#
|
||||
do_test indexedby-3.1 {
|
||||
EQP { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'}
|
||||
} {0 0 {TABLE t1}}
|
||||
do_test indexedby-3.2 {
|
||||
EQP { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'}
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-3.3 {
|
||||
EQP { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'}
|
||||
} {0 0 {TABLE t1 WITH INDEX i2}}
|
||||
do_execsql_test indexedby-3.1 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'
|
||||
} {0 0 0 {SCAN TABLE t1 (~10000 rows)}}
|
||||
do_execsql_test indexedby-3.2 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}}
|
||||
do_execsql_test indexedby-3.3 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}}
|
||||
do_test indexedby-3.4 {
|
||||
catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' }
|
||||
} {1 {cannot use index: i2}}
|
||||
@@ -102,12 +107,14 @@ do_test indexedby-3.7 {
|
||||
catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a }
|
||||
} {0 {}}
|
||||
|
||||
do_test indexedby-3.8 {
|
||||
EQP { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e }
|
||||
} {0 0 {TABLE t3 WITH INDEX sqlite_autoindex_t3_1 ORDER BY}}
|
||||
do_test indexedby-3.9 {
|
||||
EQP { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 }
|
||||
} {0 0 {TABLE t3 WITH INDEX sqlite_autoindex_t3_1}}
|
||||
do_execsql_test indexedby-3.8 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e
|
||||
} {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1 (~1000000 rows)}}
|
||||
do_execsql_test indexedby-3.9 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?) (~1 rows)}}
|
||||
do_test indexedby-3.10 {
|
||||
catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 }
|
||||
} {1 {cannot use index: sqlite_autoindex_t3_1}}
|
||||
@@ -117,12 +124,18 @@ do_test indexedby-3.11 {
|
||||
|
||||
# Tests for multiple table cases.
|
||||
#
|
||||
do_test indexedby-4.1 {
|
||||
EQP { SELECT * FROM t1, t2 WHERE a = c }
|
||||
} {0 0 {TABLE t1} 1 1 {TABLE t2 WITH INDEX i3}}
|
||||
do_test indexedby-4.2 {
|
||||
EQP { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c }
|
||||
} {0 1 {TABLE t2} 1 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_execsql_test indexedby-4.1 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 (~1000000 rows)}
|
||||
0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?) (~10 rows)}
|
||||
}
|
||||
do_execsql_test indexedby-4.2 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c
|
||||
} {
|
||||
0 0 1 {SCAN TABLE t2 (~1000000 rows)}
|
||||
0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)}
|
||||
}
|
||||
do_test indexedby-4.3 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
|
||||
@@ -138,15 +151,13 @@ do_test indexedby-4.4 {
|
||||
# also tests that nothing bad happens if an index refered to by
|
||||
# a CREATE VIEW statement is dropped and recreated.
|
||||
#
|
||||
do_test indexedby-5.1 {
|
||||
execsql {
|
||||
CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5;
|
||||
}
|
||||
EQP { SELECT * FROM v2 }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-5.2 {
|
||||
EQP { SELECT * FROM v2 WHERE b = 10 }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_execsql_test indexedby-5.1 {
|
||||
CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5;
|
||||
EXPLAIN QUERY PLAN SELECT * FROM v2
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~250000 rows)}}
|
||||
do_execsql_test indexedby-5.2 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~25000 rows)}}
|
||||
do_test indexedby-5.3 {
|
||||
execsql { DROP INDEX i1 }
|
||||
catchsql { SELECT * FROM v2 }
|
||||
@@ -165,51 +176,53 @@ do_test indexedby-5.5 {
|
||||
|
||||
# Test that "NOT INDEXED" may use the rowid index, but not others.
|
||||
#
|
||||
do_test indexedby-6.1 {
|
||||
EQP { SELECT * FROM t1 WHERE b = 10 ORDER BY rowid }
|
||||
} {0 0 {TABLE t1 WITH INDEX i2 ORDER BY}}
|
||||
do_test indexedby-6.2 {
|
||||
EQP { SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid }
|
||||
} {0 0 {TABLE t1 USING PRIMARY KEY ORDER BY}}
|
||||
do_execsql_test indexedby-6.1 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~10 rows)}}
|
||||
do_execsql_test indexedby-6.2 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid
|
||||
} {0 0 0 {SCAN TABLE t1 USING INTEGER PRIMARY KEY (~100000 rows)}}
|
||||
|
||||
# Test that "INDEXED BY" can be used in a DELETE statement.
|
||||
#
|
||||
do_test indexedby-7.1 {
|
||||
EQP { DELETE FROM t1 WHERE a = 5 }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-7.2 {
|
||||
EQP { DELETE FROM t1 NOT INDEXED WHERE a = 5 }
|
||||
} {0 0 {TABLE t1}}
|
||||
do_test indexedby-7.3 {
|
||||
EQP { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-7.4 {
|
||||
EQP { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10}
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-7.5 {
|
||||
EQP { DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10}
|
||||
} {0 0 {TABLE t1 WITH INDEX i2}}
|
||||
do_execsql_test indexedby-7.1 {
|
||||
EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5
|
||||
} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}}
|
||||
do_execsql_test indexedby-7.2 {
|
||||
EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5
|
||||
} {0 0 0 {SCAN TABLE t1 (~100000 rows)}}
|
||||
do_execsql_test indexedby-7.3 {
|
||||
EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5
|
||||
} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}}
|
||||
do_execsql_test indexedby-7.4 {
|
||||
EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}}
|
||||
do_execsql_test indexedby-7.5 {
|
||||
EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}}
|
||||
do_test indexedby-7.6 {
|
||||
catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5}
|
||||
} {1 {cannot use index: i2}}
|
||||
|
||||
# Test that "INDEXED BY" can be used in an UPDATE statement.
|
||||
#
|
||||
do_test indexedby-8.1 {
|
||||
EQP { UPDATE t1 SET rowid=rowid+1 WHERE a = 5 }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-8.2 {
|
||||
EQP { UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 }
|
||||
} {0 0 {TABLE t1}}
|
||||
do_test indexedby-8.3 {
|
||||
EQP { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 }
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-8.4 {
|
||||
EQP { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10}
|
||||
} {0 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-8.5 {
|
||||
EQP { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10}
|
||||
} {0 0 {TABLE t1 WITH INDEX i2}}
|
||||
do_execsql_test indexedby-8.1 {
|
||||
EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5
|
||||
} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}}
|
||||
do_execsql_test indexedby-8.2 {
|
||||
EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5
|
||||
} {0 0 0 {SCAN TABLE t1 (~100000 rows)}}
|
||||
do_execsql_test indexedby-8.3 {
|
||||
EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5
|
||||
} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}}
|
||||
do_execsql_test indexedby-8.4 {
|
||||
EXPLAIN QUERY PLAN
|
||||
UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}}
|
||||
do_execsql_test indexedby-8.5 {
|
||||
EXPLAIN QUERY PLAN
|
||||
UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}}
|
||||
do_test indexedby-8.6 {
|
||||
catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5}
|
||||
} {1 {cannot use index: i2}}
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ do_test insert4-2.4.1 {
|
||||
INSERT INTO t3 SELECT DISTINCT * FROM t2;
|
||||
SELECT * FROM t3;
|
||||
}
|
||||
} {1 9 9 1}
|
||||
} {9 1 1 9}
|
||||
xferopt_test insert4-2.4.2 0
|
||||
do_test insert4-2.4.3 {
|
||||
catchsql {
|
||||
|
||||
@@ -52,6 +52,7 @@ do_test minmax3-1.0 {
|
||||
INSERT INTO t1 VALUES('2', 'V', 'five');
|
||||
INSERT INTO t1 VALUES('3', 'VI', 'six');
|
||||
COMMIT;
|
||||
PRAGMA automatic_index=OFF;
|
||||
}
|
||||
} {}
|
||||
do_test minmax3-1.1.1 {
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@ ifcapable subquery {
|
||||
|
||||
select a.*, x.*
|
||||
from a, (select key,sum(period) from b group by key) as x
|
||||
where a.key=x.key;
|
||||
where a.key=x.key order by 1 desc;
|
||||
}
|
||||
} {01 data01 01 3 +1 data+1 +1 7}
|
||||
|
||||
|
||||
+1
-1
@@ -505,7 +505,7 @@ ifcapable subquery {
|
||||
)
|
||||
ORDER BY LOWER(artist) ASC;
|
||||
}
|
||||
} {one}
|
||||
} {two}
|
||||
}
|
||||
|
||||
# Ticket #1370. Do not overwrite small files (less than 1024 bytes)
|
||||
|
||||
+8
-8
@@ -46,31 +46,31 @@ if {$tcl_platform(platform) != "symbian"} {
|
||||
sqlite3_bind_double $::STMT 1 +Inf
|
||||
sqlite3_step $::STMT
|
||||
sqlite3_reset $::STMT
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
string tolower [db eval {SELECT x, typeof(x) FROM t1}]
|
||||
} {{} null inf real}
|
||||
do_test nan-1.1.3 {
|
||||
sqlite3_bind_double $::STMT 1 -Inf
|
||||
sqlite3_step $::STMT
|
||||
sqlite3_reset $::STMT
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
string tolower [db eval {SELECT x, typeof(x) FROM t1}]
|
||||
} {{} null inf real -inf real}
|
||||
do_test nan-1.1.4 {
|
||||
sqlite3_bind_double $::STMT 1 -NaN
|
||||
sqlite3_step $::STMT
|
||||
sqlite3_reset $::STMT
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
string tolower [db eval {SELECT x, typeof(x) FROM t1}]
|
||||
} {{} null inf real -inf real {} null}
|
||||
do_test nan-1.1.5 {
|
||||
sqlite3_bind_double $::STMT 1 NaN0
|
||||
sqlite3_step $::STMT
|
||||
sqlite3_reset $::STMT
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
string tolower [db eval {SELECT x, typeof(x) FROM t1}]
|
||||
} {{} null inf real -inf real {} null {} null}
|
||||
do_test nan-1.1.6 {
|
||||
sqlite3_bind_double $::STMT 1 -NaN0
|
||||
sqlite3_step $::STMT
|
||||
sqlite3_reset $::STMT
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
string tolower [db eval {SELECT x, typeof(x) FROM t1}]
|
||||
} {{} null inf real -inf real {} null {} null {} null}
|
||||
do_test nan-1.1.7 {
|
||||
db eval {
|
||||
@@ -234,12 +234,12 @@ if {$tcl_platform(platform) != "symbian"} {
|
||||
do_test nan-4.7 {
|
||||
db eval {DELETE FROM t1}
|
||||
db eval "INSERT INTO t1 VALUES([string repeat 9 309].0)"
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
string tolower [db eval {SELECT x, typeof(x) FROM t1}]
|
||||
} {inf real}
|
||||
do_test nan-4.8 {
|
||||
db eval {DELETE FROM t1}
|
||||
db eval "INSERT INTO t1 VALUES(-[string repeat 9 309].0)"
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
string tolower [db eval {SELECT x, typeof(x) FROM t1}]
|
||||
} {-inf real}
|
||||
}
|
||||
do_test nan-4.9 {
|
||||
@@ -317,7 +317,7 @@ do_test nan-4.20 {
|
||||
db eval {DELETE FROM t1}
|
||||
set big [string repeat 9 10000].0e-9000
|
||||
db eval "INSERT INTO t1 VALUES($big)"
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
string tolower [db eval {SELECT x, typeof(x) FROM t1}]
|
||||
} {inf real}
|
||||
|
||||
|
||||
|
||||
@@ -458,6 +458,7 @@ do_test select6-8.6 {
|
||||
do_test select6-9.1 {
|
||||
execsql {
|
||||
SELECT a.x, b.x FROM t1 AS a, (SELECT x FROM t1 LIMIT 2) AS b
|
||||
ORDER BY 1, 2
|
||||
}
|
||||
} {1 1 1 2 2 1 2 2 3 1 3 2 4 1 4 2}
|
||||
do_test select6-9.2 {
|
||||
|
||||
+1
-1
@@ -355,7 +355,7 @@ for {set ii 3} {$ii <= 4} {incr ii} {
|
||||
SELECT DISTINCT (a/10) FROM t1 UNION ALL SELECT DISTINCT(d%2) FROM t2
|
||||
)
|
||||
}
|
||||
} {0 1 0 1}
|
||||
} {0 1 1 0}
|
||||
|
||||
do_test selectB-$ii.20 {
|
||||
execsql {
|
||||
|
||||
+9
-2
@@ -20,7 +20,7 @@
|
||||
# Commands to manipulate the db and the file-system at a high level:
|
||||
#
|
||||
# copy_file FROM TO
|
||||
# drop_all_table ?DB?
|
||||
# drop_all_tables ?DB?
|
||||
# forcedelete FILENAME
|
||||
#
|
||||
# Test the capability of the SQLite version built into the interpreter to
|
||||
@@ -333,11 +333,18 @@ proc do_test {name cmd expected} {
|
||||
}
|
||||
|
||||
proc do_execsql_test {testname sql result} {
|
||||
uplevel do_test $testname [list "execsql {$sql}"] [list $result]
|
||||
set r {}
|
||||
foreach x $result {lappend r $x}
|
||||
uplevel do_test $testname [list "execsql {$sql}"] [list $r]
|
||||
}
|
||||
proc do_catchsql_test {testname sql result} {
|
||||
uplevel do_test $testname [list "catchsql {$sql}"] [list $result]
|
||||
}
|
||||
proc do_eqp_test {name sql res} {
|
||||
set r {}
|
||||
foreach x $res {lappend r $x}
|
||||
uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $r]
|
||||
}
|
||||
|
||||
|
||||
# Run an SQL script.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# 2011 July 8
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing that bug [54844eea3f] has been fixed.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
set ::testprefix tkt-54844eea3f
|
||||
|
||||
do_test 1.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(4);
|
||||
|
||||
CREATE TABLE t2(b INTEGER PRIMARY KEY);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
INSERT INTO t2 VALUES(2);
|
||||
INSERT INTO t2 SELECT b+2 FROM t2;
|
||||
INSERT INTO t2 SELECT b+4 FROM t2;
|
||||
INSERT INTO t2 SELECT b+8 FROM t2;
|
||||
INSERT INTO t2 SELECT b+16 FROM t2;
|
||||
|
||||
CREATE TABLE t3(c INTEGER PRIMARY KEY);
|
||||
INSERT INTO t3 VALUES(1);
|
||||
INSERT INTO t3 VALUES(2);
|
||||
INSERT INTO t3 VALUES(3);
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test 1.1 {
|
||||
execsql {
|
||||
SELECT 'test-2', t3.c, (
|
||||
SELECT count(*)
|
||||
FROM t1 JOIN (SELECT DISTINCT t3.c AS p FROM t2) AS x ON t1.a=x.p
|
||||
)
|
||||
FROM t3;
|
||||
}
|
||||
} {test-2 1 1 test-2 2 0 test-2 3 0}
|
||||
|
||||
do_test 1.2 {
|
||||
execsql {
|
||||
CREATE TABLE t4(a, b, c);
|
||||
INSERT INTO t4 VALUES('a', 1, 'one');
|
||||
INSERT INTO t4 VALUES('a', 2, 'two');
|
||||
INSERT INTO t4 VALUES('b', 1, 'three');
|
||||
INSERT INTO t4 VALUES('b', 2, 'four');
|
||||
SELECT (
|
||||
SELECT c FROM (
|
||||
SELECT * FROM t4 WHERE a=out.a ORDER BY b LIMIT 10 OFFSET 1
|
||||
) WHERE b=out.b
|
||||
) FROM t4 AS out;
|
||||
}
|
||||
} {{} two {} four}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -44,7 +44,7 @@ do_test tkt-78e04-1.4 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM "" WHERE "" LIKE 'abc%';
|
||||
}
|
||||
} {0 0 {TABLE }}
|
||||
} {0 0 0 {SCAN TABLE (~500000 rows)}}
|
||||
do_test tkt-78e04-1.5 {
|
||||
execsql {
|
||||
DROP TABLE "";
|
||||
@@ -57,12 +57,12 @@ do_test tkt-78e04-2.1 {
|
||||
CREATE INDEX "" ON t2(x);
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=5;
|
||||
}
|
||||
} {0 0 {TABLE t2 WITH INDEX }}
|
||||
} {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX (x=?) (~10 rows)}}
|
||||
do_test tkt-78e04-2.2 {
|
||||
execsql {
|
||||
DROP INDEX "";
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=2;
|
||||
}
|
||||
} {0 0 {TABLE t2}}
|
||||
} {0 0 0 {SCAN TABLE t2 (~100000 rows)}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# 2010 September 28
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. Specifically,
|
||||
# it tests that ticket [b351d95f9cd5ef17e9d9dbae18f5ca8611190001] has been
|
||||
# resolved.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
do_test tkt-b351d95.1 {
|
||||
execsql {
|
||||
CREATE table t1(a,b);
|
||||
INSERT INTO t1 VALUES('name1','This is a test');
|
||||
INSERT INTO t1 VALUES('name2','xyz');
|
||||
CREATE TABLE t2(x,y);
|
||||
INSERT INTO t2 SELECT a, CASE b WHEN 'xyz' THEN null ELSE b END FROM t1;
|
||||
SELECT x, y FROM t2 ORDER BY x;
|
||||
}
|
||||
} {name1 {This is a test} name2 {}}
|
||||
|
||||
do_test tkt-b351d95.2 {
|
||||
execsql {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2 SELECT a, coalesce(b,a) FROM t1;
|
||||
SELECT x, y FROM t2 ORDER BY x;
|
||||
}
|
||||
} {name1 {This is a test} name2 xyz}
|
||||
do_test tkt-b351d95.3 {
|
||||
execsql {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2 SELECT a, coalesce(b,a) FROM t1;
|
||||
SELECT x, y BETWEEN 'xy' AND 'xz' FROM t2 ORDER BY x;
|
||||
}
|
||||
} {name1 0 name2 1}
|
||||
|
||||
finish_test
|
||||
+3
-3
@@ -49,10 +49,10 @@ proc EQP {sql} {
|
||||
ifcapable explain {
|
||||
do_test tkt3442-1.2 {
|
||||
EQP { SELECT node FROM listhash WHERE id='5000' LIMIT 1; }
|
||||
} {0 0 {TABLE listhash WITH INDEX ididx}}
|
||||
} {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}}
|
||||
do_test tkt3442-1.3 {
|
||||
EQP { SELECT node FROM listhash WHERE id="5000" LIMIT 1; }
|
||||
} {0 0 {TABLE listhash WITH INDEX ididx}}
|
||||
} {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ ifcapable explain {
|
||||
ifcapable explain {
|
||||
do_test tkt3442-1.4 {
|
||||
EQP { SELECT node FROM listhash WHERE id=5000 LIMIT 1; }
|
||||
} {0 0 {TABLE listhash WITH INDEX ididx}}
|
||||
} {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}}
|
||||
}
|
||||
do_test tkt3442-1.5 {
|
||||
catchsql {
|
||||
|
||||
+2
-2
@@ -35,9 +35,9 @@ do_test tkt3757-1.1 {
|
||||
CREATE TABLE t2(a INTEGER, b TEXT);
|
||||
INSERT INTO t2 VALUES(2, 'two');
|
||||
ANALYZE;
|
||||
SELECT * FROM sqlite_stat1;
|
||||
SELECT * FROM sqlite_stat1 ORDER BY 1, 2;
|
||||
}
|
||||
} {t1 t1i1 {1 1 1}}
|
||||
} {t1 t1i1 {1 1 1} t2 {} 1}
|
||||
|
||||
# Modify statistics in order to make the optimizer then that:
|
||||
#
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ do_test tkt3824-2.3 {
|
||||
lsort [execsql_status {
|
||||
SELECT a FROM t2 WHERE b=2 AND c IS NULL ORDER BY b;
|
||||
}]
|
||||
} {5 9 sort}
|
||||
} {5 9 nosort}
|
||||
|
||||
do_test tkt3824-3.1 {
|
||||
db eval {
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ execsql {
|
||||
# level. Return a list that is the length of each record
|
||||
# in the table, in the tables default scanning order.
|
||||
proc record_sizes {rootpage} {
|
||||
set bt [btree_open test.db 10 0]
|
||||
set bt [btree_open test.db 10]
|
||||
btree_begin_transaction $bt
|
||||
set c [btree_cursor $bt $rootpage 0]
|
||||
btree_first $c
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# 2011 April 9
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
set testprefix unordered
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
INSERT INTO t1 VALUES(1, 'xxx');
|
||||
INSERT INTO t1 SELECT a+1, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+2, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+4, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+8, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+16, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+32, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+64, b FROM t1;
|
||||
ANALYZE;
|
||||
} {}
|
||||
|
||||
foreach idxmode {ordered unordered} {
|
||||
if {$idxmode == "unordered"} {
|
||||
execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' }
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
}
|
||||
foreach {tn sql r(ordered) r(unordered)} {
|
||||
1 "SELECT * FROM t1 ORDER BY a"
|
||||
{0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
|
||||
{0 0 0 {SCAN TABLE t1 (~128 rows)}}
|
||||
2 "SELECT * FROM t1 WHERE a >?"
|
||||
{0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~32 rows)}}
|
||||
{0 0 0 {SCAN TABLE t1 (~42 rows)}}
|
||||
3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid"
|
||||
{0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
|
||||
{0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
|
||||
4 "SELECT max(a) FROM t1"
|
||||
{0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (~1 rows)}}
|
||||
{0 0 0 {SEARCH TABLE t1 (~1 rows)}}
|
||||
5 "SELECT group_concat(b) FROM t1 GROUP BY a"
|
||||
{0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
|
||||
{0 0 0 {SCAN TABLE t1 (~128 rows)}}
|
||||
|
||||
6 "SELECT * FROM t1 WHERE a = ?"
|
||||
{0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
|
||||
{0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
|
||||
7 "SELECT count(*) FROM t1"
|
||||
{0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1(~128 rows)}}
|
||||
{0 0 0 {SCAN TABLE t1 (~128 rows)}}
|
||||
} {
|
||||
do_eqp_test 1.$idxmode.$tn $sql $r($idxmode)
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
+5
-5
@@ -227,13 +227,13 @@ do_test where3-3.0 {
|
||||
explain query plan
|
||||
SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y;
|
||||
}
|
||||
} {0 0 {TABLE t302} 1 1 {TABLE t301 USING PRIMARY KEY}}
|
||||
} {0 0 0 {SCAN TABLE t302 (~1 rows)} 0 1 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
do_test where3-3.1 {
|
||||
execsql {
|
||||
explain query plan
|
||||
SELECT * FROM t301, t302 WHERE t302.x=5 AND t301.a=t302.y;
|
||||
}
|
||||
} {0 1 {TABLE t302} 1 0 {TABLE t301 USING PRIMARY KEY}}
|
||||
} {0 0 1 {SCAN TABLE t302 (~1 rows)} 0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
|
||||
|
||||
# Verify that when there are multiple tables in a join which must be
|
||||
# full table scans that the query planner attempts put the table with
|
||||
@@ -247,18 +247,18 @@ do_test where3-4.0 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t400, t401, t402 WHERE t402.z GLOB 'abc*';
|
||||
}
|
||||
} {0 2 {TABLE t402} 1 0 {TABLE t400} 2 1 {TABLE t401}}
|
||||
} {0 0 2 {SCAN TABLE t402 (~500000 rows)} 0 1 0 {SCAN TABLE t400 (~1000000 rows)} 0 2 1 {SCAN TABLE t401 (~1000000 rows)}}
|
||||
do_test where3-4.1 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t400, t401, t402 WHERE t401.r GLOB 'abc*';
|
||||
}
|
||||
} {0 1 {TABLE t401} 1 0 {TABLE t400} 2 2 {TABLE t402}}
|
||||
} {0 0 1 {SCAN TABLE t401 (~500000 rows)} 0 1 0 {SCAN TABLE t400 (~1000000 rows)} 0 2 2 {SCAN TABLE t402 (~1000000 rows)}}
|
||||
do_test where3-4.2 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t400, t401, t402 WHERE t400.c GLOB 'abc*';
|
||||
}
|
||||
} {0 0 {TABLE t400} 1 1 {TABLE t401} 2 2 {TABLE t402}}
|
||||
} {0 0 0 {SCAN TABLE t400 (~500000 rows)} 0 1 1 {SCAN TABLE t401 (~1000000 rows)} 0 2 2 {SCAN TABLE t402 (~1000000 rows)}}
|
||||
|
||||
finish_test
|
||||
|
||||
+35
-59
@@ -358,32 +358,25 @@ do_test where9-2.8 {
|
||||
|
||||
|
||||
ifcapable explain {
|
||||
do_test where9-3.1 {
|
||||
set r [db eval {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT t2.a FROM t1, t2
|
||||
WHERE t1.a=80
|
||||
AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f)
|
||||
}]
|
||||
set a [expr {[lsearch $r {TABLE t2 VIA MULTI-INDEX UNION}]>=0}]
|
||||
set b [expr {[lsearch $r {TABLE t2 WITH INDEX t2f}]>=0}]
|
||||
set c [expr {([lsearch $r {TABLE t2 WITH INDEX t2c}]>=0)+
|
||||
[lsearch $r {TABLE t2 WITH INDEX t2d}]>=0}]
|
||||
concat $a $b $c
|
||||
} {1 1 1}
|
||||
do_test where9-3.2 {
|
||||
set r [db eval {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT coalesce(t2.a,9999)
|
||||
FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f
|
||||
WHERE t1.a=80
|
||||
}]
|
||||
set a [expr {[lsearch $r {TABLE t2 VIA MULTI-INDEX UNION}]>=0}]
|
||||
set b [expr {[lsearch $r {TABLE t2 WITH INDEX t2f}]>=0}]
|
||||
set c [expr {([lsearch $r {TABLE t2 WITH INDEX t2c}]>=0)+
|
||||
[lsearch $r {TABLE t2 WITH INDEX t2d}]>=0}]
|
||||
concat $a $b $c
|
||||
} {1 1 1}
|
||||
do_execsql_test where9-3.1 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT t2.a FROM t1, t2
|
||||
WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f)
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}
|
||||
0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?) (~2 rows)}
|
||||
0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~10 rows)}
|
||||
}
|
||||
do_execsql_test where9-3.2 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT coalesce(t2.a,9999)
|
||||
FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f
|
||||
WHERE t1.a=80
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}
|
||||
0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?) (~2 rows)}
|
||||
0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~10 rows)}
|
||||
}
|
||||
}
|
||||
|
||||
# Make sure that INDEXED BY and multi-index OR clauses play well with
|
||||
@@ -458,46 +451,29 @@ ifcapable explain {
|
||||
# The (c=31031 OR d IS NULL) clause is preferred over b>1000 because
|
||||
# the former is an equality test which is expected to return fewer rows.
|
||||
#
|
||||
do_test where9-5.1 {
|
||||
set r [db eval {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT a FROM t1
|
||||
WHERE b>1000
|
||||
AND (c=31031 OR d IS NULL)
|
||||
}]
|
||||
set a [expr {[lsearch $r {TABLE t1 VIA MULTI-INDEX UNION}]>=0}]
|
||||
set b [expr {[lsearch $r {TABLE t1 WITH INDEX t1b}]>=0}]
|
||||
concat $a $b
|
||||
} {1 0}
|
||||
do_execsql_test where9-5.1 {
|
||||
EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL)
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?) (~10 rows)}
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?) (~10 rows)}
|
||||
}
|
||||
|
||||
# In contrast, b=1000 is preferred over any OR-clause.
|
||||
#
|
||||
do_test where9-5.2 {
|
||||
set r [db eval {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT a FROM t1
|
||||
WHERE b=1000
|
||||
AND (c=31031 OR d IS NULL)
|
||||
}]
|
||||
set a [expr {[lsearch $r {TABLE t1 VIA MULTI-INDEX UNION}]>=0}]
|
||||
set b [expr {[lsearch $r {TABLE t1 WITH INDEX t1b}]>=0}]
|
||||
concat $a $b
|
||||
} {0 1}
|
||||
do_execsql_test where9-5.2 {
|
||||
EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL)
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~5 rows)}
|
||||
}
|
||||
|
||||
# Likewise, inequalities in an AND are preferred over inequalities in
|
||||
# an OR.
|
||||
#
|
||||
do_test where9-5.3 {
|
||||
set r [db eval {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT a FROM t1
|
||||
WHERE b>1000
|
||||
AND (c>=31031 OR d IS NULL)
|
||||
}]
|
||||
set a [expr {[lsearch $r {TABLE t1 VIA MULTI-INDEX UNION}]>=0}]
|
||||
set b [expr {[lsearch $r {TABLE t1 WITH INDEX t1b}]>=0}]
|
||||
concat $a $b
|
||||
} {0 1}
|
||||
do_execsql_test where9-5.3 {
|
||||
EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL)
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>?) (~125000 rows)}
|
||||
}
|
||||
}
|
||||
|
||||
############################################################################
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
# 2012 August 24
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing that an index may be used as a covering
|
||||
# index when there are OR expressions in the WHERE clause.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix whereD
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t(i,j,k,m,n);
|
||||
CREATE INDEX ijk ON t(i,j,k);
|
||||
CREATE INDEX jmn ON t(j,m,n);
|
||||
|
||||
INSERT INTO t VALUES(3, 3, 'three', 3, 'tres');
|
||||
INSERT INTO t VALUES(2, 2, 'two', 2, 'dos');
|
||||
INSERT INTO t VALUES(1, 1, 'one', 1, 'uno');
|
||||
INSERT INTO t VALUES(4, 4, 'four', 4, 'cuatro');
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2);
|
||||
} {one two}
|
||||
do_execsql_test 1.3 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (+i=2 AND j=2);
|
||||
} {one two}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT n FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2);
|
||||
} {uno dos}
|
||||
do_execsql_test 1.5 {
|
||||
SELECT k, n FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2);
|
||||
} {one uno two dos}
|
||||
do_execsql_test 1.6 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2) OR (i=3 AND j=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.7 {
|
||||
SELECT n FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2) OR (i=3 AND j=3);
|
||||
} {uno dos tres}
|
||||
do_execsql_test 1.8 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (j=2 AND m=2);
|
||||
} {one two}
|
||||
do_execsql_test 1.9 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2) OR (j=3 AND m=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.10 {
|
||||
SELECT n FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2) OR (j=3 AND m=3);
|
||||
} {uno dos tres}
|
||||
do_execsql_test 1.11 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (j=2 AND m=2) OR (i=3 AND j=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.12 {
|
||||
SELECT n FROM t WHERE (i=1 AND j=1) OR (j=2 AND m=2) OR (i=3 AND j=3);
|
||||
} {uno dos tres}
|
||||
do_execsql_test 1.13 {
|
||||
SELECT k FROM t WHERE (j=1 AND m=1) OR (i=2 AND j=2) OR (i=3 AND j=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.14 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (j=2 AND i=2) OR (i=3 AND j=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.15 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=2) OR (i=2 AND j=1) OR (i=3 AND j=4);
|
||||
} {}
|
||||
do_execsql_test 1.16 {
|
||||
SELECT k FROM t WHERE (i=1 AND (j=1 or j=2)) OR (i=3 AND j=3);
|
||||
} {one three}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(a,b,c,d);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
CREATE INDEX t1c ON t1(c);
|
||||
CREATE INDEX t1d ON t1(d);
|
||||
CREATE TABLE t2(x,y);
|
||||
CREATE INDEX t2y ON t2(y);
|
||||
|
||||
INSERT INTO t1 VALUES(1,2,3,4);
|
||||
INSERT INTO t1 VALUES(5,6,7,8);
|
||||
INSERT INTO t2 VALUES(1,2);
|
||||
INSERT INTO t2 VALUES(2,7);
|
||||
INSERT INTO t2 VALUES(3,4);
|
||||
} {}
|
||||
do_execsql_test 2.1 {
|
||||
SELECT a, x FROM t1 JOIN t2 ON +y=d OR x=7 ORDER BY a, x;
|
||||
} {1 3}
|
||||
do_execsql_test 2.2 {
|
||||
SELECT a, x FROM t1 JOIN t2 ON y=d OR x=7 ORDER BY a, x;
|
||||
} {1 3}
|
||||
|
||||
|
||||
# Similar to [do_execsql_test], except that two elements are appended
|
||||
# to the result - the string "search" and the number of times test variable
|
||||
# sqlite3_search_count is incremented by running the supplied SQL. e.g.
|
||||
#
|
||||
# do_searchcount_test 1.0 { SELECT * FROM t1 } {x y search 2}
|
||||
#
|
||||
proc do_searchcount_test {tn sql res} {
|
||||
uplevel [subst -nocommands {
|
||||
do_test $tn {
|
||||
set ::sqlite_search_count 0
|
||||
concat [db eval {$sql}] search [set ::sqlite_search_count]
|
||||
} [list $res]
|
||||
}]
|
||||
}
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t3(a, b, c);
|
||||
CREATE UNIQUE INDEX i3 ON t3(a, b);
|
||||
INSERT INTO t3 VALUES(1, 'one', 'i');
|
||||
INSERT INTO t3 VALUES(3, 'three', 'iii');
|
||||
INSERT INTO t3 VALUES(6, 'six', 'vi');
|
||||
INSERT INTO t3 VALUES(2, 'two', 'ii');
|
||||
INSERT INTO t3 VALUES(4, 'four', 'iv');
|
||||
INSERT INTO t3 VALUES(5, 'five', 'v');
|
||||
|
||||
CREATE TABLE t4(x PRIMARY KEY, y);
|
||||
INSERT INTO t4 VALUES('a', 'one');
|
||||
INSERT INTO t4 VALUES('b', 'two');
|
||||
} {}
|
||||
|
||||
do_searchcount_test 3.1 {
|
||||
SELECT a, b FROM t3 WHERE (a=1 AND b='one') OR (a=2 AND b='two')
|
||||
} {1 one 2 two search 2}
|
||||
|
||||
do_searchcount_test 3.2 {
|
||||
SELECT a, c FROM t3 WHERE (a=1 AND b='one') OR (a=2 AND b='two')
|
||||
} {1 i 2 ii search 4}
|
||||
|
||||
do_searchcount_test 3.4.1 {
|
||||
SELECT y FROM t4 WHERE x='a'
|
||||
} {one search 2}
|
||||
do_searchcount_test 3.4.2 {
|
||||
SELECT a, b FROM t3 WHERE
|
||||
(a=1 AND b=(SELECT y FROM t4 WHERE x='a'))
|
||||
OR (a=2 AND b='two')
|
||||
} {1 one 2 two search 4}
|
||||
do_searchcount_test 3.4.3 {
|
||||
SELECT a, b FROM t3 WHERE
|
||||
(a=2 AND b='two')
|
||||
OR (a=1 AND b=(SELECT y FROM t4 WHERE x='a'))
|
||||
} {2 two 1 one search 4}
|
||||
do_searchcount_test 3.4.4 {
|
||||
SELECT a, b FROM t3 WHERE
|
||||
(a=2 AND b=(SELECT y FROM t4 WHERE x='b'))
|
||||
OR (a=1 AND b=(SELECT y FROM t4 WHERE x='a'))
|
||||
} {2 two 1 one search 6}
|
||||
|
||||
do_searchcount_test 3.5.1 {
|
||||
SELECT a, b FROM t3 WHERE (a=1 AND b='one') OR rowid=4
|
||||
} {1 one 2 two search 2}
|
||||
do_searchcount_test 3.5.2 {
|
||||
SELECT a, c FROM t3 WHERE (a=1 AND b='one') OR rowid=4
|
||||
} {1 i 2 ii search 2}
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -53,7 +53,7 @@ set in [open $TOP/manifest]
|
||||
set zDate {}
|
||||
while {![eof $in]} {
|
||||
set line [gets $in]
|
||||
if {[regexp {^D (2.*[0-9])} $line all date]} {
|
||||
if {[regexp {^D (2[-0-9T:]+)} $line all date]} {
|
||||
set zDate [string map {T { }} $date]
|
||||
break
|
||||
}
|
||||
|
||||
+10
-6
@@ -155,7 +155,7 @@ proc main {argv} {
|
||||
SQLITE_OMIT_CONFLICT_CLAUSE \
|
||||
SQLITE_OMIT_DATETIME_FUNCS \
|
||||
SQLITE_OMIT_DECLTYPE \
|
||||
off_SQLITE_OMIT_DISKIO \
|
||||
off_SQLITE_OMIT_DISKIO \
|
||||
SQLITE_OMIT_EXPLAIN \
|
||||
SQLITE_OMIT_FLAG_PRAGMAS \
|
||||
SQLITE_OMIT_FLOATING_POINT \
|
||||
@@ -182,11 +182,15 @@ proc main {argv} {
|
||||
SQLITE_OMIT_TEMPDB \
|
||||
SQLITE_OMIT_TRACE \
|
||||
SQLITE_OMIT_TRIGGER \
|
||||
SQLITE_OMIT_UTF16 \
|
||||
SQLITE_OMIT_VACUUM \
|
||||
SQLITE_OMIT_VIEW \
|
||||
SQLITE_OMIT_VIRTUALTABLE \
|
||||
SQLITE_OMIT_XFER_OPT \
|
||||
SQLITE_OMIT_TRUNCATE_OPTIMIZATION \
|
||||
SQLITE_OMIT_UNIQUE_ENFORCEMENT \
|
||||
SQLITE_OMIT_UTF16 \
|
||||
SQLITE_OMIT_VACUUM \
|
||||
SQLITE_OMIT_VIEW \
|
||||
SQLITE_OMIT_VIRTUALTABLE \
|
||||
SQLITE_OMIT_WAL \
|
||||
SQLITE_OMIT_WSD \
|
||||
SQLITE_OMIT_XFER_OPT \
|
||||
]
|
||||
|
||||
# Process any command line options.
|
||||
|
||||
Reference in New Issue
Block a user