Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fc3300b2b | |||
| 91d3a61f8a | |||
| 159c1a18db | |||
| 5b88bc4bec | |||
| 28935364ef | |||
| 9dcc7cd527 | |||
| 689156fdbc | |||
| a9c19f935c | |||
| b959a017b6 | |||
| 4e8fe3ff91 | |||
| b8a9bb4fb9 | |||
| 72b8ef6ce3 | |||
| 091a81b91d | |||
| 3fee8a63c8 | |||
| 1b1f30bb5e |
@@ -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'`\\"
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
@@ -1 +1 @@
|
||||
27392118af4c38c5203a04b8013e1afdb1cebd0d
|
||||
12640cb22240ee436cad99360ceb9a208edd14f5
|
||||
+22
-14
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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 * * * * *
|
||||
**
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user