Merge recent trunk enhancements, and in particular the improvements to

the b-tree balancing logic, into the sessions branch.

FossilOrigin-Name: 28b044a51215a3f64dafb2cf3b6cb7d2029580ef
This commit is contained in:
drh 2014-10-31 14:53:32 +00:00
commit ca3e10ea37
50 changed files with 2609 additions and 663 deletions

View File

@ -1 +1 @@
3.8.7
3.8.8

18
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.8.7.
# Generated by GNU Autoconf 2.62 for sqlite 3.8.8.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.8.7'
PACKAGE_STRING='sqlite 3.8.7'
PACKAGE_VERSION='3.8.8'
PACKAGE_STRING='sqlite 3.8.8'
PACKAGE_BUGREPORT=''
# Factoring default headers for most tests.
@ -1483,7 +1483,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.8.7 to adapt to many kinds of systems.
\`configure' configures sqlite 3.8.8 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1548,7 +1548,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.8.7:";;
short | recursive ) echo "Configuration of sqlite 3.8.8:";;
esac
cat <<\_ACEOF
@ -1664,7 +1664,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.8.7
sqlite configure 3.8.8
generated by GNU Autoconf 2.62
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.8.7, which was
It was created by sqlite $as_me 3.8.8, which was
generated by GNU Autoconf 2.62. Invocation command line was
$ $0 $@
@ -14021,7 +14021,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.8.7, which was
This file was extended by sqlite $as_me 3.8.8, which was
generated by GNU Autoconf 2.62. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -14074,7 +14074,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
sqlite config.status 3.8.7
sqlite config.status 3.8.8
configured by $0, generated by GNU Autoconf 2.62,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

View File

@ -102,7 +102,7 @@ do_eqp_test rtree6.2.4.2 {
SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1}
0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)}
0 1 1 {SEARCH TABLE t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?)}
}
do_eqp_test rtree6.2.5 {

100
manifest
View File

@ -1,12 +1,12 @@
C Merge\sall\sversion\s3.8.7\supdates\sfrom\strunk.
D 2014-10-17T11:53:22.349
C Merge\srecent\strunk\senhancements,\sand\sin\sparticular\sthe\simprovements\sto\nthe\sb-tree\sbalancing\slogic,\sinto\sthe\ssessions\sbranch.
D 2014-10-31T14:53:32.379
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in dd5f245aa8c741bc65845747203c8ce2f3fb6c83
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc 35808af7f8d999176ed5b38fb482a87a129ee3e1
F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0
F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
F VERSION 53a0b870e7f16d3b06623c31d233a304c163a6af
F VERSION d846487aff892625eb8e75960234e7285f0462fe
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
@ -38,7 +38,7 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure ad59a5f48b3c59a92b5506040a22fbe3f733a9d8 x
F configure 4343c810cc772571210af75d1a8f7c2eb711d75a x
F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
@ -130,7 +130,7 @@ F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e
F ext/rtree/rtree6.test 0cfbdf27ee086bf16a3da2c6f2d5b3d6473cb27e
F ext/rtree/rtree6.test 773a90db2dce6a8353dd0d5b64bca69b29761196
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34
@ -180,25 +180,25 @@ F mptest/mptest.c 499a74af4be293b7c1c7c3d40f332b67227dd739
F mptest/multiwrite01.test 499ad0310da8dff8e8f98d2e272fc2a8aa741b2e
F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb
F src/analyze.c 8c322e1ecc08909526dbd5ab4421889d05f2263d
F src/analyze.c afbcca663c3f3625340b8e30d440cd7a97ded6bc
F src/attach.c f4e94df2d1826feda65eb0939f7f6f5f923a0ad9
F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2
F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c 7f841396adfd47507ff670a471162d2bfcda3136
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
F src/btree.c 1b1123cba0c65caa0baa51e71b8c089e3167c3ed
F src/btree.c 61d96c2edacc5267fae6e477c24c774cd540d7f0
F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8
F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179
F src/build.c 9dc2bd94347b878c89627000c92b0c8d97ec2919
F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c 535183afb3c75628b78ce82612931ac7cdf26f14
F src/ctime.c bb434068b5308a857b181c2d204a320ff0d6c638
F src/complete.c c4ba6e0626bb94bc77a0861735f3382fcf7cc818
F src/ctime.c df19848891c8a553c80e6f5a035e768280952d1a
F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036
F src/delete.c de3d07d6602b90ae6e8bdebeb7b3265bb846377f
F src/expr.c fc204d08af06437ddaffe5a1b1f1f6f9e1a55d6d
F src/delete.c 20a360262b62051afacb44122b3593a8bd9be131
F src/expr.c 0391a657df4959eaf2a2fd7d77de5ebe750686ee
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
F src/func.c ba47c1671ab3cfdafa6e9d6ee490939ea578adee
@ -211,7 +211,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994
F src/main.c c67be3c356abdf33d00b2345e653c41b4049bee1
F src/main.c 7a3d124561f3fd0555dbefe492f5db0a4ba9f8d8
F src/malloc.c 3c3ac67969612493d435e14b6832793209afd2ec
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f
@ -219,42 +219,42 @@ F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb
F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85
F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c
F src/mutex.c 19bf9acba69ca2f367c3761080f8a9f0cf4670a8
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1
F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3
F src/mutex_unix.c 551e2f25f0fa0ee8fd7a43f50fc3d8be00e95dde
F src/mutex_w32.c 06bfff9a3a83b53389a51a967643db3967032e1e
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
F src/os_unix.c fb587121840f690101336879adfa6d0b2cd0e8c7
F src/os_win.c a019caaae2bcbbc0cc4c39af6e7d7e43d8426053
F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21
F src/pager.c a171cf9dd09c6cb162b262c328d4dfd198e04f80
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
F src/pager.c 8d97b3633f098fef817656dcbf167ca904511d78
F src/pager.h d1eee3c3f741be247ce6d82752a178515fc8578b
F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45
F src/pcache.c 4121a0571c18581ee9f82f086d5e2030051ebd6a
F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a
F src/pcache1.c e412cb585f777c840ddce0500eddc5c6043c2bb5
F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f
F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196
F src/printf.c 6b79bbd063dcbadca4cf617a4cde255bcc13ea64
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89
F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7
F src/printf.c 10a2493593c8e4a538915cd3674bd7a67f70c488
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c 428165951748151e87a15295b7357221433e311b
F src/shell.c f2b146c89967d83cca8735126ee9ff4ce7345dd1
F src/sqlite.h.in 514eeb7b0845840c132736e714ddd98ab9216e6c
F src/shell.c e3a0e5d94d58fbaf9a4a0a4bb2db19ed2e64be6d
F src/sqlite.h.in 322c7813901be3038a7df08cdb456ad76e880f60
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
F src/sqliteInt.h f712b324bafdc646c7fcfe813f81e8b8eebb57b9
F src/sqliteInt.h 339f3f8bf633452d271a3c9c593c4a0faaa171f8
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 961d5926e5a8fda611d385ec22c226b8635cd1cb
F src/table.c 2e99ef7ef16187e17033d9398dc962ce22dab5cb
F src/status.c 81712116e826b0089bb221b018929536b2b5406f
F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc
F src/tclsqlite.c 684c317b85f4729de12909bfad80d3f5500357cf
F src/test1.c 518db4305d76b29dd9da3f022ca899c8fcdf9fc7
F src/test1.c 63d4b1707c4052cf9c05c1cbb4a62666d70a0b48
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@ -302,25 +302,25 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 6de09362b657f19ba83e5fa521ee715787ce9fee
F src/tokenize.c cc9016e5007fc5e76789079616d2f26741bcc689
F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f
F src/update.c b9e5295d3a78e96b7c2978c4f9d224d06880f031
F src/update.c d207deb7a031f698104bee879de0632b611e72dd
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8
F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73
F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a
F src/vdbe.c a1465183697f2a187520d13cebf6a41f3832e0c0
F src/vdbe.c 407f16f5991c5bb27978e00bf74e64dd0dabd692
F src/vdbe.h d61daeffed696e21630759de9e135ee298ad9573
F src/vdbeInt.h 7254c20b45033e1194601a02f3a386e39263c0ab
F src/vdbeapi.c 30a1c991147fdf4334900b5fed8a312ae7678707
F src/vdbeaux.c 191ea23e5adbe5b6adcb9d31860b9fb890834e24
F src/vdbeblob.c d65b01f439df63911ac3d7a9a85c15503965f2c3
F src/vdbeInt.h 18756149efd3a931803381074dccc4ce161c7063
F src/vdbeapi.c 1a5c9248249f3e17bd0707da799d4c613970ffe1
F src/vdbeaux.c d53c188cde088b58bd2733144c4c803e32bf2bba
F src/vdbeblob.c d83b1f9e8f3c0359adc8404b8673b7994739daf7
F src/vdbemem.c 96e41193b4affd9ebc0eea2fa628879dac88c744
F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438
F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010
F src/vtab.c cb0c194303fea276b48d7d4b6d970b5a96bde8de
F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793
F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
F src/where.c 2947912f1f3d6a7766fe087fd532a5d688d745b1
F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c
F src/where.c 5665df88cbd2b38eb72b4b94c8892c8afb360181
F src/whereInt.h 19279cd0664ce1d90b9ad3ef0108cb494acfe455
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
@ -363,6 +363,7 @@ F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7
F test/autoindex1.test 6ff78b94f43a59616c06c11c55b12935173506d7
F test/autoindex2.test 60d2fc6f38364308ce73a9beb01b47ded38697de
F test/autoindex3.test 8254f689c3241081fad52b7bea18ba53e07e14a2
F test/autoindex4.test fc807f9efd158bec60f5dfdf34ebe46fb274612d
F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
@ -467,6 +468,7 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579
F test/e_createtable.test c7e67b49e6cf92473c8fb30ab26143e9e2128cf7
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
@ -479,9 +481,11 @@ F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589
F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
F test/e_select.test 52692ff3849541e828ad4661fe3773a9b8711763
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10
F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52
F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585
F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9
F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40
@ -785,7 +789,7 @@ F test/permutations.test a33230010a3d4ce0c57d586672ccef10a7d1af29
F test/pragma.test 19d0241a007bcdd77fc2606ec60fc60357e7fc8b
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1
F test/printf2.test b4acd4bf8734243257f01ddefa17c4fb090acc8a
F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
@ -862,6 +866,7 @@ F test/skipscan1.test 7e15e1cc524524e7b2c4595ec85c75501d22f4ff
F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
F test/skipscan6.test 3a891b45d6df266ced861a2ad9d03fca2bc7fcc5
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
F test/sort.test c4400e7533748f6bd7413851ff148645e82b9e2d
@ -1066,7 +1071,7 @@ F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41
F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
F test/triggerC.test a68980c5955d62ee24be6f97129d824f199f9a4c
@ -1080,7 +1085,7 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
F test/unique2.test 41e7f83c6827605991160a31380148a9fc5f1339
F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb
F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32
F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b
F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
@ -1217,12 +1222,13 @@ F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
F tool/symbols.sh c5a617b8c61a0926747a56c65f5671ef8ac0e148
F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 236704a9d1551a50a55bd6e0b6473191a7a7dd21 e4ab094f8afce0817f4074e823fabe59fc29ebb4
R 94ea0ef4c36ef357c67b389bf2d7aa16
P f4de9e07be3819db222317725e62ea997cd22a20 67f0d469da28c023200239a1f3d0c6cef9ef0e45
R c6574894282e9c56b60788bbd17b6d37
U drh
Z bebb5b662648007cddd6eaea9299c843
Z d46687ae123d3be720b18e6a3cbacd2c

View File

@ -1 +1 @@
f4de9e07be3819db222317725e62ea997cd22a20
28b044a51215a3f64dafb2cf3b6cb7d2029580ef

View File

@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH SQLITE3 1 "Mon Jan 31 11:14:00 2014"
.TH SQLITE3 1 "Fri Oct 31 10:41:31 EDT 2014"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@ -49,7 +49,7 @@ a table named "memos" and insert a couple of records into that table:
$
.B sqlite3 mydata.db
.br
SQLite version 3.8.3
SQLite version 3.8.8
.br
Enter ".help" for instructions
.br
@ -107,26 +107,29 @@ the '.help' command. For example:
sqlite>
.B .help
.nf
.cc |
.backup ?DB? FILE Backup DB (default "main") to FILE
.bail ON|OFF Stop after hitting an error. Default OFF
.databases List names and files of attached databases
.dump ?TABLE? ... Dump the database in an SQL text format
.tr %.
%backup ?DB? FILE Backup DB (default "main") to FILE
%bail on|off Stop after hitting an error. Default OFF
%clone NEWDB Clone data into NEWDB from the existing database
%databases List names and files of attached databases
%dump ?TABLE? ... Dump the database in an SQL text format
If TABLE specified, only dump tables matching
LIKE pattern TABLE.
.echo ON|OFF Turn command echo on or off
.exit Exit this program
.explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.
%echo on|off Turn command echo on or off
%eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN
%exit Exit this program
%explain ?on|off? Turn output mode suitable for EXPLAIN on or off.
With no args, it turns EXPLAIN on.
.header(s) ON|OFF Turn display of headers on or off
.help Show this message
.import FILE TABLE Import data from FILE into TABLE
.indices ?TABLE? Show names of all indices
%fullschema Show schema and the content of sqlite_stat tables
%headers on|off Turn display of headers on or off
%help Show this message
%import FILE TABLE Import data from FILE into TABLE
%indices ?TABLE? Show names of all indices
If TABLE specified, only show indices for tables
matching LIKE pattern TABLE.
.load FILE ?ENTRY? Load an extension library
.log FILE|off Turn logging on or off. FILE can be stderr/stdout
.mode MODE ?TABLE? Set output mode where MODE is one of:
%load FILE ?ENTRY? Load an extension library
%log FILE|off Turn logging on or off. FILE can be stderr/stdout
%mode MODE ?TABLE? Set output mode where MODE is one of:
csv Comma-separated values
column Left-aligned columns. (See .width)
html HTML <table> code
@ -135,31 +138,35 @@ sqlite>
list Values delimited by .separator string
tabs Tab-separated values
tcl TCL list elements
.nullvalue STRING Use STRING in place of NULL values
.open ?FILENAME? Close existing database and reopen FILENAME
.output FILENAME Send output to FILENAME
.output stdout Send output to the screen
.print STRING... Print literal STRING
.prompt MAIN CONTINUE Replace the standard prompts
.quit Exit this program
.read FILENAME Execute SQL in FILENAME
.restore ?DB? FILE Restore content of DB (default "main") from FILE
.schema ?TABLE? Show the CREATE statements
%nullvalue STRING Use STRING in place of NULL values
%once FILENAME Output for the next SQL command only to FILENAME
%open ?FILENAME? Close existing database and reopen FILENAME
%output ?FILENAME? Send output to FILENAME or stdout
%print STRING... Print literal STRING
%prompt MAIN CONTINUE Replace the standard prompts
%quit Exit this program
%read FILENAME Execute SQL in FILENAME
%restore ?DB? FILE Restore content of DB (default "main") from FILE
%save FILE Write in-memory database into FILE
%schema ?TABLE? Show the CREATE statements
If TABLE specified, only show tables matching
LIKE pattern TABLE.
.separator STRING Change separator used by output mode and .import
.show Show the current values for various settings
.stats ON|OFF Turn stats on or off
.tables ?TABLE? List names of tables
%separator STRING ?NL? Change separator used by output mode and .import
NL is the end-of-line mark for CSV
%shell CMD ARGS... Run CMD ARGS... in a system shell
%show Show the current values for various settings
%stats on|off Turn stats on or off
%system CMD ARGS... Run CMD ARGS... in a system shell
%tables ?TABLE? List names of tables
If TABLE specified, only list tables matching
LIKE pattern TABLE.
.timeout MS Try opening locked tables for MS milliseconds
.trace FILE|off Output each SQL statement as it is run
.vfsname ?AUX? Print the name of the VFS stack
.width NUM1 NUM2 ... Set column widths for "column" mode
.timer ON|OFF Turn the CPU timer measurement on or off
%timeout MS Try opening locked tables for MS milliseconds
%timer on|off Turn SQL timer on or off
%trace FILE|off Output each SQL statement as it is run
%vfsname ?AUX? Print the name of the VFS stack
%width NUM1 NUM2 ... Set column widths for "column" mode
Negative values right-justify
sqlite>
|cc .
.sp
.fi
.SH OPTIONS
@ -269,7 +276,7 @@ o If the -init option is present, the specified file is processed.
o All other command line options are processed.
.SH SEE ALSO
http://www.sqlite.org/
http://www.sqlite.org/cli.html
.br
The sqlite3-doc package.
.SH AUTHOR

View File

@ -1599,6 +1599,7 @@ static void initAvgEq(Index *pIdx){
nRow = pIdx->aiRowEst[0];
nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1];
}
pIdx->nRowEst0 = nRow;
/* Set nSum to the number of distinct (iCol+1) field prefixes that
** occur in the stat4 table for this index. Set sumEq to the sum of
@ -1860,7 +1861,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( rc==SQLITE_OK ){
if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
int lookasideEnabled = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
rc = loadStat4(db, sInfo.zDatabase);

View File

@ -72,6 +72,9 @@ int sqlite3_set_authorizer(
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pArg
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
db->xAuth = (sqlite3_xauth)xAuth;
db->pAuthArg = pArg;

View File

@ -138,6 +138,13 @@ sqlite3_backup *sqlite3_backup_init(
){
sqlite3_backup *p; /* Value to return */
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(pSrcDb)||!sqlite3SafetyCheckOk(pDestDb) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
/* Lock the source database handle. The destination database
** handle is not locked in this routine, but it is locked in
** sqlite3_backup_step(). The user is required to ensure that no
@ -334,6 +341,9 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int pgszSrc = 0; /* Source page size */
int pgszDest = 0; /* Destination page size */
#ifdef SQLITE_ENABLE_API_ARMOR
if( p==0 ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(p->pSrcDb->mutex);
sqlite3BtreeEnter(p->pSrc);
if( p->pDestDb ){
@ -623,6 +633,12 @@ int sqlite3_backup_finish(sqlite3_backup *p){
** call to sqlite3_backup_step().
*/
int sqlite3_backup_remaining(sqlite3_backup *p){
#ifdef SQLITE_ENABLE_API_ARMOR
if( p==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
return p->nRemaining;
}
@ -631,6 +647,12 @@ int sqlite3_backup_remaining(sqlite3_backup *p){
** recent call to sqlite3_backup_step().
*/
int sqlite3_backup_pagecount(sqlite3_backup *p){
#ifdef SQLITE_ENABLE_API_ARMOR
if( p==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
return p->nPagecount;
}

File diff suppressed because it is too large Load Diff

View File

@ -307,7 +307,11 @@ int sqlite3UserAuthTable(const char *zTable){
Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
Table *p = 0;
int i;
assert( zName!=0 );
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 ) return 0;
#endif
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
#if SQLITE_USER_AUTHENTICATION

View File

@ -105,6 +105,13 @@ int sqlite3_complete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
#ifdef SQLITE_ENABLE_API_ARMOR
if( zSql==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
#ifndef SQLITE_OMIT_TRIGGER
/* A complex statement machine used to detect the end of a CREATE TRIGGER
** statement. This is the normal case.

View File

@ -63,6 +63,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_DISABLE_LFS
"DISABLE_LFS",
#endif
#ifdef SQLITE_ENABLE_API_ARMOR
"ENABLE_API_ARMOR",
#endif
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
"ENABLE_ATOMIC_WRITE",
#endif
@ -388,6 +391,13 @@ static const char * const azCompileOpt[] = {
*/
int sqlite3_compileoption_used(const char *zOptName){
int i, n;
#ifdef SQLITE_ENABLE_API_ARMOR
if( zOptName==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
n = sqlite3Strlen30(zOptName);

View File

@ -488,7 +488,7 @@ void sqlite3DeleteFrom(
assert( nKey==nPk ); /* OP_Found will use an unpacked key */
assert( !IsVirtual(pTab) );
if( aToOpen[iDataCur-iTabCur] ){
assert( pPk!=0 );
assert( pPk!=0 || pTab->pSelect!=0 );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
VdbeCoverage(v);
}

View File

@ -1210,20 +1210,24 @@ void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
}
/*
** These routines are Walker callbacks. Walker.u.pi is a pointer
** to an integer. These routines are checking an expression to see
** if it is a constant. Set *Walker.u.i to 0 if the expression is
** not constant.
** These routines are Walker callbacks used to check expressions to
** see if they are "constant" for some definition of constant. The
** Walker.eCode value determines the type of "constant" we are looking
** for.
**
** These callback routines are used to implement the following:
**
** sqlite3ExprIsConstant() pWalker->u.i==1
** sqlite3ExprIsConstantNotJoin() pWalker->u.i==2
** sqlite3ExprIsConstantOrFunction() pWalker->u.i==3 or 4
** sqlite3ExprIsConstant() pWalker->eCode==1
** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2
** sqlite3ExprRefOneTableOnly() pWalker->eCode==3
** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5
**
** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
** is found to not be a constant.
**
** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions
** in a CREATE TABLE statement. The Walker.u.i value is 4 when parsing
** an existing schema and 3 when processing a new statement. A bound
** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing
** an existing schema and 4 when processing a new statement. A bound
** parameter raises an error for new statements, but is silently converted
** to NULL for existing schemas. This allows sqlite_master tables that
** contain a bound parameter because they were generated by older versions
@ -1232,23 +1236,25 @@ void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
/* If pWalker->u.i is 2 then any term of the expression that comes from
** the ON or USING clauses of a join disqualifies the expression
/* If pWalker->eCode is 2 then any term of the expression that comes from
** the ON or USING clauses of a left join disqualifies the expression
** from being considered constant. */
if( pWalker->u.i==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
pWalker->u.i = 0;
if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
pWalker->eCode = 0;
return WRC_Abort;
}
switch( pExpr->op ){
/* Consider functions to be constant if all their arguments are constant
** and either pWalker->u.i==3 or 4 or the function as the SQLITE_FUNC_CONST
** flag. */
** and either pWalker->eCode==4 or 5 or the function has the
** SQLITE_FUNC_CONST flag. */
case TK_FUNCTION:
if( pWalker->u.i>=3 || ExprHasProperty(pExpr,EP_Constant) ){
if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_Constant) ){
return WRC_Continue;
}else{
pWalker->eCode = 0;
return WRC_Abort;
}
/* Fall through */
case TK_ID:
case TK_COLUMN:
case TK_AGG_FUNCTION:
@ -1257,18 +1263,22 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
testcase( pExpr->op==TK_AGG_COLUMN );
pWalker->u.i = 0;
return WRC_Abort;
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
return WRC_Continue;
}else{
pWalker->eCode = 0;
return WRC_Abort;
}
case TK_VARIABLE:
if( pWalker->u.i==4 ){
if( pWalker->eCode==5 ){
/* Silently convert bound parameters that appear inside of CREATE
** statements into a NULL when parsing the CREATE statement text out
** of the sqlite_master table */
pExpr->op = TK_NULL;
}else if( pWalker->u.i==3 ){
}else if( pWalker->eCode==4 ){
/* A bound parameter in a CREATE statement that originates from
** sqlite3_prepare() causes an error */
pWalker->u.i = 0;
pWalker->eCode = 0;
return WRC_Abort;
}
/* Fall through */
@ -1280,21 +1290,22 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
}
static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
UNUSED_PARAMETER(NotUsed);
pWalker->u.i = 0;
pWalker->eCode = 0;
return WRC_Abort;
}
static int exprIsConst(Expr *p, int initFlag){
static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
memset(&w, 0, sizeof(w));
w.u.i = initFlag;
w.eCode = initFlag;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = selectNodeIsConstant;
w.u.iCur = iCur;
sqlite3WalkExpr(&w, p);
return w.u.i;
return w.eCode;
}
/*
** Walk an expression tree. Return 1 if the expression is constant
** Walk an expression tree. Return non-zero if the expression is constant
** and 0 if it involves variables or function calls.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
@ -1302,21 +1313,31 @@ static int exprIsConst(Expr *p, int initFlag){
** a constant.
*/
int sqlite3ExprIsConstant(Expr *p){
return exprIsConst(p, 1);
return exprIsConst(p, 1, 0);
}
/*
** Walk an expression tree. Return 1 if the expression is constant
** Walk an expression tree. Return non-zero if the expression is constant
** that does no originate from the ON or USING clauses of a join.
** Return 0 if it involves variables or function calls or terms from
** an ON or USING clause.
*/
int sqlite3ExprIsConstantNotJoin(Expr *p){
return exprIsConst(p, 2);
return exprIsConst(p, 2, 0);
}
/*
** Walk an expression tree. Return 1 if the expression is constant
** Walk an expression tree. Return non-zero if the expression constant
** for any single row of the table with cursor iCur. In other words, the
** expression must not refer to any non-deterministic function nor any
** table other than iCur.
*/
int sqlite3ExprIsTableConstant(Expr *p, int iCur){
return exprIsConst(p, 3, iCur);
}
/*
** Walk an expression tree. Return non-zero if the expression is constant
** or a function call with constant arguments. Return and 0 if there
** are any variables.
**
@ -1326,7 +1347,7 @@ int sqlite3ExprIsConstantNotJoin(Expr *p){
*/
int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
assert( isInit==0 || isInit==1 );
return exprIsConst(p, 3+isInit);
return exprIsConst(p, 4+isInit, 0);
}
/*

View File

@ -598,6 +598,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
** Return the mutex associated with a database connection.
*/
sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
return db->mutex;
}
@ -607,6 +613,10 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
*/
int sqlite3_db_release_memory(sqlite3 *db){
int i;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
for(i=0; i<db->nDb; i++){
@ -737,6 +747,12 @@ static int nocaseCollatingFunc(
** Return the ROWID of the most recent insert
*/
sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
return db->lastRowid;
}
@ -744,6 +760,12 @@ sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
** Return the number of changes in the most recent call to sqlite3_exec().
*/
int sqlite3_changes(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
return db->nChange;
}
@ -751,6 +773,12 @@ int sqlite3_changes(sqlite3 *db){
** Return the number of changes since the database handle was opened.
*/
int sqlite3_total_changes(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
return db->nTotalChange;
}
@ -1296,6 +1324,9 @@ int sqlite3_busy_handler(
int (*xBusy)(void*,int),
void *pArg
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE;
#endif
sqlite3_mutex_enter(db->mutex);
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
@ -1317,6 +1348,12 @@ void sqlite3_progress_handler(
int (*xProgress)(void*),
void *pArg
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return;
}
#endif
sqlite3_mutex_enter(db->mutex);
if( nOps>0 ){
db->xProgress = xProgress;
@ -1337,6 +1374,9 @@ void sqlite3_progress_handler(
** specified number of milliseconds before returning 0.
*/
int sqlite3_busy_timeout(sqlite3 *db, int ms){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( ms>0 ){
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
db->busyTimeout = ms;
@ -1350,6 +1390,12 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
** Cause any pending operation to stop at its earliest opportunity.
*/
void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return;
}
#endif
db->u1.isInterrupted = 1;
}
@ -1487,6 +1533,12 @@ int sqlite3_create_function_v2(
){
int rc = SQLITE_ERROR;
FuncDestructor *pArg = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE_BKPT;
}
#endif
sqlite3_mutex_enter(db->mutex);
if( xDestroy ){
pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
@ -1523,6 +1575,10 @@ int sqlite3_create_function16(
){
int rc;
char *zFunc8;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
@ -1554,6 +1610,12 @@ int sqlite3_overload_function(
){
int nName = sqlite3Strlen30(zName);
int rc = SQLITE_OK;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){
return SQLITE_MISUSE_BKPT;
}
#endif
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
@ -1575,6 +1637,13 @@ int sqlite3_overload_function(
*/
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
void *pOld;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
db->xTrace = xTrace;
@ -1596,6 +1665,13 @@ void *sqlite3_profile(
void *pArg
){
void *pOld;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pProfileArg;
db->xProfile = xProfile;
@ -1616,6 +1692,13 @@ void *sqlite3_commit_hook(
void *pArg /* Argument to the function */
){
void *pOld;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pCommitArg;
db->xCommitCallback = xCallback;
@ -1634,6 +1717,13 @@ void *sqlite3_update_hook(
void *pArg /* Argument to the function */
){
void *pRet;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pUpdateArg;
db->xUpdateCallback = xCallback;
@ -1652,6 +1742,13 @@ void *sqlite3_rollback_hook(
void *pArg /* Argument to the function */
){
void *pRet;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pRollbackArg;
db->xRollbackCallback = xCallback;
@ -1719,6 +1816,9 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
UNUSED_PARAMETER(db);
UNUSED_PARAMETER(nFrame);
#else
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( nFrame>0 ){
sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
}else{
@ -1739,6 +1839,12 @@ void *sqlite3_wal_hook(
){
#ifndef SQLITE_OMIT_WAL
void *pRet;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pWalArg;
db->xWalCallback = xCallback;
@ -1766,6 +1872,10 @@ int sqlite3_wal_checkpoint_v2(
int rc; /* Return code */
int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
/* Initialize the output variables to -1 in case an error occurs. */
if( pnLog ) *pnLog = -1;
if( pnCkpt ) *pnCkpt = -1;
@ -2162,6 +2272,12 @@ static const int aHardLimit[] = {
int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
int oldLimit;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return -1;
}
#endif
/* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME
** there is a hard upper bound set at compile-time by a C preprocessor
@ -2447,6 +2563,9 @@ static int openDatabase(
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
#endif
*ppDb = 0;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
@ -2736,13 +2855,15 @@ int sqlite3_open16(
sqlite3_value *pVal;
int rc;
assert( zFilename );
assert( ppDb );
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
#endif
*ppDb = 0;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ) return rc;
#endif
if( zFilename==0 ) zFilename = "\000\000";
pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
@ -2772,13 +2893,7 @@ int sqlite3_create_collation(
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*)
){
int rc;
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, 0);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
return sqlite3_create_collation_v2(db, zName, enc, pCtx, xCompare, 0);
}
/*
@ -2793,6 +2908,10 @@ int sqlite3_create_collation_v2(
void(*xDel)(void*)
){
int rc;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel);
@ -2814,6 +2933,10 @@ int sqlite3_create_collation16(
){
int rc = SQLITE_OK;
char *zName8;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE);
@ -2836,6 +2959,9 @@ int sqlite3_collation_needed(
void *pCollNeededArg,
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = xCollNeeded;
db->xCollNeeded16 = 0;
@ -2854,6 +2980,9 @@ int sqlite3_collation_needed16(
void *pCollNeededArg,
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = 0;
db->xCollNeeded16 = xCollNeeded16;
@ -2880,6 +3009,12 @@ int sqlite3_global_recover(void){
** by the next COMMIT or ROLLBACK.
*/
int sqlite3_get_autocommit(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
return db->autoCommit;
}
@ -3062,6 +3197,9 @@ int sqlite3_sleep(int ms){
** Enable or disable the extended result codes.
*/
int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
db->errMask = onoff ? 0xffffffff : 0xff;
sqlite3_mutex_leave(db->mutex);
@ -3075,6 +3213,9 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
int rc = SQLITE_ERROR;
Btree *pBtree;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
pBtree = sqlite3DbNameToBtree(db, zDbName);
if( pBtree ){
@ -3417,7 +3558,7 @@ int sqlite3_test_control(int op, ...){
** returns a NULL pointer.
*/
const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
if( zFilename==0 ) return 0;
if( zFilename==0 || zParam==0 ) return 0;
zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] ){
int x = strcmp(zFilename, zParam);
@ -3473,6 +3614,12 @@ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
** connection.
*/
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
}
@ -3482,6 +3629,12 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
** no such database exists.
*/
int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return -1;
}
#endif
Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
}

View File

@ -82,6 +82,7 @@ int sqlite3MutexEnd(void){
sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
#endif
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}

View File

@ -175,8 +175,12 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
break;
}
default: {
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(staticMutexes) );
#ifdef SQLITE_ENABLE_API_ARMOR
if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
p = &staticMutexes[iType-2];
#if SQLITE_MUTEX_NREF
p->id = iType;

View File

@ -361,6 +361,10 @@ int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
int rc = sqlite3_initialize();
if( rc ) return rc;
#endif
#ifdef SQLITE_ENABLE_API_ARMOR
if( pVfs==0 ) return SQLITE_MISUSE_BKPT;
#endif
MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);

View File

@ -1941,6 +1941,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
rc = SQLITE_OK;
}else{
rc = sqlite3OsTruncate(pPager->jfd, 0);
if( rc==SQLITE_OK && pPager->fullSync ){
/* Make sure the new file size is written into the inode right away.
** Otherwise the journal might resurrect following a power loss and
** cause the last transaction to roll back. See
** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773
*/
rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags);
}
}
pPager->journalOff = 0;
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
@ -6839,6 +6847,18 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
}
#endif
/*
** The page handle passed as the first argument refers to a dirty page
** with a page number other than iNew. This function changes the page's
** page number to iNew and sets the value of the PgHdr.flags field to
** the value passed as the third parameter.
*/
void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){
assert( pPg->pgno!=iNew );
pPg->flags = flags;
sqlite3PcacheMove(pPg, iNew);
}
/*
** Return a pointer to the data for the specified page.
*/
@ -7237,4 +7257,5 @@ int sqlite3PagerWalFramesize(Pager *pPager){
}
#endif
#endif /* SQLITE_OMIT_DISKIO */

View File

@ -188,6 +188,8 @@ int sqlite3SectorSize(sqlite3_file *);
/* Functions used to truncate the database file. */
void sqlite3PagerTruncateImage(Pager*,Pgno);
void sqlite3PagerRekey(DbPage*, Pgno, u16);
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
void *sqlite3PagerCodec(DbPage *);
#endif

View File

@ -709,9 +709,12 @@ static int sqlite3LockAndPrepare(
const char **pzTail /* OUT: End of parsed string */
){
int rc;
assert( ppStmt!=0 );
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
#endif
*ppStmt = 0;
if( !sqlite3SafetyCheckOk(db) ){
if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
@ -818,9 +821,11 @@ static int sqlite3Prepare16(
const char *zTail8 = 0;
int rc = SQLITE_OK;
assert( ppStmt );
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
#endif
*ppStmt = 0;
if( !sqlite3SafetyCheckOk(db) ){
if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
return SQLITE_MISUSE_BKPT;
}
if( nBytes>=0 ){

View File

@ -21,11 +21,7 @@
** the glibc version so the glibc version is definitely preferred.
*/
#if !defined(HAVE_STRCHRNUL)
# if defined(linux)
# define HAVE_STRCHRNUL 1
# else
# define HAVE_STRCHRNUL 0
# endif
# define HAVE_STRCHRNUL 0
#endif
@ -216,7 +212,7 @@ void sqlite3VXPrintf(
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
char *zExtra; /* Malloced memory used by some conversion */
char *zExtra = 0; /* Malloced memory used by some conversion */
#ifndef SQLITE_OMIT_FLOATING_POINT
int exp, e2; /* exponent of real numbers */
int nsd; /* Number of significant digits returned */
@ -227,6 +223,13 @@ void sqlite3VXPrintf(
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
#ifdef SQLITE_ENABLE_API_ARMOR
if( ap==0 ){
(void)SQLITE_MISUSE_BKPT;
sqlite3StrAccumReset(pAccum);
return;
}
#endif
bufpt = 0;
if( bFlags ){
if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
@ -333,7 +336,6 @@ void sqlite3VXPrintf(
break;
}
}
zExtra = 0;
/*
** At this point, variables are initialized as follows:
@ -624,13 +626,16 @@ void sqlite3VXPrintf(
}else{
c = va_arg(ap,int);
}
buf[0] = (char)c;
if( precision>=0 ){
for(idx=1; idx<precision; idx++) buf[idx] = (char)c;
length = precision;
}else{
length =1;
if( precision>1 ){
width -= precision-1;
if( width>1 && !flag_leftjustify ){
sqlite3AppendChar(pAccum, width-1, ' ');
width = 0;
}
sqlite3AppendChar(pAccum, precision-1, c);
}
length = 1;
buf[0] = c;
bufpt = buf;
break;
case etSTRING:
@ -731,11 +736,14 @@ void sqlite3VXPrintf(
** the output.
*/
width -= length;
if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
sqlite3StrAccumAppend(pAccum, bufpt, length);
if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
if( zExtra ) sqlite3_free(zExtra);
if( zExtra ){
sqlite3_free(zExtra);
zExtra = 0;
}
}/* End for loop over the format string */
} /* End of function */
@ -788,11 +796,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
}
/*
** Append N space characters to the given string buffer.
** Append N copies of character c to the given string buffer.
*/
void sqlite3AppendSpace(StrAccum *p, int N){
void sqlite3AppendChar(StrAccum *p, int N, char c){
if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
while( (N--)>0 ) p->zText[p->nChar++] = ' ';
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
/*
@ -947,6 +955,13 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
#ifdef SQLITE_ENABLE_API_ARMOR
if( zFormat==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@ -989,6 +1004,13 @@ char *sqlite3_mprintf(const char *zFormat, ...){
char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
StrAccum acc;
if( n<=0 ) return zBuf;
#ifdef SQLITE_ENABLE_API_ARMOR
if( zBuf==0 || zFormat==0 ) {
(void)SQLITE_MISUSE_BKPT;
if( zBuf && n>0 ) zBuf[0] = 0;
return zBuf;
}
#endif
sqlite3StrAccumInit(&acc, zBuf, n, 0);
acc.useMalloc = 0;
sqlite3VXPrintf(&acc, 0, zFormat, ap);

View File

@ -48,11 +48,19 @@ void sqlite3_randomness(int N, void *pBuf){
#endif
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
sqlite3_mutex_enter(mutex);
sqlite3_mutex *mutex;
#endif
if( N<=0 ){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return;
#endif
#if SQLITE_THREADSAFE
mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
#endif
sqlite3_mutex_enter(mutex);
if( N<=0 || pBuf==0 ){
wsdPrng.isInit = 0;
sqlite3_mutex_leave(mutex);
return;

View File

@ -28,7 +28,7 @@
** is a helper function - a callback for the tree walker.
*/
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.i;
if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
return WRC_Continue;
}
static void incrAggFunctionDepth(Expr *pExpr, int N){
@ -36,7 +36,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
Walker w;
memset(&w, 0, sizeof(w));
w.xExprCallback = incrAggDepth;
w.u.i = N;
w.u.n = N;
sqlite3WalkExpr(&w, pExpr);
}
}
@ -584,7 +584,7 @@ static int exprProbability(Expr *p){
sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8);
assert( r>=0.0 );
if( r>1.0 ) return -1;
return (int)(r*1000.0);
return (int)(r*134217728.0);
}
/*
@ -716,7 +716,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to
** likelihood(X,0.9375). */
/* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938;
pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120;
}
}
#ifndef SQLITE_OMIT_AUTHORIZATION

View File

@ -899,7 +899,7 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
}
fprintf(p->out,"%s",p->newline);
}
if( azArg>0 ){
if( nArg>0 ){
for(i=0; i<nArg; i++){
output_csv(p, azArg[i], i<nArg-1);
}

View File

@ -1539,10 +1539,14 @@ struct sqlite3_mem_methods {
** argument must be a multiple of 16.
** The first argument must be a pointer to an 8-byte aligned buffer
** of at least sz*N bytes of memory.
** ^SQLite will use no more than two scratch buffers per thread. So
** N should be set to twice the expected maximum number of threads.
** ^SQLite will never require a scratch buffer that is more than 6
** times the database page size. ^If SQLite needs needs additional
** ^SQLite will not use more than two scratch buffers per thread and not
** more than one scratch buffer per thread when not performing
** a [checkpoint] in [WAL mode].
** ^SQLite will never request a scratch buffer that is more than 6
** times the database page size, except when performing a [checkpoint]
** in [WAL mode] when the scratch buffer request size is a small fraction
** of the size of the WAL file.
** ^If SQLite needs needs additional
** scratch memory beyond what is provided by this configuration option, then
** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
**
@ -1870,47 +1874,45 @@ sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
/*
** CAPI3REF: Count The Number Of Rows Modified
**
** ^This function returns the number of database rows that were changed
** or inserted or deleted by the most recently completed SQL statement
** on the [database connection] specified by the first parameter.
** ^(Only changes that are directly specified by the [INSERT], [UPDATE],
** or [DELETE] statement are counted. Auxiliary changes caused by
** triggers or [foreign key actions] are not counted.)^ Use the
** [sqlite3_total_changes()] function to find the total number of changes
** including changes caused by triggers and foreign key actions.
** ^This function returns the number of rows modified, inserted or
** deleted by the most recently completed INSERT, UPDATE or DELETE
** statement on the database connection specified by the only parameter.
** ^Executing any other type of SQL statement does not modify the value
** returned by this function.
**
** ^Changes to a view that are simulated by an [INSTEAD OF trigger]
** are not counted. Only real table changes are counted.
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
** [foreign key actions] or [REPLACE] constraint resolution are not counted.
**
** Changes to a view that are intercepted by
** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
** DELETE statement run on a view is always zero. Only changes made to real
** tables are counted.
**
** ^(A "row change" is a change to a single row of a single table
** caused by an INSERT, DELETE, or UPDATE statement. Rows that
** are changed as side effects of [REPLACE] constraint resolution,
** rollback, ABORT processing, [DROP TABLE], or by any other
** mechanisms do not count as direct row changes.)^
**
** A "trigger context" is a scope of execution that begins and
** ends with the script of a [CREATE TRIGGER | trigger].
** Most SQL statements are
** evaluated outside of any trigger. This is the "top level"
** trigger context. If a trigger fires from the top level, a
** new trigger context is entered for the duration of that one
** trigger. Subtriggers create subcontexts for their duration.
**
** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
** not create a new trigger context.
**
** ^This function returns the number of direct row changes in the
** most recent INSERT, UPDATE, or DELETE statement within the same
** trigger context.
**
** ^Thus, when called from the top level, this function returns the
** number of changes in the most recent INSERT, UPDATE, or DELETE
** that also occurred at the top level. ^(Within the body of a trigger,
** the sqlite3_changes() interface can be called to find the number of
** changes in the most recently completed INSERT, UPDATE, or DELETE
** statement within the body of the same trigger.
** However, the number returned does not include changes
** caused by subtriggers since those have their own context.)^
** Things are more complicated if the sqlite3_changes() function is
** executed while a trigger program is running. This may happen if the
** program uses the [changes() SQL function], or if some other callback
** function invokes sqlite3_changes() directly. Essentially:
**
** <ul>
** <li> ^(Before entering a trigger program the value returned by
** sqlite3_changes() function is saved. After the trigger program
** has finished, the original value is restored.)^
**
** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
** statement sets the value returned by sqlite3_changes()
** upon completion as normal. Of course, this value will not include
** any changes performed by sub-triggers, as the sqlite3_changes()
** value will be saved and restored after each sub-trigger has run.)^
** </ul>
**
** ^This means that if the changes() SQL function (or similar) is used
** by the first INSERT, UPDATE or DELETE statement within a trigger, it
** returns the value as set when the calling statement began executing.
** ^If it is used by the second or subsequent such statement within a trigger
** program, the value returned reflects the number of rows modified by the
** previous INSERT, UPDATE or DELETE statement within the same trigger.
**
** See also the [sqlite3_total_changes()] interface, the
** [count_changes pragma], and the [changes() SQL function].
@ -1924,20 +1926,17 @@ int sqlite3_changes(sqlite3*);
/*
** CAPI3REF: Total Number Of Rows Modified
**
** ^This function returns the number of row changes caused by [INSERT],
** [UPDATE] or [DELETE] statements since the [database connection] was opened.
** ^(The count returned by sqlite3_total_changes() includes all changes
** from all [CREATE TRIGGER | trigger] contexts and changes made by
** [foreign key actions]. However,
** the count does not include changes used to implement [REPLACE] constraints,
** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
** count does not include rows of views that fire an [INSTEAD OF trigger],
** though if the INSTEAD OF trigger makes changes of its own, those changes
** are counted.)^
** ^The sqlite3_total_changes() function counts the changes as soon as
** the statement that makes them is completed (when the statement handle
** is passed to [sqlite3_reset()] or [sqlite3_finalize()]).
**
** ^This function returns the total number of rows inserted, modified or
** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
** since the database connection was opened, including those executed as
** part of trigger programs. ^Executing any other type of SQL statement
** does not affect the value returned by sqlite3_total_changes().
**
** ^Changes made as part of [foreign key actions] are included in the
** count, but those made as part of REPLACE constraint resolution are
** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
** are not counted.
**
** See also the [sqlite3_changes()] interface, the
** [count_changes pragma], and the [total_changes() SQL function].
**
@ -2415,13 +2414,14 @@ sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
** ^If N is less than one, then P can be a NULL pointer.
** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
** call had N less than one, then the PRNG is seeded using randomness
** obtained from the xRandomness method of the default [sqlite3_vfs] object.
** ^If the previous call to this routine had an N of 1 or more then
** the pseudo-randomness is generated
** call had N less than one or a NULL pointer for P, then the PRNG is
** seeded using randomness obtained from the xRandomness method of
** the default [sqlite3_vfs] object.
** ^If the previous call to this routine had an N of 1 or more and a
** non-NULL P then the pseudo-randomness is generated
** internally and without recourse to the [sqlite3_vfs] xRandomness
** method.
*/

View File

@ -1222,7 +1222,7 @@ struct sqlite3 {
#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
#define SQLITE_Transitive 0x0200 /* Transitive constraints */
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
#define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */
#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
@ -1809,7 +1809,8 @@ struct Index {
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this table */
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
};
@ -2007,7 +2008,7 @@ struct Expr {
int iTable; /* TK_COLUMN: cursor number of table holding column
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
** EP_Unlikely: 1000 times likelihood */
** EP_Unlikely: 134217728 times likelihood */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
** TK_VARIABLE: variable number (always >= 1). */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
@ -2903,9 +2904,11 @@ struct Walker {
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
Parse *pParse; /* Parser context. */
int walkerDepth; /* Number of subqueries */
u8 eCode; /* A small processing code */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int i; /* Integer value */
int n; /* A counter */
int iCur; /* A cursor number */
SrcList *pSrcList; /* FROM clause */
struct SrcCount *pSrcCount; /* Counting column references */
} u;
@ -3306,6 +3309,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
int sqlite3ExprIsConstant(Expr*);
int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsTableConstant(Expr*,int);
int sqlite3ExprIsInteger(Expr*, int*);
int sqlite3ExprCanBeNull(const Expr*);
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
@ -3551,7 +3555,7 @@ int sqlite3OpenTempDatabase(Parse *);
void sqlite3StrAccumInit(StrAccum*, char*, int, int);
void sqlite3StrAccumAppend(StrAccum*,const char*,int);
void sqlite3StrAccumAppendAll(StrAccum*,const char*);
void sqlite3AppendSpace(StrAccum*,int);
void sqlite3AppendChar(StrAccum*,int,char);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumReset(StrAccum*);
void sqlite3SelectDestInit(SelectDest*,int,int);

View File

@ -86,6 +86,9 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
return SQLITE_MISUSE_BKPT;
}
#ifdef SQLITE_ENABLE_API_ARMOR
if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
#endif
*pCurrent = wsdStat.nowValue[op];
*pHighwater = wsdStat.mxValue[op];
if( resetFlag ){
@ -105,6 +108,11 @@ int sqlite3_db_status(
int resetFlag /* Reset high-water mark if true */
){
int rc = SQLITE_OK; /* Return code */
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
sqlite3_mutex_enter(db->mutex);
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {

View File

@ -126,6 +126,9 @@ int sqlite3_get_table(
int rc;
TabResult res;
#ifdef SQLITE_ENABLE_API_ARMOR
if( pazResult==0 ) return SQLITE_MISUSE_BKPT;
#endif
*pazResult = 0;
if( pnColumn ) *pnColumn = 0;
if( pnRow ) *pnRow = 0;

View File

@ -6293,7 +6293,8 @@ static int optimization_control(
{ "transitive", SQLITE_Transitive },
{ "subquery-coroutine", SQLITE_SubqCoroutine },
{ "omit-noop-join", SQLITE_OmitNoopJoin },
{ "stat3", SQLITE_Stat3 },
{ "stat3", SQLITE_Stat34 },
{ "stat4", SQLITE_Stat34 },
};
if( objc!=4 ){

View File

@ -431,8 +431,8 @@ void sqlite3Update(
/* Top of the update loop */
if( okOnePass ){
if( aToOpen[iDataCur-iBaseCur] ){
assert( pPk!=0 );
if( aToOpen[iDataCur-iBaseCur] && !isView ){
assert( pPk );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
VdbeCoverageNeverTaken(v);
}

View File

@ -251,6 +251,11 @@ int sqlite3Dequote(char *z){
*/
int sqlite3_stricmp(const char *zLeft, const char *zRight){
register unsigned char *a, *b;
if( zLeft==0 ){
return zRight ? -1 : 0;
}else if( zRight==0 ){
return 1;
}
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
@ -258,6 +263,11 @@ int sqlite3_stricmp(const char *zLeft, const char *zRight){
}
int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
register unsigned char *a, *b;
if( zLeft==0 ){
return zRight ? -1 : 0;
}else if( zRight==0 ){
return 1;
}
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }

View File

@ -2451,7 +2451,7 @@ case OP_Column: {
if( pOp->p4type==P4_MEM ){
sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
}else{
MemSetTypeFlag(pDest, MEM_Null);
sqlite3VdbeMemSetNull(pDest);
}
goto op_column_out;
}
@ -5483,6 +5483,7 @@ case OP_Program: { /* jump */
pFrame->pParent = p->pFrame;
pFrame->lastRowid = lastRowid;
pFrame->nChange = p->nChange;
pFrame->nDbChange = p->db->nChange;
p->nChange = 0;
p->pFrame = pFrame;
p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];

View File

@ -144,7 +144,8 @@ struct VdbeFrame {
int nOnceFlag; /* Number of entries in aOnceFlag */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
int nChange; /* Statement changes (Vdbe.nChanges) */
int nChange; /* Statement changes (Vdbe.nChange) */
int nDbChange; /* Value of db->nChange */
};
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])

View File

@ -966,11 +966,19 @@ static const void *columnName(
const void *(*xFunc)(Mem*),
int useType
){
const void *ret = 0;
Vdbe *p = (Vdbe *)pStmt;
const void *ret;
Vdbe *p;
int n;
sqlite3 *db = p->db;
sqlite3 *db;
#ifdef SQLITE_ENABLE_API_ARMOR
if( pStmt==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
ret = 0;
p = (Vdbe *)pStmt;
db = p->db;
assert( db!=0 );
n = sqlite3_column_count(pStmt);
if( N<n && N>=0 ){
@ -1435,6 +1443,12 @@ int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
*/
sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
sqlite3_stmt *pNext;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(pDb) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
sqlite3_mutex_enter(pDb->mutex);
if( pStmt==0 ){
pNext = (sqlite3_stmt*)pDb->pVdbe;
@ -1450,7 +1464,14 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
*/
int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
Vdbe *pVdbe = (Vdbe*)pStmt;
u32 v = pVdbe->aCounter[op];
u32 v;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !pStmt ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
v = pVdbe->aCounter[op];
if( resetFlag ) pVdbe->aCounter[op] = 0;
return (int)v;
}

View File

@ -1773,6 +1773,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
v->nCursor = pFrame->nCursor;
v->db->lastRowid = pFrame->lastRowid;
v->nChange = pFrame->nChange;
v->db->nChange = pFrame->nDbChange;
return pFrame->pc;
}
@ -2340,6 +2341,7 @@ int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
p->nChange = 0;
}
}
}
@ -2380,6 +2382,7 @@ int sqlite3VdbeHalt(Vdbe *p){
}else if( rc!=SQLITE_OK ){
p->rc = rc;
sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
}else{
db->nDeferredCons = 0;
db->nDeferredImmCons = 0;
@ -2388,6 +2391,7 @@ int sqlite3VdbeHalt(Vdbe *p){
}
}else{
sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
}
db->nStatement = 0;
}else if( eStatementOp==0 ){
@ -2399,6 +2403,7 @@ int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
p->nChange = 0;
}
}
@ -2419,6 +2424,7 @@ int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
p->nChange = 0;
}
}

View File

@ -155,6 +155,11 @@ int sqlite3_blob_open(
Parse *pParse = 0;
Incrblob *pBlob = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || ppBlob==0 || zTable==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
flags = !!flags; /* flags = (flags ? 1 : 0); */
*ppBlob = 0;

View File

@ -81,6 +81,9 @@ int sqlite3_create_module(
const sqlite3_module *pModule, /* The definition of the module */
void *pAux /* Context pointer for xCreate/xConnect */
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
#endif
return createModule(db, zName, pModule, pAux, 0);
}
@ -94,6 +97,9 @@ int sqlite3_create_module_v2(
void *pAux, /* Context pointer for xCreate/xConnect */
void (*xDestroy)(void *) /* Module destructor function */
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
#endif
return createModule(db, zName, pModule, pAux, xDestroy);
}
@ -698,6 +704,9 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
Table *pTab;
char *zErr = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
sqlite3Error(db, SQLITE_MISUSE);
@ -1054,6 +1063,9 @@ int sqlite3_vtab_on_conflict(sqlite3 *db){
static const unsigned char aMap[] = {
SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
};
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 );
assert( OE_Ignore==4 && OE_Replace==5 );
assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 );
@ -1069,8 +1081,10 @@ int sqlite3_vtab_config(sqlite3 *db, int op, ...){
va_list ap;
int rc = SQLITE_OK;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
va_start(ap, op);
switch( op ){
case SQLITE_VTAB_CONSTRAINT_SUPPORT: {

View File

@ -225,7 +225,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
}
pTerm = &pWC->a[idx = pWC->nTerm++];
if( p && ExprHasProperty(p, EP_Unlikely) ){
pTerm->truthProb = sqlite3LogEst(p->iTable) - 99;
pTerm->truthProb = sqlite3LogEst(p->iTable) - 270;
}else{
pTerm->truthProb = 1;
}
@ -756,6 +756,15 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
}
}
/*
** Mark term iChild as being a child of term iParent
*/
static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){
pWC->a[iChild].iParent = iParent;
pWC->a[iChild].truthProb = pWC->a[iParent].truthProb;
pWC->a[iParent].nChild++;
}
#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
/*
** Analyze a term that consists of two or more OR-connected
@ -1053,8 +1062,7 @@ static void exprAnalyzeOrTerm(
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
pWC->a[idxNew].iParent = idxTerm;
pTerm->nChild = 1;
markTermAsChild(pWC, idxNew, idxTerm);
}else{
sqlite3ExprListDelete(db, pList);
}
@ -1156,9 +1164,8 @@ static void exprAnalyze(
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
if( idxNew==0 ) return;
pNew = &pWC->a[idxNew];
pNew->iParent = idxTerm;
markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
if( pExpr->op==TK_EQ
&& !ExprHasProperty(pExpr, EP_FromJoin)
@ -1215,9 +1222,8 @@ static void exprAnalyze(
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
pWC->a[idxNew].iParent = idxTerm;
markTermAsChild(pWC, idxNew, idxTerm);
}
pTerm->nChild = 2;
}
#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */
@ -1292,9 +1298,8 @@ static void exprAnalyze(
exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
if( isComplete ){
pWC->a[idxNew1].iParent = idxTerm;
pWC->a[idxNew2].iParent = idxTerm;
pTerm->nChild = 2;
markTermAsChild(pWC, idxNew1, idxTerm);
markTermAsChild(pWC, idxNew2, idxTerm);
}
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
@ -1327,9 +1332,8 @@ static void exprAnalyze(
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_MATCH;
pNewTerm->iParent = idxTerm;
markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
}
@ -1350,7 +1354,7 @@ static void exprAnalyze(
if( pExpr->op==TK_NOTNULL
&& pExpr->pLeft->op==TK_COLUMN
&& pExpr->pLeft->iColumn>=0
&& OptimizationEnabled(db, SQLITE_Stat3)
&& OptimizationEnabled(db, SQLITE_Stat34)
){
Expr *pNewExpr;
Expr *pLeft = pExpr->pLeft;
@ -1369,9 +1373,8 @@ static void exprAnalyze(
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_GT;
pNewTerm->iParent = idxTerm;
markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
}
@ -1591,6 +1594,8 @@ static void constructAutomaticIndex(
Bitmask idxCols; /* Bitmap of columns used for indexing */
Bitmask extraCols; /* Bitmap of additional columns */
u8 sentWarning = 0; /* True if a warnning has been issued */
Expr *pPartial = 0; /* Partial Index Expression */
int iContinue = 0; /* Jump here to skip excluded rows */
/* Generate code to skip over the creation and initialization of the
** transient index on 2nd and subsequent iterations of the loop. */
@ -1606,6 +1611,12 @@ static void constructAutomaticIndex(
pLoop = pLevel->pWLoop;
idxCols = 0;
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( pLoop->prereq==0
&& (pTerm->wtFlags & TERM_VIRTUAL)==0
&& sqlite3ExprIsTableConstant(pTerm->pExpr, pSrc->iCursor) ){
pPartial = sqlite3ExprAnd(pParse->db, pPartial,
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
}
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
int iCol = pTerm->u.leftColumn;
Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
@ -1618,7 +1629,9 @@ static void constructAutomaticIndex(
sentWarning = 1;
}
if( (idxCols & cMask)==0 ){
if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ) return;
if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ){
goto end_auto_index_create;
}
pLoop->aLTerm[nKeyCol++] = pTerm;
idxCols |= cMask;
}
@ -1638,7 +1651,7 @@ static void constructAutomaticIndex(
** if they go out of sync.
*/
extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol;
mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
for(i=0; i<mxBitCol; i++){
@ -1647,11 +1660,10 @@ static void constructAutomaticIndex(
if( pSrc->colUsed & MASKBIT(BMS-1) ){
nKeyCol += pTable->nCol - BMS + 1;
}
pLoop->wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY;
/* Construct the Index object to describe this index */
pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed);
if( pIdx==0 ) return;
if( pIdx==0 ) goto end_auto_index_create;
pLoop->u.btree.pIndex = pIdx;
pIdx->zName = "auto-index";
pIdx->pTable = pTable;
@ -1703,18 +1715,29 @@ static void constructAutomaticIndex(
VdbeComment((v, "for %s", pTable->zName));
/* Fill the automatic index with content */
sqlite3ExprCachePush(pParse);
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
if( pPartial ){
iContinue = sqlite3VdbeMakeLabel(v);
sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL);
pLoop->wsFlags |= WHERE_PARTIALIDX;
}
regRecord = sqlite3GetTempReg(pParse);
sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
sqlite3VdbeJumpHere(v, addrTop);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ExprCachePop(pParse);
/* Jump here when skipping the initialization */
sqlite3VdbeJumpHere(v, addrInit);
end_auto_index_create:
sqlite3ExprDelete(pParse->db, pPartial);
}
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
@ -2159,7 +2182,6 @@ static int whereRangeScanEst(
if( p->nSample>0
&& nEq<p->nSampleCol
&& OptimizationEnabled(pParse->db, SQLITE_Stat3)
){
if( nEq==pBuilder->nRecValid ){
UnpackedRecord *pRec = pBuilder->pRec;
@ -2198,7 +2220,7 @@ static int whereRangeScanEst(
/* Determine iLower and iUpper using ($P) only. */
if( nEq==0 ){
iLower = 0;
iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]);
iUpper = p->nRowEst0;
}else{
/* Note: this call could be optimized away - since the same values must
** have been requested when testing key $P in whereEqualScanEst(). */
@ -2273,12 +2295,15 @@ static int whereRangeScanEst(
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
/* TUNING: If there is both an upper and lower limit, assume the range is
/* TUNING: If there is both an upper and lower limit and neither limit
** has an application-defined likelihood(), assume the range is
** reduced by an additional 75%. This means that, by default, an open-ended
** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the
** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to
** match 1/64 of the index. */
if( pLower && pUpper ) nNew -= 20;
if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){
nNew -= 20;
}
nOut -= (pLower!=0) + (pUpper!=0);
if( nNew<10 ) nNew = 10;
@ -2638,7 +2663,7 @@ static int codeAllEqualityTerms(
pLoop = pLevel->pWLoop;
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
nEq = pLoop->u.btree.nEq;
nSkip = pLoop->u.btree.nSkip;
nSkip = pLoop->nSkip;
pIdx = pLoop->u.btree.pIndex;
assert( pIdx!=0 );
@ -2752,7 +2777,7 @@ static void explainAppendTerm(
static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
Index *pIndex = pLoop->u.btree.pIndex;
u16 nEq = pLoop->u.btree.nEq;
u16 nSkip = pLoop->u.btree.nSkip;
u16 nSkip = pLoop->nSkip;
int i, j;
Column *aCol = pTab->aCol;
i16 *aiColumn = pIndex->aiColumn;
@ -2841,6 +2866,8 @@ static void explainOneScan(
if( isSearch ){
zFmt = "PRIMARY KEY";
}
}else if( flags & WHERE_PARTIALIDX ){
zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
}else if( flags & WHERE_AUTO_INDEX ){
zFmt = "AUTOMATIC COVERING INDEX";
}else if( flags & WHERE_IDX_ONLY ){
@ -3189,7 +3216,7 @@ static Bitmask codeOneLoopStart(
pIdx = pLoop->u.btree.pIndex;
iIdxCur = pLevel->iIdxCur;
assert( nEq>=pLoop->u.btree.nSkip );
assert( nEq>=pLoop->nSkip );
/* If this loop satisfies a sort order (pOrderBy) request that
** was passed to this function to implement a "SELECT min(x) ..."
@ -3206,7 +3233,7 @@ static Bitmask codeOneLoopStart(
&& pWInfo->nOBSat>0
&& (pIdx->nKeyCol>nEq)
){
assert( pLoop->u.btree.nSkip==0 );
assert( pLoop->nSkip==0 );
bSeekPastNull = 1;
nExtraReg = 1;
}
@ -3827,7 +3854,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
sqlite3_free(z);
}
if( p->wsFlags & WHERE_SKIPSCAN ){
sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->u.btree.nSkip);
sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
}else{
sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
}
@ -3956,12 +3983,15 @@ static int whereLoopCheaperProperSubset(
const WhereLoop *pY /* Compare against this WhereLoop */
){
int i, j;
if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */
if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
return 0; /* X is not a subset of Y */
}
if( pX->rRun >= pY->rRun ){
if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
}
for(i=pX->nLTerm-1; i>=0; i--){
if( pX->aLTerm[i]==0 ) continue;
for(j=pY->nLTerm-1; j>=0; j--){
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
}
@ -3983,33 +4013,26 @@ static int whereLoopCheaperProperSubset(
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
** WHERE clause terms than Y and that every WHERE clause term used by X is
** also used by Y.
**
** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the
** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE
** clause terms covered, since some of the first nLTerm entries in aLTerm[]
** will be NULL (because they are skipped). That makes it more difficult
** to compare the loops. We could add extra code to do the comparison, and
** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this
** adjustment is sufficient minor, that it is very difficult to construct
** a test case where the extra code would improve the query plan. Better
** to avoid the added complexity and just omit cost adjustments to SKIPSCAN
** loops.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return;
for(; p; p=p->pNextLoop){
if( p->iTab!=pTemplate->iTab ) continue;
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue;
if( whereLoopCheaperProperSubset(p, pTemplate) ){
/* Adjust pTemplate cost downward so that it is cheaper than its
** subset p */
** subset p. Except, do not adjust the cost estimate downward for
** a loop that skips more columns. */
if( pTemplate->nSkip>p->nSkip ) continue;
WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1));
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut - 1;
}else if( whereLoopCheaperProperSubset(pTemplate, p) ){
/* Adjust pTemplate cost upward so that it is costlier than p since
** pTemplate is a proper subset of p */
WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1));
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut + 1;
}
@ -4295,7 +4318,7 @@ static int whereLoopAddBtreeIndex(
Bitmask saved_prereq; /* Original value of pNew->prereq */
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
u16 saved_nEq; /* Original value of pNew->u.btree.nEq */
u16 saved_nSkip; /* Original value of pNew->u.btree.nSkip */
u16 saved_nSkip; /* Original value of pNew->nSkip */
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
LogEst saved_nOut; /* Original value of pNew->nOut */
int iCol; /* Index of the column in the table */
@ -4324,7 +4347,7 @@ static int whereLoopAddBtreeIndex(
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
opMask, pProbe);
saved_nEq = pNew->u.btree.nEq;
saved_nSkip = pNew->u.btree.nSkip;
saved_nSkip = pNew->nSkip;
saved_nLTerm = pNew->nLTerm;
saved_wsFlags = pNew->wsFlags;
saved_prereq = pNew->prereq;
@ -4332,44 +4355,6 @@ static int whereLoopAddBtreeIndex(
pNew->rSetup = 0;
rSize = pProbe->aiRowLogEst[0];
rLogSize = estLog(rSize);
/* Consider using a skip-scan if there are no WHERE clause constraints
** available for the left-most terms of the index, and if the average
** number of repeats in the left-most terms is at least 18.
**
** The magic number 18 is selected on the basis that scanning 17 rows
** is almost always quicker than an index seek (even though if the index
** contains fewer than 2^17 rows we assume otherwise in other parts of
** the code). And, even if it is not, it should not be too much slower.
** On the other hand, the extra seeks could end up being significantly
** more expensive. */
assert( 42==sqlite3LogEst(18) );
if( saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
){
LogEst nIter;
pNew->u.btree.nEq++;
pNew->u.btree.nSkip++;
pNew->aLTerm[pNew->nLTerm++] = 0;
pNew->wsFlags |= WHERE_SKIPSCAN;
nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
if( pTerm ){
/* TUNING: When estimating skip-scan for a term that is also indexable,
** multiply the cost of the skip-scan by 2.0, to make it a little less
** desirable than the regular index lookup. */
nIter += 10; assert( 10==sqlite3LogEst(2) );
}
pNew->nOut -= nIter;
/* TUNING: Because uncertainties in the estimates for skip-scan queries,
** add a 1.375 fudge factor to make skip-scan slightly less likely. */
nIter += 5;
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
pNew->nOut = saved_nOut;
pNew->u.btree.nEq = saved_nEq;
pNew->u.btree.nSkip = saved_nSkip;
}
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */
LogEst rCostIdx;
@ -4464,7 +4449,6 @@ static int whereLoopAddBtreeIndex(
if( nInMul==0
&& pProbe->nSample
&& pNew->u.btree.nEq<=pProbe->nSampleCol
&& OptimizationEnabled(db, SQLITE_Stat3)
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
){
Expr *pExpr = pTerm->pExpr;
@ -4532,10 +4516,44 @@ static int whereLoopAddBtreeIndex(
}
pNew->prereq = saved_prereq;
pNew->u.btree.nEq = saved_nEq;
pNew->u.btree.nSkip = saved_nSkip;
pNew->nSkip = saved_nSkip;
pNew->wsFlags = saved_wsFlags;
pNew->nOut = saved_nOut;
pNew->nLTerm = saved_nLTerm;
/* Consider using a skip-scan if there are no WHERE clause constraints
** available for the left-most terms of the index, and if the average
** number of repeats in the left-most terms is at least 18.
**
** The magic number 18 is selected on the basis that scanning 17 rows
** is almost always quicker than an index seek (even though if the index
** contains fewer than 2^17 rows we assume otherwise in other parts of
** the code). And, even if it is not, it should not be too much slower.
** On the other hand, the extra seeks could end up being significantly
** more expensive. */
assert( 42==sqlite3LogEst(18) );
if( saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
){
LogEst nIter;
pNew->u.btree.nEq++;
pNew->nSkip++;
pNew->aLTerm[pNew->nLTerm++] = 0;
pNew->wsFlags |= WHERE_SKIPSCAN;
nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
pNew->nOut -= nIter;
/* TUNING: Because uncertainties in the estimates for skip-scan queries,
** add a 1.375 fudge factor to make skip-scan slightly less likely. */
nIter += 5;
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
pNew->nOut = saved_nOut;
pNew->u.btree.nEq = saved_nEq;
pNew->nSkip = saved_nSkip;
pNew->wsFlags = saved_wsFlags;
}
return rc;
}
@ -4714,7 +4732,7 @@ static int whereLoopAddBtree(
if( pTerm->prereqRight & pNew->maskSelf ) continue;
if( termCanDriveIndex(pTerm, pSrc, 0) ){
pNew->u.btree.nEq = 1;
pNew->u.btree.nSkip = 0;
pNew->nSkip = 0;
pNew->u.btree.pIndex = 0;
pNew->nLTerm = 1;
pNew->aLTerm[0] = pTerm;
@ -4755,7 +4773,7 @@ static int whereLoopAddBtree(
}
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
pNew->u.btree.nSkip = 0;
pNew->nSkip = 0;
pNew->nLTerm = 0;
pNew->iSortIdx = 0;
pNew->rSetup = 0;
@ -5305,7 +5323,7 @@ static i8 wherePathSatisfiesOrderBy(
/* Skip over == and IS NULL terms */
if( j<pLoop->u.btree.nEq
&& pLoop->u.btree.nSkip==0
&& pLoop->nSkip==0
&& ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
){
if( i & WO_ISNULL ){
@ -5759,7 +5777,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
#ifdef WHERETRACE_ENABLED /* >=2 */
if( sqlite3WhereTrace>=2 ){
if( sqlite3WhereTrace & 0x02 ){
sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
@ -5878,7 +5896,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pWC = &pWInfo->sWC;
pLoop = pBuilder->pNew;
pLoop->wsFlags = 0;
pLoop->u.btree.nSkip = 0;
pLoop->nSkip = 0;
pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0);
if( pTerm ){
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
@ -5890,7 +5908,6 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pLoop->aLTermSpace==pLoop->aLTerm );
assert( ArraySize(pLoop->aLTermSpace)==4 );
if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)

View File

@ -115,7 +115,6 @@ struct WhereLoop {
union {
struct { /* Information for internal btree tables */
u16 nEq; /* Number of equality constraints */
u16 nSkip; /* Number of initial index columns to skip */
Index *pIndex; /* Index used, or NULL */
} btree;
struct { /* Information for virtual tables */
@ -128,12 +127,13 @@ struct WhereLoop {
} u;
u32 wsFlags; /* WHERE_* flags describing the plan */
u16 nLTerm; /* Number of entries in aLTerm[] */
u16 nSkip; /* Number of NULL aLTerm[] entries */
/**** whereLoopXfer() copies fields above ***********************/
# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot)
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
WhereTerm **aLTerm; /* WhereTerms used */
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */
};
/* This object holds the prerequisites and the cost of running a
@ -459,3 +459,4 @@ struct WhereInfo {
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */

52
test/autoindex4.test Normal file
View File

@ -0,0 +1,52 @@
# 2014-10-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 script is testing automatic index creation logic,
# and specifically creation of automatic partial indexes.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test autoindex4-1.0 {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(123,'abc'),(234,'def'),(234,'ghi'),(345,'jkl');
CREATE TABLE t2(x,y);
INSERT INTO t2 VALUES(987,'zyx'),(654,'wvu'),(987,'rqp');
SELECT *, '|' FROM t1, t2 WHERE a=234 AND x=987 ORDER BY +b;
} {234 def 987 rqp | 234 def 987 zyx | 234 ghi 987 rqp | 234 ghi 987 zyx |}
do_execsql_test autoindex4-1.1 {
SELECT *, '|' FROM t1, t2 WHERE a=234 AND x=555;
} {}
do_execsql_test autoindex4-1.2 {
SELECT *, '|' FROM t1 LEFT JOIN t2 ON a=234 AND x=555;
} {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |}
do_execsql_test autoindex4-1.3 {
SELECT *, '|' FROM t1 LEFT JOIN t2 ON x=555 WHERE a=234;
} {234 def {} {} | 234 ghi {} {} |}
do_execsql_test autoindex4-1.4 {
SELECT *, '|' FROM t1 LEFT JOIN t2 WHERE a=234 AND x=555;
} {}
do_execsql_test autoindex4-2.0 {
CREATE TABLE t3(e,f);
INSERT INTO t3 VALUES(123,654),(555,444),(234,987);
SELECT (SELECT count(*) FROM t1, t2 WHERE a=e AND x=f), e, f, '|'
FROM t3
ORDER BY rowid;
} {1 123 654 | 0 555 444 | 4 234 987 |}
finish_test

441
test/e_changes.test Normal file
View File

@ -0,0 +1,441 @@
# 2011 October 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix e_changes
# Like [do_execsql_test], except it appends the value returned by
# [db changes] to the result of executing the SQL script.
#
proc do_changes_test {tn sql res} {
uplevel [list \
do_test $tn "concat \[execsql {$sql}\] \[db changes\]" $res
]
}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-15996-49369 This function returns the number of rows
# modified, inserted or deleted by the most recently completed INSERT,
# UPDATE or DELETE statement on the database connection specified by the
# only parameter.
#
do_execsql_test 1.0 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID;
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t2(y);
}
foreach {tn schema} {
1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(b);
}
2 {
CREATE TABLE t1(a, b, PRIMARY KEY(a, b)) WITHOUT ROWID;
CREATE INDEX i1 ON t1(b);
}
} {
reset_db
execsql $schema
# Insert 1 row.
do_changes_test 1.$tn.1 { INSERT INTO t1 VALUES(0, 0) } 1
# Insert 10 rows.
do_changes_test 1.$tn.2 {
WITH rows(i, j) AS (
SELECT 1, 1 UNION ALL SELECT i+1, j+i FROM rows WHERE i<10
)
INSERT INTO t1 SELECT * FROM rows
} 10
# Modify 5 rows.
do_changes_test 1.$tn.3 {
UPDATE t1 SET b=b+1 WHERE a<5;
} 5
# Delete 4 rows
do_changes_test 1.$tn.4 {
DELETE FROM t1 WHERE a>6
} 4
# Check the "on the database connecton specified" part of hte
# requirement - changes made by other connections do not show up in
# the return value of sqlite3_changes().
do_test 1.$tn.5 {
sqlite3 db2 test.db
execsql { INSERT INTO t1 VALUES(-1, -1) } db2
db2 changes
} 1
do_test 1.$tn.6 {
db changes
} 4
db2 close
# Test that statements that modify no rows because they hit UNIQUE
# constraints set the sqlite3_changes() value to 0. Regardless of
# whether or not they are executed inside an explicit transaction.
#
# 1.$tn.8-9: outside of a transaction
# 1.$tn.10-12: inside a transaction
#
do_changes_test 1.$tn.7 {
CREATE UNIQUE INDEX i2 ON t1(a);
} 4
do_catchsql_test 1.$tn.8 {
INSERT INTO t1 VALUES('a', 0), ('b', 0), ('c', 0), (0, 11);
} {1 {UNIQUE constraint failed: t1.a}}
do_test 1.$tn.9 { db changes } 0
do_catchsql_test 1.$tn.10 {
BEGIN;
INSERT INTO t1 VALUES('a', 0), ('b', 0), ('c', 0), (0, 11);
} {1 {UNIQUE constraint failed: t1.a}}
do_test 1.$tn.11 { db changes } 0
do_changes_test 1.$tn.12 COMMIT 0
}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-44877-05564 Executing any other type of SQL statement
# does not modify the value returned by this function.
#
reset_db
do_changes_test 2.1 { CREATE TABLE t1(x) } 0
do_changes_test 2.2 {
WITH d(y) AS (SELECT 1 UNION ALL SELECT y+1 FROM d WHERE y<47)
INSERT INTO t1 SELECT y FROM d;
} 47
# The statement above set changes() to 47. Check that none of the following
# modify this.
do_changes_test 2.3 { SELECT count(x) FROM t1 } {47 47}
do_changes_test 2.4 { DROP TABLE t1 } 47
do_changes_test 2.5 { CREATE TABLE t1(x) } 47
do_changes_test 2.6 { ALTER TABLE t1 ADD COLUMN b } 47
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-53938-27527 Only changes made directly by the INSERT,
# UPDATE or DELETE statement are considered - auxiliary changes caused
# by triggers, foreign key actions or REPLACE constraint resolution are
# not counted.
#
# 3.1.*: triggers
# 3.2.*: foreign key actions
# 3.3.*: replace constraints
#
reset_db
do_execsql_test 3.1.0 {
CREATE TABLE log(x);
CREATE TABLE p1(one PRIMARY KEY, two);
CREATE TRIGGER tr_ai AFTER INSERT ON p1 BEGIN
INSERT INTO log VALUES('insert');
END;
CREATE TRIGGER tr_bd BEFORE DELETE ON p1 BEGIN
INSERT INTO log VALUES('delete');
END;
CREATE TRIGGER tr_au AFTER UPDATE ON p1 BEGIN
INSERT INTO log VALUES('update');
END;
}
do_changes_test 3.1.1 {
INSERT INTO p1 VALUES('a', 'A'), ('b', 'B'), ('c', 'C');
} 3
do_changes_test 3.1.2 {
UPDATE p1 SET two = two||two;
} 3
do_changes_test 3.1.3 {
DELETE FROM p1 WHERE one IN ('a', 'c');
} 2
do_execsql_test 3.1.4 {
-- None of the inserts on table log were counted.
SELECT count(*) FROM log
} 8
do_execsql_test 3.2.0 {
DELETE FROM p1;
INSERT INTO p1 VALUES('a', 'A'), ('b', 'B'), ('c', 'C');
CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET NULL);
CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET DEFAULT);
CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE CASCADE);
INSERT INTO c1 VALUES('a', 'aaa');
INSERT INTO c2 VALUES('b', 'bbb');
INSERT INTO c3 VALUES('c', 'ccc');
INSERT INTO p1 VALUES('d', 'D'), ('e', 'E'), ('f', 'F');
CREATE TABLE c4(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET NULL);
CREATE TABLE c5(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET DEFAULT);
CREATE TABLE c6(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE CASCADE);
INSERT INTO c4 VALUES('d', 'aaa');
INSERT INTO c5 VALUES('e', 'bbb');
INSERT INTO c6 VALUES('f', 'ccc');
PRAGMA foreign_keys = ON;
}
do_changes_test 3.2.1 { DELETE FROM p1 WHERE one = 'a' } 1
do_changes_test 3.2.2 { DELETE FROM p1 WHERE one = 'b' } 1
do_changes_test 3.2.3 { DELETE FROM p1 WHERE one = 'c' } 1
do_execsql_test 3.2.4 {
SELECT * FROM c1;
SELECT * FROM c2;
SELECT * FROM c3;
} {{} aaa {} bbb}
do_changes_test 3.2.5 { UPDATE p1 SET one = 'g' WHERE one = 'd' } 1
do_changes_test 3.2.6 { UPDATE p1 SET one = 'h' WHERE one = 'e' } 1
do_changes_test 3.2.7 { UPDATE p1 SET one = 'i' WHERE one = 'f' } 1
do_execsql_test 3.2.8 {
SELECT * FROM c4;
SELECT * FROM c5;
SELECT * FROM c6;
} {{} aaa {} bbb i ccc}
do_execsql_test 3.3.0 {
CREATE TABLE r1(a UNIQUE, b UNIQUE);
INSERT INTO r1 VALUES('i', 'i');
INSERT INTO r1 VALUES('ii', 'ii');
INSERT INTO r1 VALUES('iii', 'iii');
INSERT INTO r1 VALUES('iv', 'iv');
INSERT INTO r1 VALUES('v', 'v');
INSERT INTO r1 VALUES('vi', 'vi');
INSERT INTO r1 VALUES('vii', 'vii');
}
do_changes_test 3.3.1 { INSERT OR REPLACE INTO r1 VALUES('i', 1) } 1
do_changes_test 3.3.2 { INSERT OR REPLACE INTO r1 VALUES('iv', 'v') } 1
do_changes_test 3.3.3 { UPDATE OR REPLACE r1 SET b='v' WHERE a='iii' } 1
do_changes_test 3.3.4 { UPDATE OR REPLACE r1 SET b='vi',a='vii' WHERE a='ii' } 1
do_execsql_test 3.3.5 {
SELECT * FROM r1 ORDER BY a;
} {i 1 iii v vii vi}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-09813-48563 The value returned by sqlite3_changes()
# immediately after an INSERT, UPDATE or DELETE statement run on a view
# is always zero.
#
reset_db
do_execsql_test 4.1 {
CREATE TABLE log(log);
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
INSERT INTO t1 VALUES(5, 6);
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE TRIGGER v1_i INSTEAD OF INSERT ON v1 BEGIN
INSERT INTO log VALUES('insert');
END;
CREATE TRIGGER v1_u INSTEAD OF UPDATE ON v1 BEGIN
INSERT INTO log VALUES('update'), ('update');
END;
CREATE TRIGGER v1_d INSTEAD OF DELETE ON v1 BEGIN
INSERT INTO log VALUES('delete'), ('delete'), ('delete');
END;
}
do_changes_test 4.2.1 { INSERT INTO t1 SELECT * FROM t1 } 3
do_changes_test 4.2.2 { INSERT INTO v1 VALUES(1, 2) } 0
do_changes_test 4.3.1 { INSERT INTO t1 SELECT * FROM t1 } 6
do_changes_test 4.3.2 { UPDATE v1 SET y='xyz' WHERE x=1 } 0
do_changes_test 4.4.1 { INSERT INTO t1 SELECT * FROM t1 } 12
do_changes_test 4.4.2 { DELETE FROM v1 WHERE x=5 } 0
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-32918-61474 Before entering a trigger program the value
# returned by sqlite3_changes() function is saved. After the trigger
# program has finished, the original value is restored.
#
reset_db
db func my_changes my_changes
set ::changes [list]
proc my_changes {x} {
set res [db changes]
lappend ::changes $x $res
return $res
}
do_execsql_test 5.1.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE TABLE t2(x);
INSERT INTO t1 VALUES(1, NULL);
INSERT INTO t1 VALUES(2, NULL);
INSERT INTO t1 VALUES(3, NULL);
CREATE TRIGGER AFTER UPDATE ON t1 BEGIN
INSERT INTO t2 VALUES('a'), ('b'), ('c');
SELECT my_changes('trigger');
END;
}
do_execsql_test 5.1.1 {
INSERT INTO t2 VALUES('a'), ('b');
UPDATE t1 SET b = my_changes('update');
SELECT * FROM t1;
} {1 2 2 2 3 2}
# Value is being restored to "2" when the trigger program exits.
do_test 5.1.2 {
set ::changes
} {update 2 trigger 3 update 2 trigger 3 update 2 trigger 3}
reset_db
do_execsql_test 5.2.0 {
CREATE TABLE t1(a, b);
CREATE TABLE log(x);
INSERT INTO t1 VALUES(1, 0);
INSERT INTO t1 VALUES(2, 0);
INSERT INTO t1 VALUES(3, 0);
CREATE TRIGGER t1_a_u AFTER UPDATE ON t1 BEGIN
INSERT INTO log VALUES(old.b || ' -> ' || new.b || ' c = ' || changes() );
END;
CREATE TABLE t2(a);
INSERT INTO t2 VALUES(1), (2), (3);
UPDATE t1 SET b = changes();
}
do_execsql_test 5.2.1 {
SELECT * FROM t1;
} {1 3 2 3 3 3}
do_execsql_test 5.2.2 {
SELECT * FROM log;
} {{0 -> 3 c = 3} {0 -> 3 c = 3} {0 -> 3 c = 3}}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-17146-37073 Within a trigger program each INSERT,
# UPDATE and DELETE statement sets the value returned by
# sqlite3_changes() upon completion as normal. Of course, this value
# will not include any changes performed by sub-triggers, as the
# sqlite3_changes() value will be saved and restored after each
# sub-trigger has run.
reset_db
do_execsql_test 6.0 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(a, b);
CREATE TABLE t3(a, b);
CREATE TABLE log(x);
CREATE TRIGGER t1_i BEFORE INSERT ON t1 BEGIN
INSERT INTO t2 VALUES(new.a, new.b), (new.a, new.b);
INSERT INTO log VALUES('t2->' || changes());
END;
CREATE TRIGGER t2_i AFTER INSERT ON t2 BEGIN
INSERT INTO t3 VALUES(new.a, new.b), (new.a, new.b), (new.a, new.b);
INSERT INTO log VALUES('t3->' || changes());
END;
CREATE TRIGGER t1_u AFTER UPDATE ON t1 BEGIN
UPDATE t2 SET b=new.b WHERE a=old.a;
INSERT INTO log VALUES('t2->' || changes());
END;
CREATE TRIGGER t2_u BEFORE UPDATE ON t2 BEGIN
UPDATE t3 SET b=new.b WHERE a=old.a;
INSERT INTO log VALUES('t3->' || changes());
END;
CREATE TRIGGER t1_d AFTER DELETE ON t1 BEGIN
DELETE FROM t2 WHERE a=old.a AND b=old.b;
INSERT INTO log VALUES('t2->' || changes());
END;
CREATE TRIGGER t2_d BEFORE DELETE ON t2 BEGIN
DELETE FROM t3 WHERE a=old.a AND b=old.b;
INSERT INTO log VALUES('t3->' || changes());
END;
}
do_changes_test 6.1 {
INSERT INTO t1 VALUES('+', 'o');
SELECT * FROM log;
} {t3->3 t3->3 t2->2 1}
do_changes_test 6.2 {
DELETE FROM log;
UPDATE t1 SET b='*';
SELECT * FROM log;
} {t3->6 t3->6 t2->2 1}
do_changes_test 6.3 {
DELETE FROM log;
DELETE FROM t1;
SELECT * FROM log;
} {t3->6 t3->0 t2->2 1}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-43399-09409 This means that if the changes() SQL
# function (or similar) is used by the first INSERT, UPDATE or DELETE
# statement within a trigger, it returns the value as set when the
# calling statement began executing.
#
# EVIDENCE-OF: R-53215-27584 If it is used by the second or subsequent
# such statement within a trigger program, the value returned reflects
# the number of rows modified by the previous INSERT, UPDATE or DELETE
# statement within the same trigger.
#
reset_db
do_execsql_test 7.1 {
CREATE TABLE q1(t);
CREATE TABLE q2(u, v);
CREATE TABLE q3(w);
CREATE TRIGGER q2_insert BEFORE INSERT ON q2 BEGIN
/* changes() returns value from previous I/U/D in callers context */
INSERT INTO q1 VALUES('1:' || changes());
/* changes() returns value of previous I/U/D in this context */
INSERT INTO q3 VALUES(changes()), (2), (3);
INSERT INTO q1 VALUES('2:' || changes());
INSERT INTO q3 VALUES(changes() + 3), (changes()+4);
SELECT 'this does not affect things!';
INSERT INTO q1 VALUES('3:' || changes());
UPDATE q3 SET w = w+10 WHERE w%2;
INSERT INTO q1 VALUES('4:' || changes());
DELETE FROM q3;
INSERT INTO q1 VALUES('5:' || changes());
END;
}
do_execsql_test 7.2 {
INSERT INTO q2 VALUES('x', 'y');
SELECT * FROM q1;
} {
1:0 2:3 3:2 4:3 5:5
}
do_execsql_test 7.3 {
DELETE FROM q1;
INSERT INTO q2 VALUES('x', 'y');
SELECT * FROM q1;
} {
1:5 2:3 3:2 4:3 5:5
}
finish_test

213
test/e_totalchanges.test Normal file
View File

@ -0,0 +1,213 @@
# 2011 May 06
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix e_totalchanges
# Like [do_execsql_test], except it appends the value returned by
# [db total_changes] to the result of executing the SQL script.
#
proc do_tc_test {tn sql res} {
uplevel [list \
do_test $tn "concat \[execsql {$sql}\] \[db total_changes\]" $res
]
}
do_execsql_test 1.0 {
CREATE TABLE t1(a, b);
CREATE INDEX t1_b ON t1(b);
CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID;
CREATE INDEX t2_y ON t2(y);
}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-65438-26258 This function returns the total number of
# rows inserted, modified or deleted by all INSERT, UPDATE or DELETE
# statements completed since the database connection was opened,
# including those executed as part of trigger programs.
#
# 1.1.*: different types of I/U/D statements,
# 1.2.*: trigger programs.
#
do_tc_test 1.1.1 {
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
UPDATE t1 SET a = a+1;
DELETE FROM t1;
} {6}
do_tc_test 1.1.2 {
DELETE FROM t1
} {6}
do_tc_test 1.1.3 {
WITH data(a,b) AS (
SELECT 0, 0 UNION ALL SELECT a+1, b+1 FROM data WHERE a<99
)
INSERT INTO t1 SELECT * FROM data;
} {106}
do_tc_test 1.1.4 {
INSERT INTO t2 SELECT * FROM t1 WHERE a<50;
UPDATE t2 SET y=y+1;
} {206}
do_tc_test 1.1.5 {
DELETE FROM t2 WHERE y<=25
} {231}
do_execsql_test 1.2.1 {
DELETE FROM t1;
DELETE FROM t2;
}
sqlite3 db test.db ; # To reset total_changes
do_tc_test 1.2.2 {
CREATE TABLE log(detail);
CREATE TRIGGER t1_after_insert AFTER INSERT ON t1 BEGIN
INSERT INTO log VALUES('inserted into t1');
END;
CREATE TRIGGER t1_before_delete BEFORE DELETE ON t1 BEGIN
INSERT INTO log VALUES('deleting from t1');
INSERT INTO log VALUES('here we go!');
END;
CREATE TRIGGER t1_after_update AFTER UPDATE ON t1 BEGIN
INSERT INTO log VALUES('update');
DELETE FROM log;
END;
INSERT INTO t1 VALUES('a', 'b'); -- 1 + 1
UPDATE t1 SET b='c'; -- 1 + 1 + 2
DELETE FROM t1; -- 1 + 1 + 1
} {9}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-61766-15253 Executing any other type of SQL statement
# does not affect the value returned by sqlite3_total_changes().
do_tc_test 2.1 {
INSERT INTO t1 VALUES(1, 2), (3, 4);
INSERT INTO t2 VALUES(1, 2), (3, 4);
} {15}
do_tc_test 2.2 {
SELECT count(*) FROM t1;
} {2 15}
do_tc_test 2.3 {
CREATE TABLE t4(a, b);
ALTER TABLE t4 ADD COLUMN c;
CREATE INDEX i4 ON t4(c);
ALTER TABLE t4 RENAME TO t5;
ANALYZE;
BEGIN;
DROP TABLE t2;
ROLLBACK;
VACUUM;
} {15}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-36043-10590 Changes made as part of foreign key
# actions are included in the count, but those made as part of REPLACE
# constraint resolution are not.
#
# 3.1.*: foreign key actions
# 3.2.*: REPLACE constraints.
#
sqlite3 db test.db ; # To reset total_changes
do_tc_test 3.1.1 {
CREATE TABLE p1(c PRIMARY KEY, d);
CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET NULL);
CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE CASCADE);
CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET DEFAULT);
INSERT INTO p1 VALUES(1, 'one');
INSERT INTO p1 VALUES(2, 'two');
INSERT INTO p1 VALUES(3, 'three');
INSERT INTO p1 VALUES(4, 'four');
INSERT INTO c1 VALUES(1, 'i');
INSERT INTO c2 VALUES(2, 'ii');
INSERT INTO c3 VALUES(3, 'iii');
PRAGMA foreign_keys = ON;
} {7}
do_tc_test 3.1.2 { DELETE FROM p1 WHERE c=1; } {9}
do_tc_test 3.1.3 { DELETE FROM p1 WHERE c=2; } {11}
do_tc_test 3.1.4 { DELETE FROM p1 WHERE c=3; } {13}
do_tc_test 3.1.5 { DELETE FROM p1 WHERE c=4; } {14} ; # only 1 this time.
sqlite3 db test.db ; # To reset total_changes
do_tc_test 3.1.6 {
DROP TABLE c1;
DROP TABLE c2;
DROP TABLE c3;
CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET NULL);
CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE CASCADE);
CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET DEFAULT);
INSERT INTO p1 VALUES(1, 'one');
INSERT INTO p1 VALUES(2, 'two');
INSERT INTO p1 VALUES(3, 'three');
INSERT INTO p1 VALUES(4, 'four');
INSERT INTO c1 VALUES(1, 'i');
INSERT INTO c2 VALUES(2, 'ii');
INSERT INTO c3 VALUES(3, 'iii');
PRAGMA foreign_keys = ON;
} {7}
do_tc_test 3.1.7 { UPDATE p1 SET c=c+4 WHERE c=1; } {9}
do_tc_test 3.1.8 { UPDATE p1 SET c=c+4 WHERE c=2; } {11}
do_tc_test 3.1.9 { UPDATE p1 SET c=c+4 WHERE c=3; } {13}
do_tc_test 3.1.10 { UPDATE p1 SET c=c+4 WHERE c=4; } {14} ; # only 1 this time.
sqlite3 db test.db ; # To reset total_changes
do_tc_test 3.2.1 {
CREATE TABLE t3(a UNIQUE, b UNIQUE);
INSERT INTO t3 VALUES('one', 'one');
INSERT INTO t3 VALUES('two', 'two');
INSERT OR REPLACE INTO t3 VALUES('one', 'two');
} {3}
do_tc_test 3.2.2 {
INSERT INTO t3 VALUES('three', 'one');
UPDATE OR REPLACE t3 SET b='two' WHERE b='one';
SELECT * FROM t3;
} {three two 5}
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-54872-08741 Changes to a view that are intercepted by
# INSTEAD OF triggers are not counted.
#
sqlite3 db test.db ; # To reset total_changes
do_tc_test 4.1 {
CREATE TABLE t6(x);
CREATE VIEW v1 AS SELECT * FROM t6;
CREATE TRIGGER v1_tr1 INSTEAD OF INSERT ON v1 BEGIN
SELECT 'no-op';
END;
INSERT INTO v1 VALUES('a');
INSERT INTO v1 VALUES('b');
} {0}
do_tc_test 4.2 {
CREATE TRIGGER v1_tr2 INSTEAD OF INSERT ON v1 BEGIN
INSERT INTO t6 VALUES(new.x);
END;
INSERT INTO v1 VALUES('c');
INSERT INTO v1 VALUES('d');
} {2}
finish_test

229
test/e_wal.test Normal file
View File

@ -0,0 +1,229 @@
# 2011 May 06
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix e_wal
db close
testvfs oldvfs -iversion 1
# EVIDENCE-OF: R-58297-14483 WAL databases can be created, read, and
# written even if shared memory is unavailable as long as the
# locking_mode is set to EXCLUSIVE before the first attempted access.
#
# EVIDENCE-OF: R-00449-33772 This feature allows WAL databases to be
# created, read, and written by legacy VFSes that lack the "version 2"
# shared-memory methods xShmMap, xShmLock, xShmBarrier, and xShmUnmap on
# the sqlite3_io_methods object.
#
# 1.1: "create" tests.
# 1.2: "read" tests.
# 1.3: "write" tests.
#
# All three done with VFS "oldvfs", which has iVersion==1 and so does
# not support shared memory.
#
sqlite3 db test.db -vfs oldvfs
do_execsql_test 1.1.1 {
PRAGMA journal_mode = WAL;
} {delete}
do_execsql_test 1.1.2 {
PRAGMA locking_mode = EXCLUSIVE;
PRAGMA journal_mode = WAL;
} {exclusive wal}
do_execsql_test 1.1.3 {
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(1, 2);
} {}
do_test 1.1.4 {
list [file exists test.db-shm] [file exists test.db-wal]
} {0 1}
do_test 1.2.1 {
db close
sqlite3 db test.db -vfs oldvfs
catchsql { SELECT * FROM t1 }
} {1 {unable to open database file}}
do_test 1.2.2 {
execsql { PRAGMA locking_mode = EXCLUSIVE }
execsql { SELECT * FROM t1 }
} {1 2}
do_test 1.2.3 {
list [file exists test.db-shm] [file exists test.db-wal]
} {0 1}
do_test 1.3.1 {
db close
sqlite3 db test.db -vfs oldvfs
catchsql { INSERT INTO t1 VALUES(3, 4) }
} {1 {unable to open database file}}
do_test 1.3.2 {
execsql { PRAGMA locking_mode = EXCLUSIVE }
execsql { INSERT INTO t1 VALUES(3, 4) }
execsql { SELECT * FROM t1 }
} {1 2 3 4}
do_test 1.3.3 {
list [file exists test.db-shm] [file exists test.db-wal]
} {0 1}
# EVIDENCE-OF: R-31969-57825 If EXCLUSIVE locking mode is set prior to
# the first WAL-mode database access, then SQLite never attempts to call
# any of the shared-memory methods and hence no shared-memory wal-index
# is ever created.
#
db close
sqlite3 db test.db
do_execsql_test 2.1.1 {
PRAGMA locking_mode = EXCLUSIVE;
SELECT * FROM t1;
} {exclusive 1 2 3 4}
do_test 2.1.2 {
list [file exists test.db-shm] [file exists test.db-wal]
} {0 1}
# EVIDENCE-OF: R-36328-16367 In that case, the database connection
# remains in EXCLUSIVE mode as long as the journal mode is WAL; attempts
# to change the locking mode using "PRAGMA locking_mode=NORMAL;" are
# no-ops.
#
do_execsql_test 2.2.1 {
PRAGMA locking_mode = NORMAL;
SELECT * FROM t1;
} {exclusive 1 2 3 4}
do_test 2.2.2 {
sqlite3 db2 test.db
catchsql {SELECT * FROM t1} db2
} {1 {database is locked}}
db2 close
# EVIDENCE-OF: R-63522-46088 The only way to change out of EXCLUSIVE
# locking mode is to first change out of WAL journal mode.
#
do_execsql_test 2.3.1 {
PRAGMA journal_mode = DELETE;
SELECT * FROM t1;
} {delete 1 2 3 4}
do_test 2.3.2 {
sqlite3 db2 test.db
catchsql {SELECT * FROM t1} db2
} {1 {database is locked}}
do_execsql_test 2.3.3 {
PRAGMA locking_mode = NORMAL;
SELECT * FROM t1;
} {normal 1 2 3 4}
do_test 2.3.4 {
sqlite3 db2 test.db
catchsql {SELECT * FROM t1} db2
} {0 {1 2 3 4}}
db2 close
db close
# EVIDENCE-OF: R-57239-11845 If NORMAL locking mode is in effect for the
# first WAL-mode database access, then the shared-memory wal-index is
# created.
#
do_test 3.0 {
sqlite3 db test.db
execsql { PRAGMA journal_mode = WAL }
db close
} {}
do_test 3.1 {
sqlite3 db test.db
execsql { SELECT * FROM t1 }
list [file exists test.db-shm] [file exists test.db-wal]
} {1 1}
# EVIDENCE-OF: R-13779-07711 As long as exactly one connection is using
# a shared-memory wal-index, the locking mode can be changed freely
# between NORMAL and EXCLUSIVE.
#
do_execsql_test 3.2.1 {
PRAGMA locking_mode = EXCLUSIVE;
PRAGMA locking_mode = NORMAL;
PRAGMA locking_mode = EXCLUSIVE;
INSERT INTO t1 VALUES(5, 6);
} {exclusive normal exclusive}
do_test 3.2.2 {
sqlite3 db2 test.db
catchsql { SELECT * FROM t1 } db2
} {1 {database is locked}}
# EVIDENCE-OF: R-10993-11647 It is only when the shared-memory wal-index
# is omitted, when the locking mode is EXCLUSIVE prior to the first
# WAL-mode database access, that the locking mode is stuck in EXCLUSIVE.
#
do_execsql_test 3.2.3 {
PRAGMA locking_mode = NORMAL;
SELECT * FROM t1;
} {normal 1 2 3 4 5 6}
do_test 3.2.4 {
catchsql { SELECT * FROM t1 } db2
} {0 {1 2 3 4 5 6}}
do_catchsql_test 3.2.5 {
PRAGMA locking_mode = EXCLUSIVE;
INSERT INTO t1 VALUES(7, 8);
} {1 {database is locked}}
db2 close
# EVIDENCE-OF: R-46197-42811 This means that the underlying VFS must
# support the "version 2" shared-memory.
#
# EVIDENCE-OF: R-55316-21772 If the VFS does not support shared-memory
# methods, then the attempt to open a database that is already in WAL
# mode, or the attempt convert a database into WAL mode, will fail.
#
db close
do_test 3.4.1 {
sqlite3 db test.db -vfs oldvfs
catchsql { SELECT * FROM t1 }
} {1 {unable to open database file}}
db close
do_test 3.4.2 {
forcedelete test.db2
sqlite3 db test.db2 -vfs oldvfs
catchsql { PRAGMA journal_mode = WAL }
} {0 delete}
db close
# EVIDENCE-OF: R-22428-28959 To prevent older versions of SQLite from
# trying to recover a WAL-mode database (and making matters worse) the
# database file format version numbers (bytes 18 and 19 in the database
# header) are increased from 1 to 2 in WAL mode.
#
reset_db
do_execsql_test 4.1.1 { CREATE TABLE t1(x, y) }
do_test 4.1.2 { hexio_read test.db 18 2 } {0101}
do_execsql_test 4.1.3 { PRAGMA journal_mode = wAL } {wal}
do_test 4.1.4 { hexio_read test.db 18 2 } {0202}
# EVIDENCE-OF: R-02535-05811 One can explicitly change out of WAL mode
# using a pragma such as this: PRAGMA journal_mode=DELETE;
#
do_execsql_test 4.2.1 { INSERT INTO t1 VALUES(1, 1); } {}
do_test 4.2.2 { file exists test.db-wal } {1}
do_execsql_test 4.2.3 { PRAGMA journal_mode = delete } {delete}
do_test 4.2.4 { file exists test.db-wal } {0}
# EVIDENCE-OF: R-60175-02388 Deliberately changing out of WAL mode
# changes the database file format version numbers back to 1 so that
# older versions of SQLite can once again access the database file.
#
do_test 4.3 { hexio_read test.db 18 2 } {0101}
finish_test

View File

@ -95,5 +95,25 @@ do_execsql_test printf2-2.3 {
SELECT printf('%s=(%d/%g/%s)',a) FROM t1 ORDER BY a;
} {-1=(0/0/) 1=(0/0/) 1.5=(0/0/) abc=(0/0/)}
# The precision of the %c conversion causes the character to repeat.
#
do_execsql_test printf2-3.1 {
SELECT printf('|%110.100c|','*');
} {{| ****************************************************************************************************|}}
do_execsql_test printf2-3.2 {
SELECT printf('|%-110.100c|','*');
} {{|**************************************************************************************************** |}}
do_execsql_test printf2-3.3 {
SELECT printf('|%9.8c|%-9.8c|','*','*');
} {{| ********|******** |}}
do_execsql_test printf2-3.4 {
SELECT printf('|%8.8c|%-8.8c|','*','*');
} {|********|********|}
do_execsql_test printf2-3.5 {
SELECT printf('|%7.8c|%-7.8c|','*','*');
} {|********|********|}
finish_test

145
test/skipscan6.test Normal file
View File

@ -0,0 +1,145 @@
# 2014-10-21
#
# 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 of the "skip-scan" query strategy. In
# particular, this file verifies that use of all columns of an index
# is always preferred over the use of a skip-scan on some columns of
# the same index. Because of difficulties in scoring a skip-scan,
# the skip-scan can sometimes come out with a lower raw score when
# using STAT4. But the query planner should detect this and use the
# full index rather than the skip-scan.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix skipscan6
ifcapable !stat4 {
finish_test
return
}
do_execsql_test 1.1 {
CREATE TABLE t1(
aa int,
bb int,
cc int,
dd int,
ee int
);
CREATE INDEX ix on t1(aa, bb, cc, dd DESC);
ANALYZE sqlite_master;
INSERT INTO sqlite_stat1 VALUES('t1','ix','2695116 1347558 264 18 2');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 196859 196859 32 1','0 15043 15043 92468 92499','0 19 286 81846 92499',X'0609010804031552977BD725BD28');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 14687 161 1 1','0 289067 299306 299457 299457','0 199 6772 273984 299457',X'060902020403013406314D67456415B819');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 19313 19308 22 1','0 325815 325815 343725 343746','0 261 9545 315009 343746',X'060902080403018A49B0A3AD1ED931');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 25047 9051 15 1','0 350443 350443 356590 356604','0 266 9795 325519 356604',X'06090208040301914C2DD2E91F93CF');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 42327 9906 7 1','0 376381 376381 380291 380297','0 268 10100 344232 380297',X'06090208040301934BF672511F7ED3');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 24513 2237 1 1','0 455150 467779 470015 470015','0 286 10880 425401 470015',X'06090202040301A703464A28F2611EF1EE');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 18730 18724 15 1','0 479663 479663 498271 498285','0 287 10998 450793 498285',X'06090208040301A8494AF3A41EC50C');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 119603 47125 1 1','0 572425 572425 598915 598915','0 404 14230 546497 598915',X'06090208040302474FD1929A03194F');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 1454 1454 1 1','0 898346 898346 898373 898373','0 952 31165 827562 898373',X'06090208040304FD53F6A2A2097F64');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 57138 7069 1 1','0 1122389 1122389 1129457 1129457','0 1967 46801 1045943 1129457',X'06090208040309884BC4C52F1F6EB7');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 285 11 1 1','0 1197683 1197824 1197831 1197831','0 2033 50990 1112280 1197831',X'06090202040309D80346503FE2A9038E4F');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 25365 9773 1 1','0 1301013 1301013 1310785 1310785','0 2561 58806 1217877 1310785',X'0609020804030C5F4C8F88AB0AF2A2');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 45180 7222 1 1','0 1326378 1326378 1333599 1333599','0 2562 59921 1240187 1333599',X'0609020804030C604CAB75490B0351');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 8537 41 1 1','0 1496959 1497288 1497289 1497289','0 3050 68246 1394126 1497289',X'0609020204030EA0057F527459B0257C4B');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 26139 26131 17 1','0 1507977 1507977 1520578 1520594','0 3074 69188 1416111 1520594',X'0609020804030EB95169453423D4EA');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 102894 29678 1 1','0 1537421 1550467 1564894 1564894','0 3109 69669 1459820 1564894',X'0609020204030EE3183652A6ED3006EBCB');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 319 3 1 1','0 1796728 1796746 1796747 1796747','0 3650 86468 1682243 1796747',X'0609020204031163033550D0C41018C28D');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 127 127 1 1','0 2096194 2096194 2096205 2096205','0 5145 106437 1951535 2096205',X'060902080403180F53BB1AF727EE50');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 66574 5252 1 1','0 2230524 2265961 2271212 2271212','0 5899 114976 2085829 2271212',X'0609020204031B8A05195009976D223B90');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 19440 19440 1 1','0 2391680 2391680 2395663 2395663','0 6718 123714 2184781 2395663',X'0609020804031F7452E00A7B07431A');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 18321 2177 1 1','0 2522928 2523231 2525407 2525407','0 7838 139084 2299958 2525407',X'06090201040324A7475231103B1AA7B8');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 22384 1361 1 1','0 2541249 2544834 2546194 2546194','0 7839 139428 2308416 2546194',X'06090202040324A8011652323D4B1AA9EB');
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 18699 855 1 1','0 2563633 2578178 2579032 2579032','0 7840 139947 2321671 2579032',X'06090202040324A9077452323D7D1052C5');
INSERT INTO sqlite_stat4 VALUES('t1','ix','17965 1579 1579 1 1','2677151 2690666 2690666 2692244 2692244','1 9870 153959 2418294 2692244',X'060102080403021B8A4FE1AB84032B35');
ANALYZE sqlite_master;
} {}
do_execsql_test 1.2 {
EXPLAIN QUERY PLAN
SELECT COUNT(*)
FROM t1
WHERE bb=21
AND aa=1
AND dd BETWEEN 1413833728 and 1413837331;
} {/INDEX ix .aa=. AND bb=../}
do_execsql_test 2.1 {
DROP INDEX ix;
CREATE INDEX good on t1(bb, aa, dd DESC);
CREATE INDEX bad on t1(aa, bb, cc, dd DESC);
DELETE FROM sqlite_stat1;
DELETE FROM sqlite_stat4;
INSERT INTO sqlite_stat1 VALUES('t1','good','2695116 299 264 2');
INSERT INTO sqlite_stat1 VALUES('t1','bad','2695116 1347558 264 18 2');
INSERT INTO sqlite_stat4 VALUES('t1','good','197030 196859 32 1','15086 15086 92511 92536','19 25 81644 92536',X'05010904031552977BD725BD22');
INSERT INTO sqlite_stat4 VALUES('t1','good','14972 14687 1 1','289878 289878 299457 299457','199 244 267460 299457',X'050209040301344F7E569402C419');
INSERT INTO sqlite_stat4 VALUES('t1','good','19600 19313 22 1','327127 327127 346222 346243','261 319 306884 346243',X'0502090403018A49503BC01EC577');
INSERT INTO sqlite_stat4 VALUES('t1','good','25666 25047 15 1','352087 352087 372692 372706','266 327 325601 372706',X'050209040301914C2DD2E91F93CF');
INSERT INTO sqlite_stat4 VALUES('t1','good','42392 42327 26 1','378657 378657 382547 382572','268 331 333529 382572',X'05020904030193533B2FE326ED48');
INSERT INTO sqlite_stat4 VALUES('t1','good','24619 24513 11 1','457872 457872 461748 461758','286 358 399322 461758',X'050209040301A752B1557825EA7C');
INSERT INTO sqlite_stat4 VALUES('t1','good','18969 18730 15 1','482491 482491 501105 501119','287 360 433605 501119',X'050209040301A8494AF3A41EC50C');
INSERT INTO sqlite_stat4 VALUES('t1','good','119710 119603 1 1','576500 576500 598915 598915','404 505 519877 598915',X'05020904030247539A7A7912F617');
INSERT INTO sqlite_stat4 VALUES('t1','good','11955 11946 1 1','889796 889796 898373 898373','938 1123 794694 898373',X'050209040304EF4DF9C4150BBB28');
INSERT INTO sqlite_stat4 VALUES('t1','good','57197 57138 24 1','1129865 1129865 1151492 1151515','1967 2273 1027048 1151515',X'05020904030988533510BC26E20A');
INSERT INTO sqlite_stat4 VALUES('t1','good','3609 3543 1 1','1196265 1196265 1197831 1197831','2002 2313 1070108 1197831',X'050209040309B050E95CD718D94D');
INSERT INTO sqlite_stat4 VALUES('t1','good','25391 25365 13 1','1309378 1309378 1315567 1315579','2561 2936 1178358 1315579',X'05020904030C5F53DF9E13283570');
INSERT INTO sqlite_stat4 VALUES('t1','good','45232 45180 17 1','1334769 1334769 1337946 1337962','2562 2938 1198998 1337962',X'05020904030C60541CACEE28BCAC');
INSERT INTO sqlite_stat4 VALUES('t1','good','5496 5493 1 1','1495882 1495882 1497289 1497289','3043 3479 1348695 1497289',X'05020904030E99515C62AD0F0B34');
INSERT INTO sqlite_stat4 VALUES('t1','good','26348 26139 17 1','1517381 1517381 1529990 1530006','3074 3519 1378320 1530006',X'05020904030EB95169453423D4EA');
INSERT INTO sqlite_stat4 VALUES('t1','good','102927 102894 10 1','1547088 1547088 1649950 1649959','3109 3559 1494260 1649959',X'05020904030EE34D309F671FFA47');
INSERT INTO sqlite_stat4 VALUES('t1','good','3602 3576 1 1','1793873 1793873 1796747 1796747','3601 4128 1630783 1796747',X'050209040311294FE88B432219B9');
INSERT INTO sqlite_stat4 VALUES('t1','good','154 154 1 1','2096059 2096059 2096205 2096205','5037 5779 1893039 2096205',X'050209040317994EFF05A016DCED');
INSERT INTO sqlite_stat4 VALUES('t1','good','68153 66574 60 1','2244039 2244039 2268892 2268951','5899 6749 2027553 2268951',X'05020904031B8A532DBC5A26D2BA');
INSERT INTO sqlite_stat4 VALUES('t1','good','321 321 1 1','2395618 2395618 2395663 2395663','6609 7528 2118435 2395663',X'05020904031EFA54078EEE1E2D65');
INSERT INTO sqlite_stat4 VALUES('t1','good','19449 19440 22 1','2407769 2407769 2426049 2426070','6718 7651 2146904 2426070',X'05020904031F7450E6118C2336BD');
INSERT INTO sqlite_stat4 VALUES('t1','good','18383 18321 56 1','2539949 2539949 2551080 2551135','7838 8897 2245459 2551135',X'050209040324A752EA2E1E2642B2');
INSERT INTO sqlite_stat4 VALUES('t1','good','22479 22384 60 1','2558332 2558332 2565233 2565292','7839 8899 2251202 2565292',X'050209040324A853926538279A5F');
INSERT INTO sqlite_stat4 VALUES('t1','good','18771 18699 63 1','2580811 2580811 2596914 2596976','7840 8901 2263572 2596976',X'050209040324A9526C1DE9256E72');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 196859 196859 32 1','0 15043 15043 92468 92499','0 19 286 81846 92499',X'0609010804031552977BD725BD28');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 14687 161 1 1','0 289067 299306 299457 299457','0 199 6772 273984 299457',X'060902020403013406314D67456415B819');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 19313 19308 22 1','0 325815 325815 343725 343746','0 261 9545 315009 343746',X'060902080403018A49B0A3AD1ED931');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 25047 9051 15 1','0 350443 350443 356590 356604','0 266 9795 325519 356604',X'06090208040301914C2DD2E91F93CF');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 42327 9906 7 1','0 376381 376381 380291 380297','0 268 10100 344232 380297',X'06090208040301934BF672511F7ED3');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 24513 2237 1 1','0 455150 467779 470015 470015','0 286 10880 425401 470015',X'06090202040301A703464A28F2611EF1EE');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 18730 18724 15 1','0 479663 479663 498271 498285','0 287 10998 450793 498285',X'06090208040301A8494AF3A41EC50C');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 119603 47125 1 1','0 572425 572425 598915 598915','0 404 14230 546497 598915',X'06090208040302474FD1929A03194F');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 1454 1454 1 1','0 898346 898346 898373 898373','0 952 31165 827562 898373',X'06090208040304FD53F6A2A2097F64');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 57138 7069 1 1','0 1122389 1122389 1129457 1129457','0 1967 46801 1045943 1129457',X'06090208040309884BC4C52F1F6EB7');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 285 11 1 1','0 1197683 1197824 1197831 1197831','0 2033 50990 1112280 1197831',X'06090202040309D80346503FE2A9038E4F');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 25365 9773 1 1','0 1301013 1301013 1310785 1310785','0 2561 58806 1217877 1310785',X'0609020804030C5F4C8F88AB0AF2A2');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 45180 7222 1 1','0 1326378 1326378 1333599 1333599','0 2562 59921 1240187 1333599',X'0609020804030C604CAB75490B0351');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 8537 41 1 1','0 1496959 1497288 1497289 1497289','0 3050 68246 1394126 1497289',X'0609020204030EA0057F527459B0257C4B');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 26139 26131 17 1','0 1507977 1507977 1520578 1520594','0 3074 69188 1416111 1520594',X'0609020804030EB95169453423D4EA');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 102894 29678 1 1','0 1537421 1550467 1564894 1564894','0 3109 69669 1459820 1564894',X'0609020204030EE3183652A6ED3006EBCB');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 319 3 1 1','0 1796728 1796746 1796747 1796747','0 3650 86468 1682243 1796747',X'0609020204031163033550D0C41018C28D');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 127 127 1 1','0 2096194 2096194 2096205 2096205','0 5145 106437 1951535 2096205',X'060902080403180F53BB1AF727EE50');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 66574 5252 1 1','0 2230524 2265961 2271212 2271212','0 5899 114976 2085829 2271212',X'0609020204031B8A05195009976D223B90');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 19440 19440 1 1','0 2391680 2391680 2395663 2395663','0 6718 123714 2184781 2395663',X'0609020804031F7452E00A7B07431A');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 18321 2177 1 1','0 2522928 2523231 2525407 2525407','0 7838 139084 2299958 2525407',X'06090201040324A7475231103B1AA7B8');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 22384 1361 1 1','0 2541249 2544834 2546194 2546194','0 7839 139428 2308416 2546194',X'06090202040324A8011652323D4B1AA9EB');
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 18699 855 1 1','0 2563633 2578178 2579032 2579032','0 7840 139947 2321671 2579032',X'06090202040324A9077452323D7D1052C5');
INSERT INTO sqlite_stat4 VALUES('t1','bad','17965 1579 1579 1 1','2677151 2690666 2690666 2692244 2692244','1 9870 153959 2418294 2692244',X'060102080403021B8A4FE1AB84032B35');
ANALYZE sqlite_master;
} {}
do_execsql_test 2.2 {
EXPLAIN QUERY PLAN
SELECT COUNT(*)
FROM t1
WHERE bb=21
AND aa=1
AND dd BETWEEN 1413833728 and 1413837331;
} {/INDEX good .bb=. AND aa=. AND dd>. AND dd<../}
finish_test

View File

@ -32,6 +32,7 @@ ifcapable {!trigger} {
finish_test
return
}
set ::testprefix trigger9
proc has_rowdata {sql} {
expr {[lsearch [execsql "explain $sql"] RowData]>=0}
@ -220,4 +221,36 @@ ifcapable compound {
} {2}
}
reset_db
do_execsql_test 4.1 {
CREATE TABLE t1(a, b);
CREATE TABLE log(x);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
CREATE VIEW v1 AS SELECT a, b FROM t1;
CREATE TRIGGER tr1 INSTEAD OF DELETE ON v1 BEGIN
INSERT INTO log VALUES('delete');
END;
CREATE TRIGGER tr2 INSTEAD OF UPDATE ON v1 BEGIN
INSERT INTO log VALUES('update');
END;
CREATE TRIGGER tr3 INSTEAD OF INSERT ON v1 BEGIN
INSERT INTO log VALUES('insert');
END;
}
do_execsql_test 4.2 {
DELETE FROM v1 WHERE rowid=1;
} {}
do_execsql_test 4.3 {
UPDATE v1 SET a=b WHERE rowid=2;
} {}
finish_test

View File

@ -604,5 +604,19 @@ do_test update-14.4 {
} ;# ifcapable {trigger}
# Ticket [https://www.sqlite.org/src/tktview/43107840f1c02] on 2014-10-29
# An assertion fault on UPDATE
#
do_execsql_test update-15.1 {
CREATE TABLE t15(a INTEGER PRIMARY KEY, b);
INSERT INTO t15(a,b) VALUES(10,'abc'),(20,'def'),(30,'ghi');
ALTER TABLE t15 ADD COLUMN c;
CREATE INDEX t15c ON t15(c);
INSERT INTO t15(a,b)
VALUES(5,'zyx'),(15,'wvu'),(25,'tsr'),(35,'qpo');
UPDATE t15 SET c=printf("y%d",a) WHERE c IS NULL;
SELECT a,b,c,'|' FROM t15 ORDER BY a;
} {5 zyx y5 | 10 abc y10 | 15 wvu y15 | 20 def y20 | 25 tsr y25 | 30 ghi y30 | 35 qpo y35 |}
finish_test

123
tool/varint.c Normal file
View File

@ -0,0 +1,123 @@
/*
** A utility program to translate SQLite varints into decimal and decimal
** integers into varints.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 i64;
typedef unsigned __int64 u64;
#else
typedef long long int i64;
typedef unsigned long long int u64;
#endif
static int hexValue(char c){
if( c>='0' && c<='9' ) return c - '0';
if( c>='a' && c<='f' ) return c - 'a' + 10;
if( c>='A' && c<='F' ) return c - 'A' + 10;
return -1;
}
static char toHex(unsigned char c){
return "0123456789abcdef"[c&0xf];
}
static int putVarint(unsigned char *p, u64 v){
int i, j, n;
unsigned char buf[10];
if( v & (((u64)0xff000000)<<32) ){
p[8] = (unsigned char)v;
v >>= 8;
for(i=7; i>=0; i--){
p[i] = (unsigned char)((v & 0x7f) | 0x80);
v >>= 7;
}
return 9;
}
n = 0;
do{
buf[n++] = (unsigned char)((v & 0x7f) | 0x80);
v >>= 7;
}while( v!=0 );
buf[0] &= 0x7f;
for(i=0, j=n-1; j>=0; j--, i++){
p[i] = buf[j];
}
return n;
}
int main(int argc, char **argv){
int i;
u64 x;
u64 uX = 0;
i64 iX;
int n;
unsigned char zHex[20];
if( argc==1 ){
fprintf(stderr,
"Usage:\n"
" %s HH HH HH ... Convert varint to decimal\n"
" %s DDDDD Convert decimal to varint\n"
" Add '+' or '-' before DDDDD to disambiguate.\n",
argv[0], argv[0]);
exit(1);
}
if( argc>2
|| (strlen(argv[1])==2 && hexValue(argv[1][0])>=0 && hexValue(argv[1][1])>=0)
){
/* Hex to decimal */
for(i=1; i<argc && i<9; i++){
if( strlen(argv[i])!=2 ){
fprintf(stderr, "Not a hex byte: %s\n", argv[i]);
exit(1);
}
x = (hexValue(argv[i][0])<<4) + hexValue(argv[i][1]);
uX = (uX<<7) + (x&0x7f);
if( (x&0x80)==0 ) break;
}
if( i==9 && i<argc ){
if( strlen(argv[i])!=2 ){
fprintf(stderr, "Not a hex byte: %s\n", argv[i]);
exit(1);
}
x = (hexValue(argv[i][0])<<4) + hexValue(argv[i][1]);
uX = (uX<<8) + x;
}
i++;
if( i<argc ){
fprintf(stderr, "Extra arguments: %s...\n", argv[i]);
exit(1);
}
}else{
char *z = argv[1];
int sign = 1;
if( z[0]=='+' ) z++;
else if( z[0]=='-' ){ z++; sign = -1; }
uX = 0;
while( z[0] ){
if( z[0]<'0' || z[0]>'9' ){
fprintf(stderr, "Not a decimal number: %s", argv[1]);
exit(1);
}
uX = uX*10 + z[0] - '0';
z++;
}
if( sign<0 ){
memcpy(&iX, &uX, 8);
iX = -iX;
memcpy(&uX, &iX, 8);
}
}
n = putVarint(zHex, uX);
printf("%lld =", (i64)uX);
for(i=0; i<n; i++){
printf(" %c%c", toHex(zHex[i]>>4), toHex(zHex[i]&0x0f));
}
printf("\n");
return 0;
}