Compare commits

...

15 Commits

Author SHA1 Message Date
drh 2fc3300b2b Convert the hint expression of the CursorHint opcode into a string for
display by EXPLAIN.

FossilOrigin-Name: 12640cb22240ee436cad99360ceb9a208edd14f5
2015-08-13 21:43:19 +00:00
dan 91d3a61f8a Add simple tests for new sqlite3BtreeCursorHint() functionality.
FossilOrigin-Name: 1efa6ed584172291edce78faf9021e577583d03b
2014-07-15 11:59:44 +00:00
dan 159c1a18db In the expression passed to sqlite3BtreeCursorHint() for the inner loops of joins, replace any TK_COLUMN references to columns in the outer loops with TK_REGISTER expressions (Expr.iTable indicates the specific register containing the value).
FossilOrigin-Name: f9dddd008c6ef7940a1d66363fbb456cff7207c1
2014-07-14 19:04:29 +00:00
drh 5b88bc4bec Do not allow cursor hints to use expressions containing subqueries. This
change fixes the problem seen in the previous check-in.

FossilOrigin-Name: bfefc57554853e467ee6aeaba8d08331406fa216
2013-12-07 23:35:21 +00:00
drh 28935364ef If the SQLITE_ENABLE_CURSOR_HINTS macro is defined, then invoke the
sqlite3BtreeCursorHint() interface to provide hints to the storage engine
about rows that need not be returned.  Hints can be disabled using
SQLITE_TESTCTRL_OPTIMIZATIONS with SQLITE_CursorHints (0x2000).  Cursor
hints are not used by the built-in storage engine of SQLite but might
be useful to applications that provide their own storage engine.  The
current code is work-in-progrss and contains bugs.

FossilOrigin-Name: 3a9bec524ef2de44028b4058e67dc962082888d3
2013-12-07 20:39:19 +00:00
drh 9dcc7cd527 Increase the version number to 3.8.3.
FossilOrigin-Name: 23d00f22872a907a8ebf5b80689ff7aa66686a07
2013-12-07 17:01:23 +00:00
drh 689156fdbc At the start of each write transaction, check to see if the database file has
been moved, and if it has refuse to start the transaction, returning an
SQLITE_READONLY_DBMOVED error code.

FossilOrigin-Name: 369a23e00644f3ff8b6a2d2ed73b8cb65e9f124b
2013-12-07 16:56:09 +00:00
drh a9c19f935c Back out the new device capability. The determination of whether or not a
file has moved is now done strictly using a file-control.

FossilOrigin-Name: 9c59f5af7ac4908583fab85d37241f200c40f02d
2013-12-07 16:45:05 +00:00
drh b959a017b6 Actually look at i-node numbers to determine whether or not the database
file has moved.

FossilOrigin-Name: 2b1884dc14f9a04a04eebb3245fbe0daaff399eb
2013-12-07 12:29:22 +00:00
drh 4e8fe3ff91 Performance optimization to the moveToRoot() subroutine in btree.c.
FossilOrigin-Name: b5842a70f8e26456a8f0d39539bc266f097480a4
2013-12-06 23:25:27 +00:00
drh b8a9bb4fb9 Use memcmp() instead of the BINARY collating function where possible, for
a performance boost.

FossilOrigin-Name: c5a3a1af3c7bd34886e944a1fef2f6340ded24a0
2013-12-06 22:45:31 +00:00
drh 72b8ef6ce3 Remove some commented-out code from sqlite3BtreeMovetoUnpacked() to try to make
it more readable.

FossilOrigin-Name: 2d62d1131f8bbc4e1f8f7aeaf0d91e3237fe3b7c
2013-12-06 22:44:51 +00:00
mistachkin 091a81b91d Add the SQLITE_READONLY_DBMOVED error code to the sqlite3ErrName() function.
FossilOrigin-Name: 7789f801d720db5394117e764675cd4bbe6b2da1
2013-12-06 19:58:32 +00:00
drh 3fee8a63c8 Only error out on a database file move when attempting to start a write
transaction.  Assume read transactions are still safe.  And make the error
SQLITE_READONLY_DBMOVED instead of SQLITE_IOERR_NODB.

FossilOrigin-Name: 28348f2ada98c616241a51aecb70b63e87e6ddbb
2013-12-06 17:23:38 +00:00
drh 1b1f30bb5e Add code to detect if the database file is moved or deleted out from under
SQLite and return an SQLITE_IOERR_NODB.

FossilOrigin-Name: 8759a8e4d83b163e315eff316cf163f6ea42f2bb
2013-12-06 15:37:35 +00:00
25 changed files with 711 additions and 74 deletions
+1 -1
View File
@@ -1 +1 @@
3.8.2
3.8.3
Vendored
+9 -9
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.8.2.
# Generated by GNU Autoconf 2.62 for sqlite 3.8.3.
#
# 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.2'
PACKAGE_STRING='sqlite 3.8.2'
PACKAGE_VERSION='3.8.3'
PACKAGE_STRING='sqlite 3.8.3'
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.2 to adapt to many kinds of systems.
\`configure' configures sqlite 3.8.3 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.2:";;
short | recursive ) echo "Configuration of sqlite 3.8.3:";;
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.2
sqlite configure 3.8.3
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.2, which was
It was created by sqlite $as_me 3.8.3, 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.2, which was
This file was extended by sqlite $as_me 3.8.3, 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.2
sqlite config.status 3.8.3
configured by $0, generated by GNU Autoconf 2.62,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+1
View File
@@ -242,6 +242,7 @@ TESTSRC = \
$(TOP)/src/test_backup.c \
$(TOP)/src/test_btree.c \
$(TOP)/src/test_config.c \
$(TOP)/src/test_cursorhint.c \
$(TOP)/src/test_demovfs.c \
$(TOP)/src/test_devsym.c \
$(TOP)/src/test_fs.c \
+33 -29
View File
@@ -1,12 +1,12 @@
C Version\s3.8.2
D 2013-12-06T14:53:30.888
C Convert\sthe\shint\sexpression\sof\sthe\sCursorHint\sopcode\sinto\sa\sstring\sfor\ndisplay\sby\sEXPLAIN.
D 2015-08-13T21:43:19.244
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in e1a9b4258bbde53f5636f4e238c65b7e11459e2b
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc bb1f271c8ee9773489c89be00f3f8ad7ed7ae8e0
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION 52f7e22bfcec71a462e34194b4ae1671380fde59
F VERSION 8ed548d87d0a27fd7d7620476f9e25f9fa742d73
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 87ca612393d0f439550634bd2c156ea9ff6195ae
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 f97b17cd80fa428e5df4e70a36ed5b4ed21100c2 x
F configure 1673bc402f8fc95015f72c279adc5a9a668ee237 x
F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
@@ -142,7 +142,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt f439556c5ce01ced70987e5ee86549a45165d9ff
F main.mk 82fd90375561d7b66287ae5a8b09e1e027394019
F main.mk a6fa2dee82ed65ef48edc82baa0b480366f53212
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh d2a981497b404d6498f5ff3e3b1f3816bdfcb338
@@ -166,16 +166,16 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 1809a7caa2504233bdddd12f5018422421789537
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c fe6c95c57fd14ed4b3329f4b5bb08132fe7c322d
F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9
F src/btree.c 9e6d189894f54744d1a20c63de5afb66342f0904
F src/btree.h 450f1c6022ec89da529a57f3e704e87c6c14b34d
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
F src/build.c 1965c7b596ca6295b7ca59541ad186c57564b8f7
F src/build.c 9b40580b62916612678bdb69ce0286e39c29a862
F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c b36db1f79ee50eaca979660c9dd36437f5410b93
F src/expr.c 31a2b65339f6c3795d4cfa5e99798cd72f9fdfdf
F src/expr.c cdfc50b604ea9c9bbaa44f1f0a5c6cc835e84a32
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
F src/func.c ef30d26ae4d79bbc7300c74e77fd117a0ba30235
@@ -188,7 +188,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
F src/main.c 74bdee8f574588868e67c25cd377df7cba80102e
F src/main.c 355fc9ab213b43a4d8a96aadf2a84622e6668f0a
F src/malloc.c 543a8eb5508eaf4cadf55a9b503379eba2088128
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
@@ -205,9 +205,9 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c f076587029285554a3a65d30d0e71d50cd61f41f
F src/os_unix.c 60a7b3b23e6fcf83a50d1e320b280b551724e11f
F src/os_win.c 4323dd0bac4f7a7037fc4cf87fb4692d17f0b108
F src/pager.c 2aa4444ffe86e9282d03bc349a4a5e49bd77c0e8
F src/pager.c d27dc8aaeac16c90eb0c859c074683bfc4533c41
F src/pager.h f094af9f6ececfaa8a1e93876905a4f34233fb0c
F src/parse.y acee1a9958539e21263362b194594c5255ad2fca
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
@@ -219,16 +219,16 @@ F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c d41381d80a22d3a83352aeca274cccf264ac277a
F src/select.c 44fa5a4a270ce70b59acb616b01bc897e6d1e7ac
F src/shell.c 936a72ff784efff3832cce274a96ed0b036e6758
F src/sqlite.h.in baf55c31c4e15a4b626acfeaa792f2aaa566657f
F src/sqlite.h.in 125dc0b76f0116f1cd6f13536db52ba981e1c5bd
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h f3a5d663fe9c6c0b2ee7fc2e20a6204eaea5bc7c
F src/sqliteInt.h ccf72d12670132233750c6275a8ed978a95839aa
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 651b10698c87bbc3ae5772e2491e3444c5bbf153
F src/tclsqlite.c 571af8d366a8c00106c8c4bfa5b2ab07a9e58baf
F src/test1.c 760e0419705f712d80595f47199568cd7e3b57a4
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
@@ -243,6 +243,7 @@ F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
F src/test_config.c 10d0e00dd6315879a6d9fac20bd063c7bbbfb8f8
F src/test_cursorhint.c 7c37315e15d6543689e8b48979a8eb370baa3cfc
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
@@ -272,7 +273,7 @@ F src/test_syscall.c 16dbe79fb320fadb5acd7a0a59f49e52ab2d2091
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c ec4c1a62b890bf1dbcdb966399e140b904c700a4
F src/trigger.c d84e1f3669e9a217731a14a9d472b1c7b87c87ba
@@ -280,11 +281,11 @@ F src/update.c d1c2477dcf14d90999d1935af4efb4806553250b
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
F src/util.c 76ed0519296e3f62e97e57dab1999e34184c8e49
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c 54894fde8dc806d259e015ac7c9680145e725835
F src/vdbe.h c06f0813f853566457ce9cfb1a4a4bc39a5da644
F src/vdbeInt.h 05fbda0e061dbc4aaa2709a8cccf3515c245b263
F src/vdbe.c 54e269c6268a6f37697e27d6bc572674f14b1581
F src/vdbe.h 57b87844270b2e92647b8b82a8948f7a29efae8d
F src/vdbeInt.h 9ad955ca89d4dc4b6056cece1896b4b85a8521fe
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
F src/vdbeaux.c 09b79d475f5af2b3b5068f639609d88e0ced9d95
F src/vdbeaux.c f4ed66c45336e42e7f1bdaccf7586c84eba06bac
F src/vdbeblob.c 8cd05a5630e6d5563ad017bf82edaf812b28acde
F src/vdbemem.c 20e349d2ca928802fc8f2d42a2cc488fd6981d3f
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
@@ -293,7 +294,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
F src/where.c e6a4e713abe6f995495ea53dd6a5e48f88b53883
F src/where.c 907fd82f4f8fc89d8a72d44caf5a5679c0769630
F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -420,6 +421,7 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
F test/cursorhint.test e55ad8c466327ffb3511b60007102bca22314d0a
F test/date.test 42973251b9429f2c41b77eb98a7b0b0ba2d3b2c0
F test/dbstatus.test 8de104bb5606f19537d23cd553b41349b5ab1204
F test/dbstatus2.test 10418e62b3db5dca070f0c3eef3ea13946f339c2
@@ -726,6 +728,7 @@ F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
F test/pager4.test b40ecb4cc7dff957ee7916e41ab21d1ed702a642
F test/pagerfault.test 7285379906ab2f1108b8e82bbdf2d386cc8ff3ff
F test/pagerfault2.test caf4c7facb914fd3b03a17b31ae2b180c8d6ca1f
F test/pagerfault3.test 1003fcda009bf48a8e22a516e193b6ef0dd1bbd8
@@ -1145,10 +1148,11 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P c632567063d81c4be404ce58cbac0eff7412f565
R 39f74301df16683d1c19ab7ca83b6451
T +bgcolor * #d0c0ff
T +sym-release *
T +sym-version-3.8.2 *
U dan
Z bddf39b758268961698f9899546a37dd
P 1efa6ed584172291edce78faf9021e577583d03b
Q +206884718782331a7aaacc2c811e4e9d2effae91
R fcae2238c266b3818e83c96b2fcbbede
T *branch * cursor-hints-displayP4
T *sym-cursor-hints-displayP4 *
T -sym-cursor-hints *
U drh
Z 41561b125b2ba8dcbfb094780611e534
+1 -1
View File
@@ -1 +1 @@
27392118af4c38c5203a04b8013e1afdb1cebd0d
12640cb22240ee436cad99360ceb9a208edd14f5
+22 -14
View File
@@ -764,6 +764,21 @@ int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
return SQLITE_OK;
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
/*
** Give a hint to the cursor that it only has to deliver rows for which
** the expression pExpr is true. Within this expression, rows of the
** cursor are identified by Expr.op==TK_COLUMN with Expr.iTable==iTable.
**
** This interfaces is not used by the standard storage engine of SQLite.
** It is only useful to application that replace SQLite's built-in storage
** engine with their own.
*/
void sqlite3BtreeCursorHint(BtCursor *pCur, int iTable, const Expr *pExpr){
/* Alternative storage engines might use this. */
}
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Given a page number of a regular database page, return the page
@@ -4395,8 +4410,6 @@ static void moveToParent(BtCursor *pCur){
static int moveToRoot(BtCursor *pCur){
MemPage *pRoot;
int rc = SQLITE_OK;
Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt;
assert( cursorHoldsMutex(pCur) );
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
@@ -4411,16 +4424,12 @@ static int moveToRoot(BtCursor *pCur){
}
if( pCur->iPage>=0 ){
int i;
for(i=1; i<=pCur->iPage; i++){
releasePage(pCur->apPage[i]);
}
pCur->iPage = 0;
while( pCur->iPage ) releasePage(pCur->apPage[pCur->iPage--]);
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}else{
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0],
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
@@ -4453,14 +4462,16 @@ static int moveToRoot(BtCursor *pCur){
pCur->atLast = 0;
pCur->validNKey = 0;
if( pRoot->nCell==0 && !pRoot->leaf ){
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
}else if( !pRoot->leaf ){
Pgno subpage;
if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT;
subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
pCur->eState = CURSOR_VALID;
rc = moveToChild(pCur, subpage);
}else{
pCur->eState = ((pRoot->nCell>0)?CURSOR_VALID:CURSOR_INVALID);
pCur->eState = CURSOR_INVALID;
}
return rc;
}
@@ -4716,9 +4727,7 @@ int sqlite3BtreeMovetoUnpacked(
** 2 bytes of the cell.
*/
nCell = pCell[0];
if( nCell<=pPage->max1bytePayload
/* && (pCell+nCell)<pPage->aDataEnd */
){
if( nCell<=pPage->max1bytePayload ){
/* This branch runs if the record-size field of the cell is a
** single byte varint and the record fits entirely on the main
** b-tree page. */
@@ -4726,7 +4735,6 @@ int sqlite3BtreeMovetoUnpacked(
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
}else if( !(pCell[1] & 0x80)
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
/* && (pCell+nCell+2)<=pPage->aDataEnd */
){
/* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
+3
View File
@@ -167,6 +167,9 @@ int sqlite3BtreeMovetoUnpacked(
int *pRes
);
int sqlite3BtreeCursorHasMoved(BtCursor*, int*);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
void sqlite3BtreeCursorHint(BtCursor*, int, const Expr*);
#endif
int sqlite3BtreeDelete(BtCursor*);
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
const void *pData, int nData,
+3 -2
View File
@@ -4183,8 +4183,9 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
assert( sqlite3KeyInfoIsWriteable(pKey) );
for(i=0; i<nCol; i++){
char *zColl = pIdx->azColl[i];
if( NEVER(zColl==0) ) zColl = "BINARY";
pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl);
assert( zColl!=0 );
pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
sqlite3LocateCollSeq(pParse, zColl);
pKey->aSortOrder[i] = pIdx->aSortOrder[i];
}
if( pParse->nErr ){
+16
View File
@@ -1264,6 +1264,22 @@ int sqlite3ExprIsConstantOrFunction(Expr *p){
return exprIsConst(p, 2);
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
/*
** Walk an expression tree. Return 1 if the expression contains a
** subquery of some kind. Return 0 if there are no subqueries.
*/
int sqlite3ExprContainsSubquery(Expr *p){
Walker w;
memset(&w, 0, sizeof(w));
w.u.i = 1;
w.xExprCallback = sqlite3ExprWalkNoop;
w.xSelectCallback = selectNodeIsConstant;
sqlite3WalkExpr(&w, p);
return w.u.i==0;
}
#endif
/*
** If the expression p codes a constant integer that is small enough
** to fit in a 32-bit integer, return 1 and put the value of the integer
+1
View File
@@ -1086,6 +1086,7 @@ const char *sqlite3ErrName(int rc){
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break;
case SQLITE_READONLY_DBMOVED: zName = "SQLITE_READONLY_DBMOVED"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break;
+14 -4
View File
@@ -1315,6 +1315,15 @@ static int findInodeInfo(
return SQLITE_OK;
}
/*
** Return TRUE if pFile has been renamed or unlinked since it was first opened.
*/
static int fileHasMoved(unixFile *pFile){
struct stat buf;
return pFile->pInode!=0 &&
(osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
}
/*
** Check a unixFile that is a database. Verify the following:
@@ -1349,10 +1358,7 @@ static void verifyDbFile(unixFile *pFile){
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
if( pFile->pInode!=0
&& ((rc = osStat(pFile->zPath, &buf))!=0
|| buf.st_ino!=pFile->pInode->fileId.ino)
){
if( fileHasMoved(pFile) ){
sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
@@ -3801,6 +3807,10 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
case SQLITE_FCNTL_HAS_MOVED: {
*(int*)pArg = fileHasMoved(pFile);
return SQLITE_OK;
}
#if SQLITE_MAX_MMAP_SIZE>0
case SQLITE_FCNTL_MMAP_SIZE: {
i64 newLimit = *(i64*)pArg;
+37 -7
View File
@@ -4797,6 +4797,30 @@ int sqlite3PagerOpen(
}
/* Verify that the database file has not be deleted or renamed out from
** under the pager. Return SQLITE_OK if the database is still were it ought
** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
** code from sqlite3OsAccess()) if the database has gone missing.
*/
static int databaseIsUnmoved(Pager *pPager){
int bHasMoved = 0;
int rc;
if( pPager->tempFile ) return SQLITE_OK;
if( pPager->dbSize==0 ) return SQLITE_OK;
assert( pPager->zFilename && pPager->zFilename[0] );
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
if( rc==SQLITE_NOTFOUND ){
/* If the HAS_MOVED file-control is unimplemented, assume that the file
** has not been moved. That is the historical behavior of SQLite: prior to
** version 3.8.3, it never checked */
rc = SQLITE_OK;
}else if( rc==SQLITE_OK && bHasMoved ){
rc = SQLITE_READONLY_DBMOVED;
}
return rc;
}
/*
** This function is called after transitioning from PAGER_UNLOCK to
@@ -5473,13 +5497,19 @@ static int pager_open_journal(Pager *pPager){
(SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
(SQLITE_OPEN_MAIN_JOURNAL)
);
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
rc = sqlite3JournalOpen(
pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
);
#else
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
#endif
/* Verify that the database still has the same name as it did when
** it was originally opened. */
rc = databaseIsUnmoved(pPager);
if( rc==SQLITE_OK ){
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
rc = sqlite3JournalOpen(
pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
);
#else
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
#endif
}
}
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
}
+3 -3
View File
@@ -3689,7 +3689,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** Walker.xSelectCallback is set to do something useful for every
** subquery in the parser tree.
*/
static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return WRC_Continue;
}
@@ -3710,7 +3710,7 @@ static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
memset(&w, 0, sizeof(w));
w.xExprCallback = exprWalkNoop;
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
if( pParse->hasCompound ){
w.xSelectCallback = convertCompoundSelectToSubquery;
@@ -3774,7 +3774,7 @@ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
Walker w;
memset(&w, 0, sizeof(w));
w.xSelectCallback = selectAddSubqueryTypeInfo;
w.xExprCallback = exprWalkNoop;
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
w.bSelectDepthFirst = 1;
sqlite3WalkSelect(&w, pSelect);
+10 -1
View File
@@ -486,6 +486,7 @@ int sqlite3_exec(
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
@@ -553,7 +554,8 @@ int sqlite3_exec(
** after reboot following a crash or power loss, the only bytes in a
** file that were written at the application level might have changed
** and that adjacent bytes, even bytes within the same sector are
** guaranteed to be unchanged.
** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
** flag indicate that a file cannot be deleted when open.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -916,6 +918,12 @@ struct sqlite3_io_methods {
** SQLite stack may generate instances of this file control if
** the [SQLITE_USE_FCNTL_TRACE] compile-time option is enabled.
**
** <li>[[SQLITE_FCNTL_HAS_MOVED]]
** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a
** pointer to an integer and it writes a boolean into that integer depending
** on whether or not the file has been renamed, moved, or deleted since it
** was first opened.
**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -936,6 +944,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_TEMPFILENAME 16
#define SQLITE_FCNTL_MMAP_SIZE 18
#define SQLITE_FCNTL_TRACE 19
#define SQLITE_FCNTL_HAS_MOVED 20
/*
** CAPI3REF: Mutex Handle
+3
View File
@@ -1064,6 +1064,7 @@ struct sqlite3 {
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
#define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */
#define SQLITE_AdjustOutEst 0x1000 /* Adjust output estimates using WHERE */
#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
@@ -2616,6 +2617,7 @@ int sqlite3WalkExprList(Walker*, ExprList*);
int sqlite3WalkSelect(Walker*, Select*);
int sqlite3WalkSelectExpr(Walker*, Select*);
int sqlite3WalkSelectFrom(Walker*, Select*);
int sqlite3ExprWalkNoop(Walker*, Expr*);
/*
** Return code from the parse-tree walking primitives and their
@@ -2970,6 +2972,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
int sqlite3ExprIsConstant(Expr*);
int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*);
int sqlite3ExprContainsSubquery(Expr*);
int sqlite3ExprIsInteger(Expr*, int*);
int sqlite3ExprCanBeNull(const Expr*);
void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
+2
View File
@@ -3672,6 +3672,7 @@ static void init_all(Tcl_Interp *interp){
extern int Sqlitetest9_Init(Tcl_Interp*);
extern int Sqlitetestasync_Init(Tcl_Interp*);
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
extern int Sqlitetest_cursorhint_Init(Tcl_Interp*);
extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
extern int Sqlitetest_func_Init(Tcl_Interp*);
extern int Sqlitetest_hexio_Init(Tcl_Interp*);
@@ -3715,6 +3716,7 @@ static void init_all(Tcl_Interp *interp){
Sqlitetest9_Init(interp);
Sqlitetestasync_Init(interp);
Sqlitetest_autoext_Init(interp);
Sqlitetest_cursorhint_Init(interp);
Sqlitetest_demovfs_Init(interp);
Sqlitetest_func_Init(interp);
Sqlitetest_hexio_Init(interp);
+162
View File
@@ -0,0 +1,162 @@
/*
** 2008 March 19
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** implements new SQL functions used by the test scripts.
*/
#include "sqlite3.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sqliteInt.h"
#include "vdbeInt.h"
struct CursorHintGlobal {
Tcl_Interp *interp;
Tcl_Obj *pScript;
} cursorhintglobal;
static char *exprToString(Mem *aMem, Expr *pExpr){
char *zRet = 0;
char *zBinOp = 0;
switch( pExpr->op ){
case TK_STRING:
zRet = sqlite3_mprintf("%Q", pExpr->u.zToken);
break;
case TK_INTEGER:
zRet = sqlite3_mprintf("%d", pExpr->u.iValue);
break;
case TK_NULL:
zRet = sqlite3_mprintf("%s", "NULL");
break;
case TK_REGISTER: {
Mem *pMem = &aMem[pExpr->iTable];
if( pMem->flags & MEM_Int ){
zRet = sqlite3_mprintf("%lld", pMem->u.i);
}
else if( pMem->flags & MEM_Real ){
zRet = sqlite3_mprintf("%f", pMem->r);
}
else if( pMem->flags & MEM_Str ){
zRet = sqlite3_mprintf("%.*Q", pMem->n, pMem->z);
}
else if( pMem->flags & MEM_Blob ){
}
else{
zRet = sqlite3_mprintf("%s", "NULL");
}
break;
}
case TK_COLUMN: {
zRet = sqlite3_mprintf("col(%d)", (int)pExpr->iColumn);
break;
}
case TK_LT: zBinOp = "<"; break;
case TK_LE: zBinOp = "<="; break;
case TK_GT: zBinOp = ">"; break;
case TK_GE: zBinOp = ">="; break;
case TK_NE: zBinOp = "!="; break;
case TK_EQ: zBinOp = "=="; break;
case TK_IS: zBinOp = "IS"; break;
case TK_ISNOT: zBinOp = "IS NOT"; break;
case TK_AND: zBinOp = "AND"; break;
case TK_OR: zBinOp = "OR"; break;
case TK_PLUS: zBinOp = "+"; break;
case TK_STAR: zBinOp = "*"; break;
case TK_MINUS: zBinOp = "-"; break;
case TK_REM: zBinOp = "%"; break;
case TK_BITAND: zBinOp = "&"; break;
case TK_BITOR: zBinOp = "|"; break;
case TK_SLASH: zBinOp = "/"; break;
case TK_LSHIFT: zBinOp = "<<"; break;
case TK_RSHIFT: zBinOp = ">>"; break;
case TK_CONCAT: zBinOp = "||"; break;
default:
zRet = sqlite3_mprintf("%s", "expr");
break;
}
if( zBinOp ){
zRet = sqlite3_mprintf("(%z %s %z)",
exprToString(aMem, pExpr->pLeft),
zBinOp,
exprToString(aMem, pExpr->pRight)
);
}
return zRet;
}
void sqlite3BtreeCursorHintTest(Mem *aMem, Expr *pExpr){
if( cursorhintglobal.pScript ){
Tcl_Obj *pEval = Tcl_DuplicateObj(cursorhintglobal.pScript);
char *zExpr;
Tcl_Obj *pObj;
Tcl_IncrRefCount(pEval);
zExpr = exprToString(aMem, pExpr);
pObj = Tcl_NewStringObj(zExpr, -1);
sqlite3_free(zExpr);
Tcl_ListObjAppendElement(cursorhintglobal.interp, pEval, pObj);
Tcl_EvalObjEx(cursorhintglobal.interp, pEval, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(pEval);
}
}
/*
** Usage: cursorhint_hook SCRIPT
*/
static int install_cursorhint_hook(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
if( objc!=1 && objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "?SCRIPT?");
return TCL_ERROR;
}
if( cursorhintglobal.pScript ){
Tcl_DecrRefCount(cursorhintglobal.pScript);
memset(&cursorhintglobal, 0, sizeof(cursorhintglobal));
}
if( objc==2 ){
cursorhintglobal.interp = interp;
cursorhintglobal.pScript = Tcl_DuplicateObj(objv[1]);
}
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_cursorhint_Init(Tcl_Interp *interp){
static struct {
char *zName;
Tcl_ObjCmdProc *xProc;
} aObjCmd[] = {
{ "cursorhint_hook", install_cursorhint_hook },
};
int i;
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
}
sqlite3_initialize();
return TCL_OK;
}
+5
View File
@@ -258,6 +258,11 @@ static void vfstrace_print_errcode(
case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
case SQLITE_IOERR_SHMMAP: zVal = "SQLITE_IOERR_SHMMAP"; break;
case SQLITE_IOERR_SEEK: zVal = "SQLITE_IOERR_SEEK"; break;
case SQLITE_IOERR_GETTEMPPATH: zVal = "SQLITE_IOERR_GETTEMPPATH"; break;
case SQLITE_IOERR_CONVPATH: zVal = "SQLITE_IOERR_CONVPATH"; break;
case SQLITE_READONLY_DBMOVED: zVal = "SQLITE_READONLY_DBMOVED"; break;
case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
+24
View File
@@ -6170,6 +6170,30 @@ case OP_Trace: {
}
#endif
#ifdef SQLITE_ENABLE_CURSOR_HINTS
/* Opcode: CursorHint P1 P2 * P4 *
**
** Provide a hint to cursor P1 that it only needs to return rows that
** satisfy the Expr tree given in P4. P2 is the table number of cursor P1
** such that references to cursor P1 in the Expr tree are given by
** Expr.iTable==P2.
*/
case OP_CursorHint: {
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p4type==P4_EXPR );
pC = p->apCsr[pOp->p1];
if( pC ){
sqlite3BtreeCursorHint(pC->pCursor, pOp->p2, pOp->p4.pExpr);
#ifdef SQLITE_TEST
void sqlite3BtreeCursorHintTest(Mem*, Expr*);
sqlite3BtreeCursorHintTest(p->aMem, pOp->p4.pExpr);
#endif
}
break;
}
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
/* Opcode: Noop * * * * *
**
+4
View File
@@ -59,6 +59,9 @@ struct VdbeOp {
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
int *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
int (*xAdvance)(BtCursor *, int *);
} p4;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
@@ -106,6 +109,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */
#define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */
#define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */
#define P4_EXPR (-7) /* P4 is a pointer to an Expr tree */
#define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */
#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
#define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */
+11
View File
@@ -26,6 +26,17 @@
# define SQLITE_MAX_SCHEMA_RETRY 50
#endif
/*
** VDBE_DISPLAY_P4 is true or false depending on whether or not the
** "explain" P4 display logic is enabled.
*/
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|| defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
# define VDBE_DISPLAY_P4 1
#else
# define VDBE_DISPLAY_P4 0
#endif
/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine. Each instruction is an instance
+93 -3
View File
@@ -639,6 +639,12 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
break;
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
case P4_EXPR: {
sqlite3ExprDelete(db, (Expr*)p4);
break;
}
#endif
case P4_MPRINTF: {
if( db->pnBytesFreed==0 ) sqlite3_free(p4);
break;
@@ -756,6 +762,15 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
}else if( n==P4_KEYINFO ){
pOp->p4.p = (void*)zP4;
pOp->p4type = P4_KEYINFO;
#ifdef SQLITE_ENABLE_CURSOR_HINTS
}else if( n==P4_EXPR ){
/* Responsibility for deleting the Expr tree is handed over to the
** VDBE by this operation. The caller should have already invoked
** sqlite3ExprDup() or whatever other routine is needed to make a
** private copy of the tree. */
pOp->p4.pExpr = (Expr*)zP4;
pOp->p4type = P4_EXPR;
#endif
}else if( n==P4_VTAB ){
pOp->p4.p = (void*)zP4;
pOp->p4type = P4_VTAB;
@@ -932,9 +947,78 @@ static int displayComment(
}
#endif /* SQLITE_DEBUG */
#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
/*
** Translate the P4.pExpr value for an OP_CursorHint opcode into text
** that can be displayed in the P4 column of EXPLAIN output.
*/
static int displayP4Expr(int nTemp, char *zTemp, Expr *pExpr){
const char *zBinOp = 0;
switch( pExpr->op ){
case TK_STRING:
sqlite3_snprintf(nTemp, zTemp, "%Q", pExpr->u.zToken);
break;
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|| defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
case TK_INTEGER:
sqlite3_snprintf(nTemp, zTemp, "%d", pExpr->u.iValue);
break;
case TK_NULL:
sqlite3_snprintf(nTemp, zTemp, "NULL");
break;
case TK_REGISTER: {
sqlite3_snprintf(nTemp, zTemp, "r[%d]", pExpr->iTable);
break;
}
case TK_COLUMN: {
sqlite3_snprintf(nTemp, zTemp, "c%d", (int)pExpr->iColumn);
break;
}
case TK_LT: zBinOp = "<"; break;
case TK_LE: zBinOp = "<="; break;
case TK_GT: zBinOp = ">"; break;
case TK_GE: zBinOp = ">="; break;
case TK_NE: zBinOp = "!="; break;
case TK_EQ: zBinOp = "=="; break;
case TK_IS: zBinOp = " IS "; break;
case TK_ISNOT: zBinOp = " IS NOT "; break;
case TK_AND: zBinOp = " AND "; break;
case TK_OR: zBinOp = " OR "; break;
case TK_PLUS: zBinOp = "+"; break;
case TK_STAR: zBinOp = "*"; break;
case TK_MINUS: zBinOp = "-"; break;
case TK_REM: zBinOp = "%"; break;
case TK_BITAND: zBinOp = "&"; break;
case TK_BITOR: zBinOp = "|"; break;
case TK_SLASH: zBinOp = "/"; break;
case TK_LSHIFT: zBinOp = "<<"; break;
case TK_RSHIFT: zBinOp = ">>"; break;
case TK_CONCAT: zBinOp = "||"; break;
default:
sqlite3_snprintf(nTemp, zTemp, "%s", "expr");
break;
}
if( zBinOp && nTemp>5 ){
int n = 1;
zTemp[0] = '(';
n += displayP4Expr(nTemp-n, zTemp+n, pExpr->pLeft);
sqlite3_snprintf(nTemp-n, zTemp+n, "%s", zBinOp);
n += sqlite3Strlen30(zTemp+n);
n += displayP4Expr(nTemp-n, zTemp+n, pExpr->pRight);
sqlite3_snprintf(nTemp-n, zTemp+n, ")");
}
return sqlite3Strlen30(zTemp);
}
#endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */
#if VDBE_DISPLAY_P4
/*
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
@@ -973,6 +1057,12 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
assert( i<nTemp );
break;
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
case P4_EXPR: {
displayP4Expr(nTemp, zTemp, pOp->p4.pExpr);
break;
}
#endif
case P4_COLLSEQ: {
CollSeq *pColl = pOp->p4.pColl;
sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName);
@@ -1041,7 +1131,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
assert( zP4!=0 );
return zP4;
}
#endif
#endif /* VDBE_DISPLAY_P4 */
/*
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
+87
View File
@@ -2715,6 +2715,90 @@ static void explainOneScan(
# define explainOneScan(u,v,w,x,y,z)
#endif /* SQLITE_OMIT_EXPLAIN */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
/*
** This function is called on every node of an expression tree used as an
** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN
** that accesses any cursor other than (pWalker->u.i), do the following:
**
** 1) allocate a register and code an OP_Column instruction to read
** the specified column into the new register, and
**
** 2) transform the expression node to a TK_REGISTER node that reads
** from the newly populated register.
*/
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
int rc = WRC_Continue;
if( pExpr->op==TK_COLUMN && pExpr->iTable!=pWalker->u.i ){
Vdbe *v = pWalker->pParse->pVdbe;
int reg = ++pWalker->pParse->nMem; /* Register for column value */
sqlite3ExprCodeGetColumnOfTable(
v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg
);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pExpr->op==TK_AGG_FUNCTION ){
/* An aggregate function in the WHERE clause of a query means this must
** be a correlated sub-query, and expression pExpr is an aggregate from
** the parent context. Do not walk the function arguments in this case.
**
** todo: It should be possible to replace this node with a TK_REGISTER
** expression, as the result of the expression must be stored in a
** register at this point. The same holds for TK_AGG_COLUMN nodes. */
rc = WRC_Prune;
}
return rc;
}
/*
** Insert an OP_CursorHint instruction if it is appropriate to do so.
*/
static void codeCursorHint(
WhereInfo *pWInfo,
int iLevel
){
Parse *pParse = pWInfo->pParse;
sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe;
WhereLevel *pLevel;
Expr *pExpr = 0;
int iCur;
WhereClause *pWC;
WhereTerm *pTerm;
WhereLoop *pWLoop;
int i, j;
if( OptimizationDisabled(db, SQLITE_CursorHints) ) return;
pLevel = &pWInfo->a[iLevel];
pWLoop = pLevel->pWLoop;
iCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor;
pWC = &pWInfo->sWC;
for(i=0; i<pWC->nTerm; i++){
pTerm = &pWC->a[i];
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( pTerm->prereqAll & pLevel->notReady ) continue;
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue;
for(j=0; j<pWLoop->nLTerm && pWLoop->aLTerm[j]!=pTerm; j++){}
if( j<pWLoop->nLTerm ) continue;
pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
}
if( pExpr!=0 ){
const char *a = (const char*)pExpr;
Walker sWalker;
memset(&sWalker, 0, sizeof(sWalker));
sWalker.xExprCallback = codeCursorHintFixExpr;
sWalker.pParse = pParse;
sWalker.u.i = pLevel->iTabCur;
sqlite3WalkExpr(&sWalker, pExpr);
sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0, a, P4_EXPR);
}
}
#else
# define codeCursorHint(A,B) /* No-op */
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
@@ -2876,6 +2960,7 @@ static Bitmask codeOneLoopStart(
pStart = pEnd;
pEnd = pTerm;
}
codeCursorHint(pWInfo, iLevel);
if( pStart ){
Expr *pX; /* The expression that defines the start bound */
int r1, rTemp; /* Registers for holding the start boundary */
@@ -3061,6 +3146,7 @@ static Bitmask codeOneLoopStart(
start_constraints = pRangeStart || nEq>0;
/* Seek the index cursor to the start of the range. */
codeCursorHint(pWInfo, iLevel);
nConstraint = nEq;
if( pRangeStart ){
Expr *pRight = pRangeStart->pExpr->pRight;
@@ -3408,6 +3494,7 @@ static Bitmask codeOneLoopStart(
static const u8 aStep[] = { OP_Next, OP_Prev };
static const u8 aStart[] = { OP_Rewind, OP_Last };
assert( bRev==0 || bRev==1 );
codeCursorHint(pWInfo, iLevel);
pLevel->op = aStep[bRev];
pLevel->p1 = iCur;
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
+72
View File
@@ -0,0 +1,72 @@
# 2014 July 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix cursorhint
do_execsql_test 1.0 {
CREATE TABLE t1(a,b);
CREATE TABLE t2(x,y);
INSERT INTO t1 VALUES(10, 15);
INSERT INTO t1 VALUES(20, 25);
INSERT INTO t2 VALUES('ten', 'fifteen');
INSERT INTO t2 VALUES('twenty', 'twentyfive');
PRAGMA automatic_index = 0;
}
proc H {expr} {
lappend ::cursorhint $expr
}
proc do_cursorhint_test {tn sql hints} {
cursorhint_hook H
set ::cursorhint [list]
set testbody [subst {
execsql {$sql}
set ::cursorhint
}]
uplevel [list do_test $tn $testbody [list {*}$hints]]
cursorhint_hook
}
do_cursorhint_test 1.1 {
SELECT * FROM t1 CROSS JOIN t2 WHERE a=x;
} {
{(10 == col(0))}
{(20 == col(0))}
}
do_cursorhint_test 1.2 {
SELECT * FROM t2 CROSS JOIN t1 WHERE a=x;
} {
{(col(0) == 'ten')}
{(col(0) == 'twenty')}
}
do_cursorhint_test 1.3 {
SELECT * FROM t1 CROSS JOIN t2 WHERE b=15;
} {
{(col(1) == 15)}
}
do_cursorhint_test 1.3 {
SELECT * FROM t1 CROSS JOIN t2 WHERE y=b+1;
} {
{(col(1) == (15 + 1))}
{(col(1) == (25 + 1))}
}
finish_test
+94
View File
@@ -0,0 +1,94 @@
# 2013-12-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.
#
#***********************************************************************
#
# Tests for the SQLITE_IOERR_NODB error condition: the database file file
# is unlinked or renamed out from under SQLite.
#
if {$tcl_platform(platform)!="unix"} return
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a database file for testing
#
do_execsql_test pager4-1.1 {
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(673,'stone','philips');
SELECT * FROM t1;
} {673 stone philips}
# After renaming the database file while it is open, one can still
# read from the database, but writing returns a READONLY error.
#
file delete -force test-xyz.db
file rename test.db test-xyz.db
do_catchsql_test pager4-1.2 {
SELECT * FROM t1;
} {0 {673 stone philips}}
do_catchsql_test pager4-1.3 {
UPDATE t1 SET a=537;
} {1 {attempt to write a readonly database}}
# Creating a different database file with the same name of the original
# is detected and still leaves the database read-only.
#
sqlite3 db2 test.db
db2 eval {CREATE TABLE t2(x,y,z)}
do_catchsql_test pager4-1.4 {
UPDATE t1 SET a=948;
} {1 {attempt to write a readonly database}}
# Changing the name back clears the READONLY error
#
db2 close
file delete -force test.db
file rename test-xyz.db test.db
do_catchsql_test pager4-1.5 {
SELECT * FROM t1;
} {0 {673 stone philips}}
do_catchsql_test pager4-1.6 {
UPDATE t1 SET a=537;
SELECT * FROM t1;
} {0 {537 stone philips}}
# We can write to a renamed database if journal_mode=OFF or
# journal_mode=MEMORY.
#
file rename test.db test-xyz.db
do_catchsql_test pager4-1.7 {
PRAGMA journal_mode=OFF;
UPDATE t1 SET a=107;
SELECT * FROM t1;
} {0 {off 107 stone philips}}
do_catchsql_test pager4-1.8 {
PRAGMA journal_mode=MEMORY;
UPDATE t1 SET b='magpie';
SELECT * FROM t1;
} {0 {memory 107 magpie philips}}
# Any other journal mode gives a READONLY error
#
do_catchsql_test pager4-1.9 {
PRAGMA journal_mode=DELETE;
UPDATE t1 SET c='jaguar';
} {1 {attempt to write a readonly database}}
do_catchsql_test pager4-1.10 {
PRAGMA journal_mode=TRUNCATE;
UPDATE t1 SET c='jaguar';
} {1 {attempt to write a readonly database}}
do_catchsql_test pager4-1.11 {
PRAGMA journal_mode=PERSIST;
UPDATE t1 SET c='jaguar';
} {1 {attempt to write a readonly database}}
finish_test