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:
commit
ca3e10ea37
18
configure
vendored
18
configure
vendored
@ -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'`\\"
|
||||
|
||||
|
@ -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
100
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
f4de9e07be3819db222317725e62ea997cd22a20
|
||||
28b044a51215a3f64dafb2cf3b6cb7d2029580ef
|
83
sqlite3.1
83
sqlite3.1
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
22
src/backup.c
22
src/backup.c
@ -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;
|
||||
}
|
||||
|
||||
|
917
src/btree.c
917
src/btree.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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.
|
||||
|
10
src/ctime.c
10
src/ctime.c
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
85
src/expr.c
85
src/expr.c
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
173
src/main.c
173
src/main.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
4
src/os.c
4
src/os.c
@ -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);
|
||||
|
21
src/pager.c
21
src/pager.c
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 ){
|
||||
|
60
src/printf.c
60
src/printf.c
@ -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);
|
||||
|
14
src/random.c
14
src/random.c
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
124
src/sqlite.h.in
124
src/sqlite.h.in
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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: {
|
||||
|
@ -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;
|
||||
|
@ -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 ){
|
||||
|
@ -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);
|
||||
}
|
||||
|
10
src/util.c
10
src/util.c
@ -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++; }
|
||||
|
@ -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];
|
||||
|
@ -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))])
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
16
src/vtab.c
16
src/vtab.c
@ -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: {
|
||||
|
199
src/where.c
199
src/where.c
@ -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)
|
||||
|
@ -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
52
test/autoindex4.test
Normal 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
441
test/e_changes.test
Normal 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
213
test/e_totalchanges.test
Normal 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
229
test/e_wal.test
Normal 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
|
@ -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
145
test/skipscan6.test
Normal 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
|
@ -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
|
||||
|
@ -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
123
tool/varint.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user