aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.msc9
-rw-r--r--VERSION2
-rw-r--r--autoconf/tea/README.txt61
-rw-r--r--autoconf/tea/doc/sqlite3.n15
-rw-r--r--ext/wasm/GNUmakefile4
-rw-r--r--main.mk6
-rw-r--r--manifest76
-rw-r--r--manifest.uuid2
-rw-r--r--src/btree.c11
-rw-r--r--src/dbpage.c13
-rw-r--r--src/expr.c8
-rw-r--r--src/json.c4
-rw-r--r--src/os_unix.c11
-rw-r--r--src/os_win.c15
-rw-r--r--src/pager.c9
-rw-r--r--src/select.c18
-rw-r--r--src/shell.c.in13
-rw-r--r--src/sqliteInt.h28
-rw-r--r--src/tclsqlite.c138
-rw-r--r--src/test1.c5
-rw-r--r--src/vacuum.c3
-rw-r--r--src/vdbe.c3
-rw-r--r--src/vdbe.h2
-rw-r--r--src/vdbeapi.c2
-rw-r--r--src/vdbeaux.c26
-rw-r--r--src/vdbesort.c16
-rw-r--r--src/wal.c3
-rw-r--r--test/dblwidth-a.sql20
-rw-r--r--test/fts3join.test5
-rw-r--r--test/join.test22
-rw-r--r--test/joinH.test70
-rw-r--r--test/snapshot3.test3
-rw-r--r--test/tclsqlite.test153
-rw-r--r--test/vacuum.test21
-rw-r--r--test/walsetlk_recover.test104
-rw-r--r--test/walsetlk_snapshot.test109
-rw-r--r--tool/sqlite3_rsync.c3
37 files changed, 763 insertions, 250 deletions
diff --git a/Makefile.msc b/Makefile.msc
index 6aef67155..644e8e855 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -2674,7 +2674,14 @@ srctree-check: $(TOP)\tool\srctree-check.tcl
# Testing for a release
#
-releasetest:
+releasetest: verify-source
+ $(TCLSH_CMD) $(TOP)\test\testrunner.tcl release
+
+# xdevtest is like releasetest, except that it skips the
+# dependency on verify-source so that xdevtest can be run from
+# a modified source tree.
+#
+xdevtest:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl release
diff --git a/VERSION b/VERSION
index ca25ff637..84ba969c4 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.50.0
+3.51.0
diff --git a/autoconf/tea/README.txt b/autoconf/tea/README.txt
index 28f23a88d..122b08d32 100644
--- a/autoconf/tea/README.txt
+++ b/autoconf/tea/README.txt
@@ -41,24 +41,32 @@ step-by-step instructions at the links below for more information:
https://sqlite.org/src/doc/trunk/doc/compile-for-unix.md
https://sqlite.org/src/doc/trunk/doc/compile-for-windows.md
+And info about the extension's Tcl interface can be found at:
+
+ https://sqlite.org/tclsqlite.html
+
The whole point of the amalgamation-autoconf tarball (in which this
-README.txt file is embedded) is to provide a means of compiling
-SQLite that does not require first installing TCL and/or "tclsh".
-The canonical Makefile in the SQLite source tree provides more
-capabilities (such as the the ability to run test cases to ensure
-that the build worked) and is better maintained. The only
-downside of the canonical Makefile is that it requires a TCL
-installation. But if you are wanting to build the TCL extension for
-SQLite, then presumably you already have a TCL installation. So why
-not just use the more-capable and better-maintained canoncal Makefile?
-
-This TEA builder is derived from code found at
+README.txt file is embedded) is to provide a means of compiling SQLite
+that does not require first installing TCL and/or "tclsh". The
+canonical Makefile in the SQLite source tree provides more
+capabilities (such as the the ability to run test cases to ensure that
+the build worked) and is better maintained. The only downside of the
+canonical Makefile is that it requires a TCL installation. But if you
+are wanting to build the TCL extension for SQLite, then presumably you
+already have a TCL installation. So why not just use the more-capable
+and better-maintained canoncal Makefile?
+
+As of version 3.50.0, this build process uses "teaish":
+
+ https://fossil.wanderinghorse.net/r/teaish
+
+which is conceptually derived from the pre-3.50 toolchain, TEA:
http://core.tcl-lang.org/tclconfig
http://core.tcl-lang.org/sampleextension
-The SQLite developers do not understand how it works. It seems to
-work for us. It might also work for you. But we cannot promise that.
+It to works for us. It might also work for you. But we cannot
+promise that.
If you want to use this TEA builder and it works for you, that's fine.
But if you have trouble, the first thing you should do is go back
@@ -70,30 +78,17 @@ to using the canonical Makefile in the SQLite source tree.
UNIX BUILD
==========
-Building under most UNIX systems is easy, just run the configure script
-and then run make. For more information about the build process, see
-the tcl/unix/README file in the Tcl src dist. The following minimal
-example will install the extension in the /opt/tcl directory.
+Building under most UNIX systems is easy, just run the configure
+script and then run make. For example:
$ cd sqlite-*-tea
- $ ./configure --prefix=/opt/tcl
- $ make
+ $ ./configure --with-tcl=/path/to/tcl/install/root
+ $ make test
$ make install
WINDOWS BUILD
=============
-The recommended method to build extensions under windows is to use the
-Msys + Mingw build process. This provides a Unix-style build while
-generating native Windows binaries. Using the Msys + Mingw build tools
-means that you can use the same configure script as per the Unix build
-to create a Makefile. See the tcl/win/README file for the URL of
-the Msys + Mingw download.
-
-If you have VC++ then you may wish to use the files in the win
-subdirectory and build the extension using just VC++. These files have
-been designed to be as generic as possible but will require some
-additional maintenance by the project developer to synchronise with
-the TEA configure.in and Makefile.in files. Instructions for using the
-VC++ makefile are written in the first part of the Makefile.vc
-file.
+On Windows this build is known to work on Cygwin and some Msys2
+environments. We do not currently support Microsoft makefiles for
+native Windows builds.
diff --git a/autoconf/tea/doc/sqlite3.n b/autoconf/tea/doc/sqlite3.n
deleted file mode 100644
index 351404634..000000000
--- a/autoconf/tea/doc/sqlite3.n
+++ /dev/null
@@ -1,15 +0,0 @@
-.TH sqlite3 n 4.1 "Tcl-Extensions"
-.HS sqlite3 tcl
-.BS
-.SH NAME
-sqlite3 \- an interface to the SQLite3 database engine
-.SH SYNOPSIS
-\fBsqlite3\fI command_name ?filename?\fR
-.br
-.SH DESCRIPTION
-SQLite3 is a self-contains, zero-configuration, transactional SQL database
-engine. This extension provides an easy to use interface for accessing
-SQLite database files from Tcl.
-.PP
-For full documentation see \fIhttps://sqlite.org/\fR and
-in particular \fIhttps://sqlite.org/tclsqlite.html\fR.
diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile
index 6470fd630..28387872f 100644
--- a/ext/wasm/GNUmakefile
+++ b/ext/wasm/GNUmakefile
@@ -598,8 +598,6 @@ emcc.flags += -v
endif
-# wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
-# Emscripten 4.0.7 (2025-04-15) stops exporting HEAP* by default
########################################################################
# emcc flags for .c/.o.
emcc.cflags :=
@@ -619,6 +617,8 @@ emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
emcc.exportedRuntimeMethods := \
-sEXPORTED_RUNTIME_METHODS=wasmMemory,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAP64,HEAPU64
+# wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
+# Emscripten 4.0.7 (2025-04-15) stops exporting HEAP* by default
emcc.jsflags += $(emcc.exportedRuntimeMethods)
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
emcc.jsflags += -sIMPORTED_MEMORY
diff --git a/main.mk b/main.mk
index 88c641b70..fe874b1f3 100644
--- a/main.mk
+++ b/main.mk
@@ -1835,6 +1835,12 @@ mdevtest: srctree-check has_tclsh85
sdevtest: has_tclsh85
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl sdevtest $(TSTRNNR_OPTS)
+# Like releasetest, except it omits srctree-check and verify-source so
+# that it can be used on a modified source tree.
+#
+xdevtest: has_tclsh85
+ $(TCLSH_CMD) $(TOP)/test/testrunner.tcl release $(TSTRNNR_OPTS)
+
#
# Validate that various generated files in the source tree
# are up-to-date.
diff --git a/manifest b/manifest
index 2ab4f5294..a74d89470 100644
--- a/manifest
+++ b/manifest
@@ -1,14 +1,14 @@
-C When\ssynthesizing\san\sON\sconstraint\sfrom\sa\sUSING\sor\sNATURAL,\sif\sthe\sleft-hand\nside\sis\scoming\sfrom\sa\sRIGHT\sJOIN,\sbe\ssure\sto\sset\sthe\sEP_CanBeNull\sflag\sso\sthat\nthe\soptimizer\sknows\sto\scheck\sfor\sNULL\seven\sif\sthe\scolumn\shas\sa\sNOT\sNULL\nconstraint.\s\sFix\sfor\sthe\sproblem\sreported\sby\n[forum:/forumpost/4fc70203b61c7e12|forum\spost\s4fc70203b61]
-D 2025-05-30T19:55:46.105
+C Enhance\ssqlite3_rsync\sso\sthat\sit\sworks\seven\sif\sthe\sreplica\sdatabase\sis\ninitially\smalformed.
+D 2025-06-03T10:49:51.412
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
F Makefile.in c3e414df4dc8dfb12f1f6baf129fcb6d18cd0ebd3c9109370fb3fceeeef9a37a
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
-F Makefile.msc 0206f28988bb6634c7e8aff05bf6cfa65d6dfe1d2b6bd95160dd99290a83dfc7
+F Makefile.msc aa4f9ae86cf59fe94a3e93bf1a4c241b3ffffe96cf4d823517acf593c277223b
F README.md e28077cfbef795e99c9c75ed95aa7257a1166709b562076441a8506ac421b7c1
-F VERSION 001dea55eb8304ec9130b6b44a32d3fc349f279d45a7e224fc0730c3cb8e2372
+F VERSION 16eddb43056a79c1977427ab7a05f3457c373fa159dcdced8754eb89ce7e06b8
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
@@ -23,11 +23,10 @@ F autoconf/README.first f1d3876e9a7852c22f275a6f06814e64934cecbc0b5b9617d6484909
F autoconf/README.txt b749816b8452b3af994dc6d607394bef3df1736d7e09359f1087de8439a52807
F autoconf/auto.def 3d994f3a9cc9b712dbce92a5708570ddcf3b988141b6eb738f2ed16127a9f0ac
F autoconf/tea/Makefile.in bf6b43eafcd18766d81a8f0085cfc9cb051d8abae9031a8e7c3f5f1246e8f166
-F autoconf/tea/README.txt 656d4686c509d375f5988ff3deda94f65fe6cd8358cd55d1f1dcc7b6e2ff73aa
+F autoconf/tea/README.txt 23475876343498ef2b514cc7510e8f1559a17e8e03fbc7a41c1c8a3b89e7b7e3
F autoconf/tea/_teaish.tester.tcl.in 8253b44be88e2e3f21de95a65d3a90c2be8e70b7bdd08a5b80e337ba7402f8f1
F autoconf/tea/auto.def ce95b9450e2fa4ba5dc857e208fe10f4e6f2d737796ac3278aee6079db417529
F autoconf/tea/configure d0b12b984edca6030d1976375b80157ac78b5b90a5b4f0dcee39357f63f4a80b x
-F autoconf/tea/doc/sqlite3.n 9a97f4f717ceab73004ea412af7960625c1cb24b5c25e4ae4c8b5d8fa4300f4e
F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523
F autoconf/tea/pkgIndex.tcl.in e07da6b94561f4aa382bab65b1ccceb04701b97bf59d007c1d1f20a222b22d07
F autoconf/tea/teaish.tcl a2224762a039ed30c45cc1ce4b2fde5667fb0aa2569bb56590f5cb5d45d7410b
@@ -621,7 +620,7 @@ F ext/session/sqlite3session.c 6b0877fe1ab832aa4b85eaca72606dfd1630a1363a1be7af1
F ext/session/sqlite3session.h 9bb1a6687b467764b35178dc29bbd2c57ab8cd3acdc8a62f088c34ad17e4fe2b
F ext/session/test_session.c 2ddff73ea368d827028c32851b291416e1008845832feb27b751d15e57e13cc3
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
-F ext/wasm/GNUmakefile d6b869cf3d3eaaec8cf56adf925910c3e443f455562bcb4a4cd2d1e43c933d8d
+F ext/wasm/GNUmakefile e315b903c33b28ca074367041849de9dd2681c96d1437c11a5e9596abc265012
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
F ext/wasm/README.md b89605f65661cf35bf034ff6d43e448cc169b8017fc105d498e33b81218b482c
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
@@ -709,7 +708,7 @@ F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
F ext/wasm/wasmfs.make 68999f5bd8c489239592d59a420f8c627c99169bbd6fa16a404751f757b9f702
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
-F main.mk 517db864e770c486bd1465298c20d91899918d395263266997d477b20ef9eec8
+F main.mk 34290a772ec671de1fa5defd4fa4074aad24b1ea7eaabebba071e30564c6498c
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
@@ -726,17 +725,17 @@ F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
F src/bitvec.c 782cc29b42b47e7ec6348eb0aaf9ffe60063f498387e7249f458d445af4b53e9
F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
-F src/btree.c 00fcee37947641f48d4b529d96143e74d056b7afa8f26d61292c90ee59c056b2
+F src/btree.c 53a9c7b243e94c992853d90f1dac0959028433b4b0d27e04409cee04e001b508
F src/btree.h 18e5e7b2124c23426a283523e5f31a4bff029131b795bb82391f9d2f3136fc50
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
F src/build.c 67c1db4c5e89a8519fe9b6dafc287f6bc3627696b5b8536dc5e06db570d8c05f
F src/callback.c acae8c8dddda41ee85cfdf19b926eefe830f371069f8aadca3aa39adf5b1c859
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/date.c 9db4d604e699a73e10b8e85a44db074a1f04c0591a77e2abfd77703f50dce1e9
-F src/dbpage.c fcb1aafe00872a8aff9a7aa0ef7ff1b01e5817ec7bbd521f8f3e1e674ac8d609
+F src/dbpage.c b3e218f8ed74fcbb7fa805df8ca669a3718d397617b3d8a8aac3307dc315c4d6
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
-F src/expr.c 6f184da1f36576ad1ecc48a03f14774235373c64f88d462c710834930ee6c145
+F src/expr.c f16fa5cbd849991462edf1d31bb7def5b970bb9611afcb4ea21c77e88e52a220
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
F src/func.c 7686ea382b20e8bfe2ab9de76150c99ee7b6e83523561f3c7787e0f68cb435c2
@@ -746,7 +745,7 @@ F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c d05934dfab2c5c0c480fc6fd2038f11215661de08ea6ff38d2563216bd555c1b
-F src/json.c d34969ecb9555f33fc0b2227628189a9a4e20dda5df5d173db9918a014aa7ad1
+F src/json.c cb87977b1ee25ee7d27505d65a9261b687395bf895342c8ba566b7c01aee2047
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c d7edd8e671237539d795d30daaf888908a2c82e99bade4c78f3be021e8b7d655
F src/main.c 07f78d917ffcdf327982840cfd8e855fd000527a2ea5ace372ce4febcbd0bf97
@@ -770,10 +769,10 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
-F src/os_unix.c 410185df4900817c218c0efdb8064b3481af88cb3f7cea7392f820b6eebc7889
-F src/os_win.c b39f31fb0b137d67091d21880f0fded6b1c3c8c59b9e24e42844a1c0070437d4
+F src/os_unix.c 04e054ab86d86a7be99ebe5265922687791a40df5afc781d059beb47f4a40acd
+F src/os_win.c b8d3cfdf2f40e2f9715b7d8df64f3c0c7ee18743a2dd0c4fc70c1d57fa1aadc7
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
-F src/pager.c 9fbb541b46125dfa8914827575e6bb4d15048caa008073b1709112d495d7983b
+F src/pager.c 23c0f17deb892da6b32fef1f465507df7ab5cd01d774288cb43695658a649259
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
F src/parse.y e426d7323311554c75b0aebc426d0fe3c88d9777ffefed236f343ad9e661dc4c
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
@@ -785,18 +784,18 @@ F src/printf.c 3b91c334f528359145f4dde0dedd945bbb21044d0825ea064934d7222d61662c
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c d40fe18d7c2fd0339f5846ffcf7d6809866e380acdf14c76fb2af87e9fe13f64
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c 571fff5cf453c3cafc122873b982dff39075e1edd1afec707216c9b534fde7bf
-F src/shell.c.in ba53a52dafb167ac6320703da741386c34fbcabe8c078a188bb9f89808e3ef8f
+F src/select.c 882d739e0d5e6c7a8b46a3cca3ada37fe1a56301f1360d6b141312c666bbe482
+F src/shell.c.in 1da613953db4c8d50e3a4a66fa7d69b4c95edb3628941d732637d3c35ea0dce6
F src/sqlite.h.in 22882ddd3a70751aa8864c81993ee4562ed54c2c508b6270f75e223ffee38e1b
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 0bfd049bb2088cc44c2ad54f2079d1c6e43091a4e1ce8868779b75f6c1484f1e
-F src/sqliteInt.h bb9137b860b2416b12788f09b32384ceab96b720aae07a6e9afacc545e43619a
+F src/sqliteInt.h 0eeb2d363e7994aba3b482d3a9c88248b4d1fdad39cb65ff48621b2ae494a763
F src/sqliteLimit.h 6d817c28a8f19af95e6f4921933b7fbbca48a962bce0eb0ec81e8bb3ef38e68b
F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c d0e63ffe7944dd223bf62066d9f982cbee1978811c7fbfd889f4ba9c5baed3d1
+F src/tclsqlite.c 3c604c49e6cf4211960a9ddb9505280fd22cde32175f40884c641c0f5a286036
F src/tclsqlite.h 65e2c761446e1c9fa0342b7d2612a703483643c8b6a316d12a65b745a4727395
-F src/test1.c 9b54135e5f1352f06b1d23d7c183f124c1f33de6ea8997cd801f0f215c43591d
+F src/test1.c 13cc07851f989141b29f7ca3c6c90f6d18f90081ab423c66716c8cb29d277d1f
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
F src/test3.c 432646f581d8af1bb495e58fc98234380250954f5d5535e507fc785eccc3987a
F src/test4.c 0ac87fc13cdb334ab3a71823f99b6c32a6bebe5d603cd6a71d84c823d43a25a0
@@ -853,20 +852,20 @@ F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
F src/util.c 36fb1150062957280777655976f3f9a75db236cb8207a0770ceae8d5ec17fcd3
-F src/vacuum.c d580ceb395c1ae3d59da41cbfea60683ff7dd2b94ddf4d0f5657620159e2eeb7
-F src/vdbe.c 0feab5781141acca67bd5de84172fff902304274ec5cfe58609f005b8d160050
-F src/vdbe.h 31eddcffc1d14c76c2a20fe4e137e1ee43d44f370896fae14a067052801a3625
+F src/vacuum.c 1bacdd0a81d2b5dc1c508fbf0d938c89fa78dd8d5b46ec92686d44030d4f4789
+F src/vdbe.c 714fab7aa7c516edbcf5e4f653ae8f548a3e24c0ed19086d7383bb5851983992
+F src/vdbe.h 93761ed7c6b8bc19524912fd9b9b587d41bf4f1d0ade650a00dadc10518d8958
F src/vdbeInt.h 0bc581a9763be385e3af715e8c0a503ba8422c2b7074922faf4bb0d6ae31b15e
-F src/vdbeapi.c 28fab30ed0acc981aecfdcaab0a421503609078e29850eb28494816682baf0a7
-F src/vdbeaux.c 948c379976885a073b54cc7d8ffda087dc1a1095d1f5bb8df218796f8c933ac3
+F src/vdbeapi.c 613a6f29efacd6ed83e886b6e52db0fe52ba80a596b0a137608db1948bad90a9
+F src/vdbeaux.c fd2c6b19a8892c31a2adc719f156f313560f9cc490cdbd04ff08fdae5d7aedb7
F src/vdbeblob.c b1b4032cac46b41e44b957c4d00aee9851f862dfd85ecb68116ba49884b03dfd
F src/vdbemem.c e67d9c6484d868c879d20c70d00bf4a9058082f1d4058607ca15d50eb3aebc21
-F src/vdbesort.c 49e366d0216c782eba287bf602384e4330d2526a22f1275492d2785ce103c79b
+F src/vdbesort.c cb6f472e83ca12c46aa7de0ac0a9d11458b357986f2617a1c90dfb19a542ecbe
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
F src/vtab.c 828221bdbeaaa6d62126ee6d07fd4ec0d09dcaea846f87ad01944d8b7e548859
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c bcf40795a09b699ad7e42624dd6282b13335164fbabcd5a98a717758cebef451
+F src/wal.c b0f848cfba8dd057f77073493cdd542f9125b4cf87941f53e9d0db21604155c8
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
F src/where.c 45a3b496248a0b36d91ce34da3278d54f8fa20e9d3fbd36d45a42051d1118137
@@ -1084,6 +1083,7 @@ F test/dbfuzz.c fc566102f72c8af84ae8077b4faf7f056c571e6fa7a32e98b66e42b7505f47b6
F test/dbfuzz001.test 6c9a4622029d69dc38926f115864b055cb2f39badd25ec22cbfb130c8ba8e9c3
F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
F test/dbfuzz2.c 4b3c12de4d98b1b2d908ab03d217d4619e47c8b23d5e67f8a6f2b1bdee7cae23
+F test/dblwidth-a.sql eb4141518610e52f931a55a984310075e98dc31eee5a28ae806b1e35377be85a
F test/dbpage.test 63fab1eb026bada121107e53436fa749bbf83281dc9dea17af422f7a5c0f289f
F test/dbpagefault.test ea39de2ca86041a9c6df1135645180a76d0a8da93ac159e2fafe38e39636530b
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
@@ -1222,7 +1222,7 @@ F test/fts3fault3.test ccdd2292dd2d4e21e30fc5f4c8e064f79e516087eec5ff57ab6bc4f6a
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
F test/fts3fuzz001.test c78afcd8ad712ea0b8d2ed50851a8aab3bc9dc52c64a536291e07112f519357c
F test/fts3integrity.test 0c6fe7353d7b24d78862f4272ee9df4da2f32b3ff30fa3396945cda8119580a8
-F test/fts3join.test 1a4d786539b2b79a41c28ef2ac22cacd92a8ee830249b68a7dee4a020848e3bb
+F test/fts3join.test de31d304ba479043a7d33d2f201c514b3e1da809da6797d7a58704d00e8da2e6
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a
F test/fts3matchinfo2.test 00144e841704b8debfcdf6097969cd9f2a1cf759e2203cda42583648f2e6bf58
@@ -1361,7 +1361,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 5984da7bf74b6540aa356f2ab0c6ae68a6d12039a3d798a9ac6a100abc17d520
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9
-F test/join.test 015ef539ea2b779d0a219f4c0f82f39bf20884aed42142165e56791094d1cf3d
+F test/join.test 255c1f42b7fe027b518cadb2bf40f41a793a95e7f8db2bceb54faaf59ff19c6c
F test/join2.test f59d63264fb24784ae9c3bc9d867eb569cd6d442da5660f8852effe5c1938c27
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
@@ -1376,7 +1376,7 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2
F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
-F test/joinH.test 55f69e64da74d4eca2235237f3acb657aef181e22e45daa228e35bba865e0255
+F test/joinH.test fd76024ff104baec16417db5cafc0894ad4e0863e70803e63c1bba0322706339
F test/journal1.test bc61a4228db11bffca118bd358ba4b868524bf080f3532749de6c539656e20fa
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
F test/journal3.test e5aeff93a7776cf644dbc48dec277655cff80a1cd24689036abc87869b120ea6
@@ -1664,7 +1664,7 @@ F test/skipscan5.test 0672103fd2c8f96bd114133f356192b35ece45c794fe3677e1d9e5e310
F test/skipscan6.test e2b256cf5d538a605beb97dc97ca5e2836dfc24c5e1d9b7a09e13c069a3b8b49
F test/snapshot.test a504f2e7009f512ef66c719f0ea1c55a556bdaf1e1312c80a04d46fc1a3e9632
F test/snapshot2.test 8d6ff5dd9cc503f6e12d408a30409c3f9c653507b24408d9cd7195931c89bc54
-F test/snapshot3.test 41350216abc6c7da37113ad462259c070786e5ad70bdc8709daaed148b1b3a2c
+F test/snapshot3.test 2e0328ba019aa981848e10aded4d7dcd6094ec1f9c6290a34ab18415be0c44eb
F test/snapshot4.test d4e9347ef2fcabc491fc893506c7bbaf334da3be111d6eb4f3a97cc623b78322
F test/snapshot_fault.test 129234ceb9b26a0e1000e8563a16e790f5c1412354e70749cbd78c3d5d07d60a
F test/snapshot_up.test 77dc7853bfb2b4fa249f76e1714cfa1e596826165d9ef22c06ac3a0b7b778d9a
@@ -1725,7 +1725,7 @@ F test/tabfunc01.test 8a484fe8b19fc24844f72ca1ceb7c9ae8c9a6bca000a5c6ccab5d89f5c
F test/table.test e87294bf1c80bfd7792142b84ab32ea5beb4f3f71e535d7fb263a6b2068377bf
F test/tableapi.test e37c33e6be2276e3a96bb54b00eea7f321277115d10e5b30fdb52a112b432750
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
-F test/tclsqlite.test ad0bbd92edabe64cc91d990a0748142fe5ab962d74ac71fa3bfa94d50d2f4c87
+F test/tclsqlite.test 3f697424cfc1cdc9c076ec0cadb0e700f059400a3e3ce134b7d856fc9f880e1c
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
F test/tempdb2.test 353864e96fd3ae2f70773d0ffbf8b1fe48589b02c2ec05013b540879410c3440
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
@@ -1959,7 +1959,7 @@ F test/uri.test 1250724af9beeed2d6c3716f5b990c483200c54f408d3c0ec9543a3c7961f8fc
F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
F test/utf16align.test 9fde0bb5d3a821594aa68c6829ab9c5453a084384137ebb9f6153e2d678039da
F test/vacuum-into.test 5a489714feecfdabfc7b293be4111564a173dee92c0d6818dd0207f3ade65783
-F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
+F test/vacuum.test f3b2257a4fcd659513c866a5d9e5f70999cc58fd5d74e979290385fa350b79ee
F test/vacuum2.test 9fd45ce6ce29f5614c249e03938d3567c06a9e772d4f155949f8eafe2d8af520
F test/vacuum3.test d9d9a04ee58c485b94694fd4f68cffaba49c32234fdefe1ac1a622c5e17d4ce3
F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7c010
@@ -2036,6 +2036,8 @@ F test/walseh1.test bae700eb99519b6d5cd3f893c04759accc5a59c391d4189fe4dd6995a533
F test/walsetlk.test 9079cd8ef82570b8cf0067f31e049a72bec353fb2d5f0cc88f1736dc42ba9704
F test/walsetlk2.test 9097083633cdf55bf1098b694fb8651d0356d38fef28b869481d18029d7ceaf4
F test/walsetlk3.test 1b82bd92dea7e58f498b4399b0b3d26773dd8ac5c74205ce4a23c207cb8e85fe
+F test/walsetlk_recover.test adccbffc59e365063a4efd2da6b661ae2fcf15d775b6719fe46acd87face08ff
+F test/walsetlk_snapshot.test 86d5588380f9927d8fcbbd75133b0a34fddf959378d6823c6f164a390123f70a
F test/walshared.test 42e3808582504878af237ea02c42ca793e8a0efaa19df7df26ac573370dbc7a3
F test/walslow.test 0c51843836c9dcf40a5ac05aa781bfb977b396ee2c872d92bd48b79d5dd9aa23
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
@@ -2189,7 +2191,7 @@ F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d
F tool/split-sqlite3c.tcl 4969fd642dad0ea483e4e104163021d92baf98f6a8eac981fe48525f9b873430
F tool/sqldiff.c 134be7866be19f8beb32043d5aea5657f01aaeae2df8d33d758ff722c78666b9
F tool/sqlite3_analyzer.c.in 14f02cb5ec3c264cd6107d1f1dad77092b1cf440fc196c30b69ae87b56a1a43b
-F tool/sqlite3_rsync.c e8659970e839d71d2ef04b96d48ad65f1d4298a41636affaf93c32ed71f3f879
+F tool/sqlite3_rsync.c c1e1a737ebb458a4ccbbaa21e5eaa878448fef1aaa71b879b9a685785e28987f
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
F tool/src-verify.c 6c655d9a8d6b30f3648fc78a79bf3838ed68f8543869d380c43ea9f17b3b8501
@@ -2207,8 +2209,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 2e486f8fd011d28fdd7e59ff34f7f04374019932eb160a8c4de56a5ce01e5782
-R 4fc3d788e929e3ad2e87da5f4f76e5b7
+P 27d9e8e79b921c4a86916556f3bf56b94684a7e3d40166c0fdaaf750d4011de0
+R 9cc60dad3acf43f97f93eee6529b25c7
U drh
-Z b8769468b1683decb71b7b0ba97e34bc
+Z b6b73666051465f0df1cb185ca3428e3
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 31fbda4e9..4b4b23196 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-60adc78a22956429d34ccc4e2c193c5994c11c3b3cff7901d47fad7d92dba935
+ea1754f7d8a770477a1b19b606b27724fdc0b733e51fef32c1ef834f972c3cc5
diff --git a/src/btree.c b/src/btree.c
index 1bd59a1b1..f53060e7f 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -872,7 +872,7 @@ static int btreeMoveto(
assert( nKey==(i64)(int)nKey );
pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
- sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey);
+ sqlite3VdbeRecordUnpack((int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){
rc = SQLITE_CORRUPT_BKPT;
}else{
@@ -2856,6 +2856,7 @@ static int removeFromSharingList(BtShared *pBt){
sqlite3_mutex_leave(pMainMtx);
return removed;
#else
+ UNUSED_PARAMETER( pBt );
return 1;
#endif
}
@@ -3697,6 +3698,13 @@ static SQLITE_NOINLINE int btreeBeginTrans(
(void)sqlite3PagerWalWriteLock(pPager, 0);
unlockBtreeIfUnused(pBt);
}
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT)
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ /* If a blocking lock timed out, break out of the loop here so that
+ ** the busy-handler is not invoked. */
+ break;
+ }
+#endif
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
btreeInvokeBusyHandler(pBt) );
sqlite3PagerWalDb(pPager, 0);
@@ -11317,6 +11325,7 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
*/
int sqlite3BtreeSchemaLocked(Btree *p){
int rc;
+ UNUSED_PARAMETER(p); /* only used in DEBUG builds */
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
diff --git a/src/dbpage.c b/src/dbpage.c
index f9fdcc5a3..4e2addad9 100644
--- a/src/dbpage.c
+++ b/src/dbpage.c
@@ -227,7 +227,7 @@ static int dbpageEof(sqlite3_vtab_cursor *pCursor){
** idxStr is not used
*/
static int dbpageFilter(
- sqlite3_vtab_cursor *pCursor,
+ sqlite3_vtab_cursor *pCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
@@ -237,10 +237,11 @@ static int dbpageFilter(
sqlite3 *db = pTab->db;
Btree *pBt;
- (void)idxStr;
-
+ UNUSED_PARAMETER(idxStr);
+ UNUSED_PARAMETER(argc);
+
/* Default setting is no rows of result */
- pCsr->pgno = 1;
+ pCsr->pgno = 1;
pCsr->mxPgno = 0;
if( idxNum & 2 ){
@@ -275,8 +276,8 @@ static int dbpageFilter(
}
static int dbpageColumn(
- sqlite3_vtab_cursor *pCursor,
- sqlite3_context *ctx,
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
int i
){
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
diff --git a/src/expr.c b/src/expr.c
index 12c94362f..606a4cd7e 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -73,7 +73,9 @@ char sqlite3ExprAffinity(const Expr *pExpr){
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
);
}
- if( op==TK_VECTOR ){
+ if( op==TK_VECTOR
+ || (op==TK_FUNCTION && pExpr->affExpr==SQLITE_AFF_DEFER)
+ ){
assert( ExprUseXList(pExpr) );
return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
}
@@ -266,7 +268,9 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
p = p->pLeft;
continue;
}
- if( op==TK_VECTOR ){
+ if( op==TK_VECTOR
+ || (op==TK_FUNCTION && p->affExpr==SQLITE_AFF_DEFER)
+ ){
assert( ExprUseXList(p) );
p = p->x.pList->a[0].pExpr;
continue;
diff --git a/src/json.c b/src/json.c
index 4ae17a5a4..3078be34b 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1285,8 +1285,10 @@ static int jsonBlobChangePayloadSize(
nExtra = 1;
}else if( szType==13 ){
nExtra = 2;
- }else{
+ }else if( szType==14 ){
nExtra = 4;
+ }else{
+ nExtra = 8;
}
if( szPayload<=11 ){
nNeeded = 0;
diff --git a/src/os_unix.c b/src/os_unix.c
index 1146545fe..784bc3517 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -5035,21 +5035,20 @@ static int unixShmLock(
/* Check that, if this to be a blocking lock, no locks that occur later
** in the following list than the lock being obtained are already held:
**
- ** 1. Checkpointer lock (ofst==1).
- ** 2. Write lock (ofst==0).
- ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
+ ** 1. Recovery lock (ofst==2).
+ ** 2. Checkpointer lock (ofst==1).
+ ** 3. Write lock (ofst==0).
+ ** 4. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
**
** In other words, if this is a blocking lock, none of the locks that
** occur later in the above list than the lock being obtained may be
** held.
- **
- ** It is not permitted to block on the RECOVER lock.
*/
#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
{
u16 lockMask = (p->exclMask|p->sharedMask);
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
- (ofst!=2) /* not RECOVER */
+ (ofst!=2 || lockMask==0)
&& (ofst!=1 || lockMask==0 || lockMask==2)
&& (ofst!=0 || lockMask<3)
&& (ofst<3 || lockMask<(1<<ofst))
diff --git a/src/os_win.c b/src/os_win.c
index cd7e49190..c7c923e77 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -2722,7 +2722,11 @@ static int winHandleLockTimeout(
if( res==WAIT_OBJECT_0 ){
ret = TRUE;
}else if( res==WAIT_TIMEOUT ){
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
rc = SQLITE_BUSY_TIMEOUT;
+#else
+ rc = SQLITE_BUSY;
+#endif
}else{
/* Some other error has occurred */
rc = SQLITE_IOERR_LOCK;
@@ -4533,21 +4537,20 @@ static int winShmLock(
/* Check that, if this to be a blocking lock, no locks that occur later
** in the following list than the lock being obtained are already held:
**
- ** 1. Checkpointer lock (ofst==1).
- ** 2. Write lock (ofst==0).
- ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
+ ** 1. Recovery lock (ofst==2).
+ ** 2. Checkpointer lock (ofst==1).
+ ** 3. Write lock (ofst==0).
+ ** 4. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
**
** In other words, if this is a blocking lock, none of the locks that
** occur later in the above list than the lock being obtained may be
** held.
- **
- ** It is not permitted to block on the RECOVER lock.
*/
#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
{
u16 lockMask = (p->exclMask|p->sharedMask);
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
- (ofst!=2) /* not RECOVER */
+ (ofst!=2 || lockMask==0)
&& (ofst!=1 || lockMask==0 || lockMask==2)
&& (ofst!=0 || lockMask<3)
&& (ofst<3 || lockMask<(1<<ofst))
diff --git a/src/pager.c b/src/pager.c
index 21f3ac5f6..1850ba37b 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -700,6 +700,9 @@ struct Pager {
Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
char *zWal; /* File name for write-ahead log */
#endif
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ sqlite3 *dbWal;
+#endif
};
/*
@@ -7581,6 +7584,11 @@ static int pagerOpenWal(Pager *pPager){
pPager->fd, pPager->zWal, pPager->exclusiveMode,
pPager->journalSizeLimit, &pPager->pWal
);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_OK ){
+ sqlite3WalDb(pPager->pWal, pPager->dbWal);
+ }
+#endif
}
pagerFixMaplimit(pPager);
@@ -7700,6 +7708,7 @@ int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
** blocking locks are required.
*/
void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
+ pPager->dbWal = db;
if( pagerUseWal(pPager) ){
sqlite3WalDb(pPager->pWal, db);
}
diff --git a/src/select.c b/src/select.c
index da0aa63e4..6c0e7c92d 100644
--- a/src/select.c
+++ b/src/select.c
@@ -630,7 +630,13 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
if( pFuncArgs ){
pFuncArgs = sqlite3ExprListAppend(pParse, pFuncArgs, pE1);
pE1 = sqlite3ExprFunction(pParse, pFuncArgs, &tkCoalesce, 0);
+ if( pE1 ){
+ pE1->affExpr = SQLITE_AFF_DEFER;
+ }
}
+ }else if( (pSrc->a[i+1].fg.jointype & JT_LEFT)!=0 && pParse->nErr==0 ){
+ assert( pE1!=0 );
+ ExprSetProperty(pE1, EP_CanBeNull);
}
pE2 = sqlite3CreateColumnExpr(db, pSrc, i+1, iRightCol);
sqlite3SrcItemColumnUsed(pRight, iRightCol);
@@ -2107,6 +2113,10 @@ static void generateColumnTypes(
#endif
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
}
+#else
+ UNUSED_PARAMETER(pParse);
+ UNUSED_PARAMETER(pTabList);
+ UNUSED_PARAMETER(pEList);
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
}
@@ -4238,9 +4248,9 @@ static int compoundHasDifferentAffinities(Select *p){
** from 2015-02-09.)
**
** (3) If the subquery is the right operand of a LEFT JOIN then
-** (3a) the subquery may not be a join and
-** (3b) the FROM clause of the subquery may not contain a virtual
-** table and
+** (3a) the subquery may not be a join
+** (**) Was (3b): "the FROM clause of the subquery may not contain
+** a virtual table"
** (**) Was: "The outer query may not have a GROUP BY." This case
** is now managed correctly
** (3d) the outer query may not be DISTINCT.
@@ -4456,7 +4466,7 @@ static int flattenSubquery(
*/
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
if( pSubSrc->nSrc>1 /* (3a) */
- || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */
+ /**** || IsVirtual(pSubSrc->a[0].pSTab) (3b)-omitted */
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
){
diff --git a/src/shell.c.in b/src/shell.c.in
index 8660bd78a..363685eb0 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -887,12 +887,21 @@ static int strlen30(const char *z){
/*
** Return the length of a string in characters. Multibyte UTF8 characters
-** count as a single character.
+** count as a single character for single-width characters, or as two
+** characters for double-width characters.
*/
static int strlenChar(const char *z){
int n = 0;
while( *z ){
- if( (0xc0&*(z++))!=0x80 ) n++;
+ if( (0x80&z[0])==0 ){
+ n++;
+ z++;
+ }else{
+ int u = 0;
+ int len = decodeUtf8((const u8*)z, &u);
+ z += len;
+ n += cli_wcwidth(u);
+ }
}
return n;
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 994a3864c..c65d159d1 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2329,6 +2329,7 @@ struct CollSeq {
#define SQLITE_AFF_INTEGER 0x44 /* 'D' */
#define SQLITE_AFF_REAL 0x45 /* 'E' */
#define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */
+#define SQLITE_AFF_DEFER 0x58 /* 'X' - defer computation until later */
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
@@ -2644,9 +2645,15 @@ struct FKey {
** argument to sqlite3VdbeKeyCompare and is used to control the
** comparison of the two index keys.
**
-** Note that aSortOrder[] and aColl[] have nField+1 slots. There
-** are nField slots for the columns of an index then one extra slot
-** for the rowid at the end.
+** The aSortOrder[] and aColl[] arrays have nAllField slots each. There
+** are nKeyField slots for the columns of an index then extra slots
+** for the rowid or key at the end. The aSortOrder array is located after
+** the aColl[] array.
+**
+** If SQLITE_ENABLE_PREUPDATE_HOOK is defined, then aSortFlags might be NULL
+** to indicate that this object is for use by a preupdate hook. When aSortFlags
+** is NULL, then nAllField is uninitialized and no space is allocated for
+** aColl[], so those fields may not be used.
*/
struct KeyInfo {
u32 nRef; /* Number of references to this KeyInfo object */
@@ -2658,7 +2665,9 @@ struct KeyInfo {
CollSeq *aColl[FLEXARRAY]; /* Collating sequence for each term of the key */
};
-/* The size (in bytes) of a KeyInfo object with up to N fields */
+/* The size (in bytes) of a KeyInfo object with up to N fields. This includes
+** the main body of the KeyInfo object and the aColl[] array of N elements,
+** but does not count the memory used to hold aSortFlags[]. */
#define SZ_KEYINFO(N) (offsetof(KeyInfo,aColl) + (N)*sizeof(CollSeq*))
/* The size of a bare KeyInfo with no aColl[] entries */
@@ -2686,9 +2695,8 @@ struct KeyInfo {
**
** An instance of this object serves as a "key" for doing a search on
** an index b+tree. The goal of the search is to find the entry that
-** is closed to the key described by this object. This object might hold
-** just a prefix of the key. The number of fields is given by
-** pKeyInfo->nField.
+** is closest to the key described by this object. This object might hold
+** just a prefix of the key. The number of fields is given by nField.
**
** The r1 and r2 fields are the values to return if this key is less than
** or greater than a key in the btree, respectively. These are normally
@@ -2698,7 +2706,7 @@ struct KeyInfo {
** The key comparison functions actually return default_rc when they find
** an equals comparison. default_rc can be -1, 0, or +1. If there are
** multiple entries in the b-tree with the same key (when only looking
-** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to
+** at the first nField elements) then default_rc can be set to -1 to
** cause the search to find the last match, or +1 to cause the search to
** find the first match.
**
@@ -2710,8 +2718,8 @@ struct KeyInfo {
** b-tree.
*/
struct UnpackedRecord {
- KeyInfo *pKeyInfo; /* Collation and sort-order information */
- Mem *aMem; /* Values */
+ KeyInfo *pKeyInfo; /* Comparison info for the index that is unpacked */
+ Mem *aMem; /* Values for columns of the index */
union {
char *z; /* Cache of aMem[0].z for vdbeRecordCompareString() */
i64 i; /* Cache of aMem[0].u.i for vdbeRecordCompareInt() */
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 8c40b8692..02a4d84e4 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -49,6 +49,10 @@
# define CONST const
#elif !defined(Tcl_Size)
typedef int Tcl_Size;
+# ifndef Tcl_BounceRefCount
+# define Tcl_BounceRefCount(X) Tcl_IncrRefCount(X); Tcl_DecrRefCount(X)
+ /* https://www.tcl-lang.org/man/tcl9.0/TclLib/Object.html */
+# endif
#endif
/**** End copy of tclsqlite.h ****/
@@ -1084,7 +1088,9 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
Tcl_DecrRefCount(pCmd);
}
- if( rc && rc!=TCL_RETURN ){
+ if( TCL_BREAK==rc ){
+ sqlite3_result_null(context);
+ }else if( rc && rc!=TCL_RETURN ){
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
}else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
@@ -1102,7 +1108,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
}else if( (c=='b' && pVar->bytes==0 && strcmp(zType,"boolean")==0 )
|| (c=='b' && pVar->bytes==0 && strcmp(zType,"booleanString")==0 )
|| (c=='w' && strcmp(zType,"wideInt")==0)
- || (c=='i' && strcmp(zType,"int")==0)
+ || (c=='i' && strcmp(zType,"int")==0)
){
eType = SQLITE_INTEGER;
}else if( c=='d' && strcmp(zType,"double")==0 ){
@@ -1616,11 +1622,12 @@ struct DbEvalContext {
SqlPreparedStmt *pPreStmt; /* Current statement */
int nCol; /* Number of columns returned by pStmt */
int evalFlags; /* Flags used */
- Tcl_Obj *pArray; /* Name of array variable */
+ Tcl_Obj *pVarName; /* Name of target array/dict variable */
Tcl_Obj **apColName; /* Array of column names */
};
#define SQLITE_EVAL_WITHOUTNULLS 0x00001 /* Unset array(*) for NULL */
+#define SQLITE_EVAL_ASDICT 0x00002 /* Use dict instead of array */
/*
** Release any cache of column names currently held as part of
@@ -1641,20 +1648,20 @@ static void dbReleaseColumnNames(DbEvalContext *p){
/*
** Initialize a DbEvalContext structure.
**
-** If pArray is not NULL, then it contains the name of a Tcl array
+** If pVarName is not NULL, then it contains the name of a Tcl array
** variable. The "*" member of this array is set to a list containing
** the names of the columns returned by the statement as part of each
** call to dbEvalStep(), in order from left to right. e.g. if the names
** of the returned columns are a, b and c, it does the equivalent of the
** tcl command:
**
-** set ${pArray}(*) {a b c}
+** set ${pVarName}(*) {a b c}
*/
static void dbEvalInit(
DbEvalContext *p, /* Pointer to structure to initialize */
SqliteDb *pDb, /* Database handle */
Tcl_Obj *pSql, /* Object containing SQL script */
- Tcl_Obj *pArray, /* Name of Tcl array to set (*) element of */
+ Tcl_Obj *pVarName, /* Name of Tcl array to set (*) element of */
int evalFlags /* Flags controlling evaluation */
){
memset(p, 0, sizeof(DbEvalContext));
@@ -1662,9 +1669,9 @@ static void dbEvalInit(
p->zSql = Tcl_GetString(pSql);
p->pSql = pSql;
Tcl_IncrRefCount(pSql);
- if( pArray ){
- p->pArray = pArray;
- Tcl_IncrRefCount(pArray);
+ if( pVarName ){
+ p->pVarName = pVarName;
+ Tcl_IncrRefCount(pVarName);
}
p->evalFlags = evalFlags;
addDatabaseRef(p->pDb);
@@ -1687,7 +1694,7 @@ static void dbEvalRowInfo(
Tcl_Obj **apColName = 0; /* Array of column names */
p->nCol = nCol = sqlite3_column_count(pStmt);
- if( nCol>0 && (papColName || p->pArray) ){
+ if( nCol>0 && (papColName || p->pVarName) ){
apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol );
for(i=0; i<nCol; i++){
apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1);
@@ -1696,20 +1703,35 @@ static void dbEvalRowInfo(
p->apColName = apColName;
}
- /* If results are being stored in an array variable, then create
- ** the array(*) entry for that array
+ /* If results are being stored in a variable then create the
+ ** array(*) or dict(*) entry for that variable.
*/
- if( p->pArray ){
+ if( p->pVarName ){
Tcl_Interp *interp = p->pDb->interp;
Tcl_Obj *pColList = Tcl_NewObj();
Tcl_Obj *pStar = Tcl_NewStringObj("*", -1);
+ Tcl_IncrRefCount(pColList);
+ Tcl_IncrRefCount(pStar);
for(i=0; i<nCol; i++){
Tcl_ListObjAppendElement(interp, pColList, apColName[i]);
}
- Tcl_IncrRefCount(pStar);
- Tcl_ObjSetVar2(interp, p->pArray, pStar, pColList, 0);
+ if( 0==(SQLITE_EVAL_ASDICT & p->evalFlags) ){
+ Tcl_ObjSetVar2(interp, p->pVarName, pStar, pColList, 0);
+ }else{
+ Tcl_Obj * pDict = Tcl_ObjGetVar2(interp, p->pVarName, NULL, 0);
+ if( !pDict ){
+ pDict = Tcl_NewDictObj();
+ }else if( Tcl_IsShared(pDict) ){
+ pDict = Tcl_DuplicateObj(pDict);
+ }
+ if( Tcl_DictObjPut(interp, pDict, pStar, pColList)==TCL_OK ){
+ Tcl_ObjSetVar2(interp, p->pVarName, NULL, pDict, 0);
+ }
+ Tcl_BounceRefCount(pDict);
+ }
Tcl_DecrRefCount(pStar);
+ Tcl_DecrRefCount(pColList);
}
}
@@ -1751,7 +1773,7 @@ static int dbEvalStep(DbEvalContext *p){
if( rcs==SQLITE_ROW ){
return TCL_OK;
}
- if( p->pArray ){
+ if( p->pVarName ){
dbEvalRowInfo(p, 0, 0);
}
rcs = sqlite3_reset(pStmt);
@@ -1802,9 +1824,9 @@ static void dbEvalFinalize(DbEvalContext *p){
dbReleaseStmt(p->pDb, p->pPreStmt, 0);
p->pPreStmt = 0;
}
- if( p->pArray ){
- Tcl_DecrRefCount(p->pArray);
- p->pArray = 0;
+ if( p->pVarName ){
+ Tcl_DecrRefCount(p->pVarName);
+ p->pVarName = 0;
}
Tcl_DecrRefCount(p->pSql);
dbReleaseColumnNames(p);
@@ -1879,7 +1901,7 @@ static int DbUseNre(void){
/*
** This function is part of the implementation of the command:
**
-** $db eval SQL ?ARRAYNAME? SCRIPT
+** $db eval SQL ?TGT-NAME? SCRIPT
*/
static int SQLITE_TCLAPI DbEvalNextCmd(
ClientData data[], /* data[0] is the (DbEvalContext*) */
@@ -1893,8 +1915,8 @@ static int SQLITE_TCLAPI DbEvalNextCmd(
** is a pointer to a Tcl_Obj containing the script to run for each row
** returned by the queries encapsulated in data[0]. */
DbEvalContext *p = (DbEvalContext *)data[0];
- Tcl_Obj *pScript = (Tcl_Obj *)data[1];
- Tcl_Obj *pArray = p->pArray;
+ Tcl_Obj * const pScript = (Tcl_Obj *)data[1];
+ Tcl_Obj * const pVarName = p->pVarName;
while( (rc==TCL_OK || rc==TCL_CONTINUE) && TCL_OK==(rc = dbEvalStep(p)) ){
int i;
@@ -1902,15 +1924,46 @@ static int SQLITE_TCLAPI DbEvalNextCmd(
Tcl_Obj **apColName;
dbEvalRowInfo(p, &nCol, &apColName);
for(i=0; i<nCol; i++){
- if( pArray==0 ){
+ if( pVarName==0 ){
Tcl_ObjSetVar2(interp, apColName[i], 0, dbEvalColumnValue(p,i), 0);
}else if( (p->evalFlags & SQLITE_EVAL_WITHOUTNULLS)!=0
- && sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL
+ && sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL
){
- Tcl_UnsetVar2(interp, Tcl_GetString(pArray),
- Tcl_GetString(apColName[i]), 0);
+ /* Remove NULL-containing column from the target container... */
+ if( 0==(SQLITE_EVAL_ASDICT & p->evalFlags) ){
+ /* Target is an array */
+ Tcl_UnsetVar2(interp, Tcl_GetString(pVarName),
+ Tcl_GetString(apColName[i]), 0);
+ }else{
+ /* Target is a dict */
+ Tcl_Obj *pDict = Tcl_ObjGetVar2(interp, pVarName, NULL, 0);
+ if( pDict ){
+ if( Tcl_IsShared(pDict) ){
+ pDict = Tcl_DuplicateObj(pDict);
+ }
+ if( Tcl_DictObjRemove(interp, pDict, apColName[i])==TCL_OK ){
+ Tcl_ObjSetVar2(interp, pVarName, NULL, pDict, 0);
+ }
+ Tcl_BounceRefCount(pDict);
+ }
+ }
+ }else if( 0==(SQLITE_EVAL_ASDICT & p->evalFlags) ){
+ /* Target is an array: set target(colName) = colValue */
+ Tcl_ObjSetVar2(interp, pVarName, apColName[i],
+ dbEvalColumnValue(p,i), 0);
}else{
- Tcl_ObjSetVar2(interp, pArray, apColName[i], dbEvalColumnValue(p,i), 0);
+ /* Target is a dict: set target(colName) = colValue */
+ Tcl_Obj *pDict = Tcl_ObjGetVar2(interp, pVarName, NULL, 0);
+ if( !pDict ){
+ pDict = Tcl_NewDictObj();
+ }else if( Tcl_IsShared(pDict) ){
+ pDict = Tcl_DuplicateObj(pDict);
+ }
+ if( Tcl_DictObjPut(interp, pDict, apColName[i],
+ dbEvalColumnValue(p,i))==TCL_OK ){
+ Tcl_ObjSetVar2(interp, pVarName, NULL, pDict, 0);
+ }
+ Tcl_BounceRefCount(pDict);
}
}
@@ -2019,7 +2072,7 @@ static int SQLITE_TCLAPI DbObjCmd(
"timeout", "total_changes", "trace",
"trace_v2", "transaction", "unlock_notify",
"update_hook", "version", "wal_hook",
- 0
+ 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
@@ -2853,13 +2906,15 @@ deserialize_error:
}
/*
- ** $db eval ?options? $sql ?array? ?{ ...code... }?
+ ** $db eval ?options? $sql ?varName? ?{ ...code... }?
**
- ** The SQL statement in $sql is evaluated. For each row, the values are
- ** placed in elements of the array named "array" and ...code... is executed.
- ** If "array" and "code" are omitted, then no callback is every invoked.
- ** If "array" is an empty string, then the values are placed in variables
- ** that have the same name as the fields extracted by the query.
+ ** The SQL statement in $sql is evaluated. For each row, the values
+ ** are placed in elements of the array or dict named $varName and
+ ** ...code... is executed. If $varName and $code are omitted, then
+ ** no callback is ever invoked. If $varName is an empty string,
+ ** then the values are placed in variables that have the same name
+ ** as the fields extracted by the query, and those variables are
+ ** accessible during the eval of $code.
*/
case DB_EVAL: {
int evalFlags = 0;
@@ -2867,8 +2922,9 @@ deserialize_error:
while( objc>3 && (zOpt = Tcl_GetString(objv[2]))!=0 && zOpt[0]=='-' ){
if( strcmp(zOpt, "-withoutnulls")==0 ){
evalFlags |= SQLITE_EVAL_WITHOUTNULLS;
- }
- else{
+ }else if( strcmp(zOpt, "-asdict")==0 ){
+ evalFlags |= SQLITE_EVAL_ASDICT;
+ }else{
Tcl_AppendResult(interp, "unknown option: \"", zOpt, "\"", (void*)0);
return TCL_ERROR;
}
@@ -2876,8 +2932,8 @@ deserialize_error:
objv++;
}
if( objc<3 || objc>5 ){
- Tcl_WrongNumArgs(interp, 2, objv,
- "?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?");
+ Tcl_WrongNumArgs(interp, 2, objv,
+ "?OPTIONS? SQL ?VAR-NAME? ?SCRIPT?");
return TCL_ERROR;
}
@@ -2903,17 +2959,17 @@ deserialize_error:
}else{
ClientData cd2[2];
DbEvalContext *p;
- Tcl_Obj *pArray = 0;
+ Tcl_Obj *pVarName = 0;
Tcl_Obj *pScript;
if( objc>=5 && *(char *)Tcl_GetString(objv[3]) ){
- pArray = objv[3];
+ pVarName = objv[3];
}
pScript = objv[objc-1];
Tcl_IncrRefCount(pScript);
p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
- dbEvalInit(p, pDb, objv[2], pArray, evalFlags);
+ dbEvalInit(p, pDb, objv[2], pVarName, evalFlags);
cd2[0] = (void *)p;
cd2[1] = (void *)pScript;
diff --git a/src/test1.c b/src/test1.c
index bb2f2d3b9..1c363ca3b 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -8458,7 +8458,12 @@ static int SQLITE_TCLAPI test_sqlite3_db_config(
{ "DQS_DML", SQLITE_DBCONFIG_DQS_DML },
{ "DQS_DDL", SQLITE_DBCONFIG_DQS_DDL },
{ "LEGACY_FILE_FORMAT", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT },
+ { "TRUSTED_SCHEMA", SQLITE_DBCONFIG_TRUSTED_SCHEMA },
{ "STMT_SCANSTATUS", SQLITE_DBCONFIG_STMT_SCANSTATUS },
+ { "REVERSE_SCANORDER", SQLITE_DBCONFIG_REVERSE_SCANORDER },
+ { "ATTACH_CREATE", SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE },
+ { "ATTACH_WRITE", SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE },
+ { "COMMENTS", SQLITE_DBCONFIG_ENABLE_COMMENTS },
};
int i;
int v = 0;
diff --git a/src/vacuum.c b/src/vacuum.c
index 96d77e5bc..1b4838040 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -195,7 +195,8 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_mTrace = db->mTrace;
- db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments;
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments
+ | SQLITE_AttachCreate | SQLITE_AttachWrite;
db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder
| SQLITE_Defensive | SQLITE_CountRows);
diff --git a/src/vdbe.c b/src/vdbe.c
index 29b6f9a65..b23bd38d2 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2476,6 +2476,7 @@ case OP_Compare: {
pKeyInfo = pOp->p4.pKeyInfo;
assert( n>0 );
assert( pKeyInfo!=0 );
+ assert( pKeyInfo->aSortFlags!=0 );
p1 = pOp->p1;
p2 = pOp->p2;
#ifdef SQLITE_DEBUG
@@ -5349,7 +5350,7 @@ case OP_Found: { /* jump, in3, ncycle */
if( rc ) goto no_mem;
pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
if( pIdxKey==0 ) goto no_mem;
- sqlite3VdbeRecordUnpack(pC->pKeyInfo, r.aMem->n, r.aMem->z, pIdxKey);
+ sqlite3VdbeRecordUnpack(r.aMem->n, r.aMem->z, pIdxKey);
pIdxKey->default_rc = 0;
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &pC->seekResult);
sqlite3DbFreeNN(db, pIdxKey);
diff --git a/src/vdbe.h b/src/vdbe.h
index dc98e270e..a7aedfbb0 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -301,7 +301,7 @@ void sqlite3VdbeSetVarmask(Vdbe*, int);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3BlobCompare(const Mem*, const Mem*);
-void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
+void sqlite3VdbeRecordUnpack(int,const void*,UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index ed9549462..f5260e7e6 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -2163,7 +2163,7 @@ static UnpackedRecord *vdbeUnpackRecord(
pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
if( pRet ){
memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1));
- sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
+ sqlite3VdbeRecordUnpack(nKey, pKey, pRet);
}
return pRet;
}
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index a6798e62d..8a900aeff 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -4202,30 +4202,22 @@ void sqlite3VdbeSerialGet(
return;
}
/*
-** This routine is used to allocate sufficient space for an UnpackedRecord
-** structure large enough to be used with sqlite3VdbeRecordUnpack() if
-** the first argument is a pointer to KeyInfo structure pKeyInfo.
+** Allocate sufficient space for an UnpackedRecord structure large enough
+** to hold a decoded index record for pKeyInfo.
**
-** The space is either allocated using sqlite3DbMallocRaw() or from within
-** the unaligned buffer passed via the second and third arguments (presumably
-** stack space). If the former, then *ppFree is set to a pointer that should
-** be eventually freed by the caller using sqlite3DbFree(). Or, if the
-** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL
-** before returning.
-**
-** If an OOM error occurs, NULL is returned.
+** The space is allocated using sqlite3DbMallocRaw(). If an OOM error
+** occurs, NULL is returned.
*/
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
KeyInfo *pKeyInfo /* Description of the record */
){
UnpackedRecord *p; /* Unpacked record to return */
- int nByte; /* Number of bytes required for *p */
+ u64 nByte; /* Number of bytes required for *p */
assert( sizeof(UnpackedRecord) + sizeof(Mem)*65536 < 0x7fffffff );
nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
if( !p ) return 0;
p->aMem = (Mem*)&((char*)p)[ROUND8P(sizeof(UnpackedRecord))];
- assert( pKeyInfo->aSortFlags!=0 );
p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nKeyField + 1;
return p;
@@ -4237,7 +4229,6 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
** contents of the decoded record.
*/
void sqlite3VdbeRecordUnpack(
- KeyInfo *pKeyInfo, /* Information about the record format */
int nKey, /* Size of the binary record */
const void *pKey, /* The binary record */
UnpackedRecord *p /* Populate this structure before returning. */
@@ -4248,6 +4239,7 @@ void sqlite3VdbeRecordUnpack(
u16 u; /* Unsigned loop counter */
u32 szHdr;
Mem *pMem = p->aMem;
+ KeyInfo *pKeyInfo = p->pKeyInfo;
p->default_rc = 0;
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
@@ -4275,6 +4267,8 @@ void sqlite3VdbeRecordUnpack(
** warnings from MSAN. */
sqlite3VdbeMemSetNull(pMem-1);
}
+ testcase( u == pKeyInfo->nKeyField + 1 );
+ testcase( u < pKeyInfo->nKeyField + 1 );
assert( u<=pKeyInfo->nKeyField + 1 );
p->nField = u;
}
@@ -5134,6 +5128,7 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
** The easiest way to enforce this limit is to consider only records with
** 13 fields or less. If the first field is an integer, the maximum legal
** header size is (12*5 + 1 + 1) bytes. */
+ assert( p->pKeyInfo->aSortFlags!=0 );
if( p->pKeyInfo->nAllField<=13 ){
int flags = p->aMem[0].flags;
if( p->pKeyInfo->aSortFlags[0] ){
@@ -5492,7 +5487,6 @@ void sqlite3VdbePreUpdateHook(
i64 iKey2;
PreUpdate preupdate;
const char *zTbl = pTab->zName;
- static const u8 fakeSortOrder = 0;
#ifdef SQLITE_DEBUG
int nRealCol;
if( pTab->tabFlags & TF_WithoutRowid ){
@@ -5531,7 +5525,7 @@ void sqlite3VdbePreUpdateHook(
preupdate.pKeyinfo->db = db;
preupdate.pKeyinfo->enc = ENC(db);
preupdate.pKeyinfo->nKeyField = pTab->nCol;
- preupdate.pKeyinfo->aSortFlags = (u8*)&fakeSortOrder;
+ preupdate.pKeyinfo->aSortFlags = 0; /* Indicate .aColl, .nAllField uninit */
preupdate.iKey1 = iKey1;
preupdate.iKey2 = iKey2;
preupdate.pTab = pTab;
diff --git a/src/vdbesort.c b/src/vdbesort.c
index 9a7e0760c..39661eb4c 100644
--- a/src/vdbesort.c
+++ b/src/vdbesort.c
@@ -766,7 +766,7 @@ static int vdbeSorterCompareTail(
){
UnpackedRecord *r2 = pTask->pUnpacked;
if( *pbKey2Cached==0 ){
- sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
+ sqlite3VdbeRecordUnpack(nKey2, pKey2, r2);
*pbKey2Cached = 1;
}
return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1);
@@ -793,7 +793,7 @@ static int vdbeSorterCompare(
){
UnpackedRecord *r2 = pTask->pUnpacked;
if( !*pbKey2Cached ){
- sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
+ sqlite3VdbeRecordUnpack(nKey2, pKey2, r2);
*pbKey2Cached = 1;
}
return sqlite3VdbeRecordCompare(nKey1, pKey1, r2);
@@ -833,6 +833,7 @@ static int vdbeSorterCompareText(
);
}
}else{
+ assert( pTask->pSorter->pKeyInfo->aSortFlags!=0 );
assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) );
if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){
res = res * -1;
@@ -896,6 +897,7 @@ static int vdbeSorterCompareInt(
}
}
+ assert( pTask->pSorter->pKeyInfo->aSortFlags!=0 );
if( res==0 ){
if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
@@ -969,7 +971,8 @@ int sqlite3VdbeSorterInit(
assert( pCsr->eCurType==CURTYPE_SORTER );
assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*)
< 0x7fffffff );
- szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nKeyField+1);
+ assert( pCsr->pKeyInfo->nKeyField<=pCsr->pKeyInfo->nAllField );
+ szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nAllField);
sz = SZ_VDBESORTER(nWorker+1);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
@@ -983,7 +986,12 @@ int sqlite3VdbeSorterInit(
pKeyInfo->db = 0;
if( nField && nWorker==0 ){
pKeyInfo->nKeyField = nField;
+ assert( nField<=pCsr->pKeyInfo->nAllField );
}
+ /* It is OK that pKeyInfo reuses the aSortFlags field from pCsr->pKeyInfo,
+ ** since the pCsr->pKeyInfo->aSortFlags[] array is invariant and lives
+ ** longer that pSorter. */
+ assert( pKeyInfo->aSortFlags==pCsr->pKeyInfo->aSortFlags );
sqlite3BtreeEnter(pBt);
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(pBt);
sqlite3BtreeLeave(pBt);
@@ -2763,7 +2771,7 @@ int sqlite3VdbeSorterCompare(
assert( r2->nField==nKeyCol );
pKey = vdbeSorterRowkey(pSorter, &nKey);
- sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2);
+ sqlite3VdbeRecordUnpack(nKey, pKey, r2);
for(i=0; i<nKeyCol; i++){
if( r2->aMem[i].flags & MEM_Null ){
*pRes = -1;
diff --git a/src/wal.c b/src/wal.c
index 5fe2296d6..1fd5b201c 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -3062,7 +3062,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
rc = walIndexReadHdr(pWal, pChanged);
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- walDisableBlocking(pWal);
if( rc==SQLITE_BUSY_TIMEOUT ){
rc = SQLITE_BUSY;
*pCnt |= WAL_RETRY_BLOCKED_MASK;
@@ -3077,6 +3076,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
** WAL_RETRY this routine will be called again and will probably be
** right on the second iteration.
*/
+ (void)walEnableBlocking(pWal);
if( pWal->apWiData[0]==0 ){
/* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
** We assume this is a transient condition, so return WAL_RETRY. The
@@ -3093,6 +3093,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
rc = SQLITE_BUSY_RECOVERY;
}
}
+ walDisableBlocking(pWal);
if( rc!=SQLITE_OK ){
return rc;
}
diff --git a/test/dblwidth-a.sql b/test/dblwidth-a.sql
new file mode 100644
index 000000000..38c219698
--- /dev/null
+++ b/test/dblwidth-a.sql
@@ -0,0 +1,20 @@
+/*
+** Run this script using "sqlite3" to confirm that the command-line
+** shell properly handles the output of double-width characters.
+**
+** https://sqlite.org/forum/forumpost/008ac80276
+*/
+.mode box
+CREATE TABLE data(word TEXT, description TEXT);
+INSERT INTO data VALUES('〈οὐκέτι〉','Greek without dblwidth <...>');
+.print .mode box
+SELECT * FROM data;
+.mode table
+.print .mode table
+SELECT * FROM data;
+.mode qbox
+.print .mode qbox
+SELECT * FROM data;
+.mode column
+.print .mode column
+SELECT * FROM data;
diff --git a/test/fts3join.test b/test/fts3join.test
index cbd08b63f..9171c817b 100644
--- a/test/fts3join.test
+++ b/test/fts3join.test
@@ -97,11 +97,8 @@ do_eqp_test 4.2 {
WHERE t4.y = ?;
} {
QUERY PLAN
- |--MATERIALIZE rr
- | `--SCAN ft4 VIRTUAL TABLE INDEX 3:
|--SCAN t4
- |--BLOOM FILTER ON rr (docid=?)
- `--SEARCH rr USING AUTOMATIC COVERING INDEX (docid=?) LEFT-JOIN
+ `--SCAN ft4 VIRTUAL TABLE INDEX 3: LEFT-JOIN
}
finish_test
diff --git a/test/join.test b/test/join.test
index 789ae0124..ef2f6335c 100644
--- a/test/join.test
+++ b/test/join.test
@@ -1316,20 +1316,30 @@ do_execsql_test join-31.1 {
CREATE TABLE t1(c0 INT , c1 INT); INSERT INTO t1(c0, c1) VALUES(NULL,11);
CREATE TABLE t2(c0 INT NOT NULL);
CREATE TABLE t2n(c0 INT);
- CREATE TABLE t3(x INT); INSERT INTO t3(x) VALUES(4);
- CREATE TABLE t5(c0 INT, x INT); INSERT INTO t5 VALUES(NULL, 4);
+ CREATE TABLE t3(x INT); INSERT INTO t3(x) VALUES(3);
+ CREATE TABLE t4(y INT); INSERT INTO t4(y) VALUES(4);
+ CREATE TABLE t5(c0 INT, x INT); INSERT INTO t5 VALUES(NULL, 5);
}
do_execsql_test join-31.2 {
SELECT * FROM t2 RIGHT JOIN t3 ON true LEFT JOIN t1 USING(c0);
-} {NULL 4 NULL}
+} {NULL 3 NULL}
do_execsql_test join-31.3 {
SELECT * FROM t2 RIGHT JOIN t3 ON true NATURAL LEFT JOIN t1;
-} {NULL 4 NULL}
+} {NULL 3 NULL}
do_execsql_test join-31.4 {
SELECT * FROM t2n RIGHT JOIN t3 ON true LEFT JOIN t1 USING(c0);
-} {NULL 4 NULL}
+} {NULL 3 NULL}
do_execsql_test join-31.5 {
SELECT * FROM t5 LEFT JOIN t1 USING(c0);
-} {NULL 4 NULL}
+} {NULL 5 NULL}
+do_execsql_test join-31.6 {
+ SELECT * FROM t3 LEFT JOIN t2 ON true LEFT JOIN t1 USING(c0);
+} {3 NULL NULL}
+do_execsql_test join-31.7 {
+ SELECT * FROM t3 LEFT JOIN t2 ON true NATURAL LEFT JOIN t1;
+} {3 NULL NULL}
+do_execsql_test join-31.8 {
+ SELECT * FROM t3 LEFT JOIN t2 ON true JOIN t4 ON true NATURAL LEFT JOIN t1;
+} {3 NULL 4 NULL}
finish_test
diff --git a/test/joinH.test b/test/joinH.test
index 908b93dee..339200968 100644
--- a/test/joinH.test
+++ b/test/joinH.test
@@ -341,4 +341,74 @@ do_execsql_test 13.4 {
GROUP BY a1.a ORDER BY 1;
} {-1480 240 480}
+#-------------------------------------------------------------------------
+# 2025-05-30
+# https://sqlite.org/forum/forumpost/5028c785b6
+#
+reset_db
+
+do_execsql_test 14.0 {
+ CREATE TABLE t1(c0 INT);
+ CREATE TABLE t2(c0 BLOB);
+ CREATE TABLE t3(c0 BLOB);
+ CREATE TABLE t4(c4 BLOB);
+ INSERT INTO t1(c0) VALUES(0);
+ INSERT INTO t3(c0) VALUES('0');
+}
+
+do_execsql_test 14.1.1 {
+ SELECT * FROM t1 NATURAL LEFT JOIN t2 NATURAL JOIN t3;
+} {0}
+
+do_execsql_test 14.1.2 {
+ SELECT * FROM t1 NATURAL LEFT JOIN t2 NATURAL JOIN t3 FULL JOIN t4 ON true;
+} {0 {}}
+
+do_execsql_test 14.1.3 {
+ SELECT * FROM (t1 NATURAL LEFT JOIN t2 NATURAL JOIN t3) FULL JOIN t4 ON true;
+} {0 {}}
+
+do_execsql_test 14.1.4 {
+ SELECT *
+ FROM (t1 NATURAL LEFT JOIN t2 NATURAL JOIN t3) AS qq FULL JOIN t4 ON true;
+} {0 {}}
+
+do_execsql_test 14.2.1 {
+ SELECT * FROM t3 NATURAL LEFT JOIN t2 NATURAL JOIN t1;
+} {0}
+
+do_execsql_test 14.2.2 {
+ SELECT * FROM t3 NATURAL LEFT JOIN t2 NATURAL JOIN t1 FULL JOIN t4 ON true;
+} {0 {}}
+
+do_execsql_test 14.2.3 {
+ SELECT * FROM (t3 NATURAL LEFT JOIN t2 NATURAL JOIN t1) FULL JOIN t4 ON true;
+} {0 {}}
+
+do_execsql_test 14.2.4 {
+ SELECT *
+ FROM (t3 NATURAL LEFT JOIN t2 NATURAL JOIN t1) AS qq FULL JOIN t4 ON true;
+} {0 {}}
+
+# 2025-06-01
+#
+reset_db
+do_execsql_test 15.1 {
+ CREATE TABLE t0(c0);
+ CREATE TABLE t1(c0);
+ CREATE TABLE t2(c0);
+ INSERT INTO t0 VALUES ('1.0');
+ INSERT INTO t2(c0) VALUES (9);
+ SELECT t0.c0,t2.c0 FROM (SELECT CAST(t0.c0 as REAL) AS c0 FROM t0) as subquery NATURAL LEFT JOIN t1 NATURAL JOIN t0 RIGHT JOIN t2 ON 1;
+} {1.0 9}
+do_execsql_test 15.2 {
+ CREATE TABLE x1(x COLLATE nocase);
+ CREATE TABLE x2(x);
+ CREATE TABLE x3(x);
+ CREATE TABLE t4(y);
+ INSERT INTO x1 VALUES('ABC');
+ INSERT INTO x3 VALUES('abc');
+ SELECT lower(x), quote(y) FROM x1 LEFT JOIN x2 USING (x) JOIN x3 USING (x) FULL JOIN t4;
+} {abc NULL}
+
finish_test
diff --git a/test/snapshot3.test b/test/snapshot3.test
index 470d463a6..6d57b1d0c 100644
--- a/test/snapshot3.test
+++ b/test/snapshot3.test
@@ -96,6 +96,9 @@ do_test 1.8 {
list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg
} {1 SQLITE_ERROR_SNAPSHOT}
+db3 close
+db2 close
+
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
diff --git a/test/tclsqlite.test b/test/tclsqlite.test
index 0758abd82..5f373ea18 100644
--- a/test/tclsqlite.test
+++ b/test/tclsqlite.test
@@ -9,7 +9,7 @@
#
#***********************************************************************
# This file implements regression tests for TCL interface to the
-# SQLite library.
+# SQLite library.
#
# Actually, all tests are based on the TCL interface, so the main
# interface is pretty well tested. This file contains some addition
@@ -121,7 +121,7 @@ ifcapable {complete} {
do_test tcl-1.14 {
set v [catch {db eval} msg]
lappend v $msg
-} {1 {wrong # args: should be "db eval ?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?"}}
+} {1 {wrong # args: should be "db eval ?OPTIONS? SQL ?VAR-NAME? ?SCRIPT?"}}
do_test tcl-1.15 {
set v [catch {db function} msg]
lappend v $msg
@@ -359,6 +359,19 @@ do_test tcl-9.3 {
execsql {SELECT typeof(ret_int())}
} {integer}
+proc breakAsNullUdf args {
+ if {"1" eq [lindex $args 0]} {return -code break}
+}
+do_test tcl-9.4 {
+ db function banu breakAsNullUdf
+ execsql {SELECT typeof(banu()), typeof(banu(1))}
+} {text null}
+do_test tcl-9.5 {
+ db nullvalue banunull
+ db eval {SELECT banu(), banu(1)}
+} {{} banunull}
+
+
# Recursive calls to the same user-defined function
#
ifcapable tclvar {
@@ -465,7 +478,7 @@ do_test tcl-10.13 {
db eval {SELECT * FROM t4}
} {1 2 5 6 7}
-# Now test that [db transaction] commands may be nested with
+# Now test that [db transaction] commands may be nested with
# the expected results.
#
do_test tcl-10.14 {
@@ -475,7 +488,7 @@ do_test tcl-10.14 {
INSERT INTO t4 VALUES('one');
}
- catch {
+ catch {
db transaction {
db eval { INSERT INTO t4 VALUES('two') }
db transaction {
@@ -674,11 +687,11 @@ do_test tcl-15.5 {
} {0}
-# 2017-06-26: The --withoutnulls flag to "db eval".
+# 2017-06-26: The -withoutnulls flag to "db eval".
#
-# In the "db eval --withoutnulls SQL ARRAY" form, NULL results cause the
-# corresponding array entry to be unset. The default behavior (without
-# the -withoutnulls flags) is for the corresponding array value to get
+# In the "db eval -withoutnulls SQL TARGET" form, NULL results cause the
+# corresponding target entry to be unset. The default behavior (without
+# the -withoutnulls flags) is for the corresponding target value to get
# the [db nullvalue] string.
#
catch {db close}
@@ -720,64 +733,64 @@ reset_db
proc add {a b} { return [expr $a + $b] }
proc ret {a} { return $a }
-db function add_i -returntype integer add
+db function add_i -returntype integer add
db function add_r -ret real add
-db function add_t -return text add
-db function add_b -returntype blob add
-db function add_a -returntype any add
+db function add_t -return text add
+db function add_b -returntype blob add
+db function add_a -returntype any add
-db function ret_i -returntype int ret
+db function ret_i -returntype int ret
db function ret_r -returntype real ret
-db function ret_t -returntype text ret
-db function ret_b -returntype blob ret
-db function ret_a -r any ret
+db function ret_t -returntype text ret
+db function ret_b -returntype blob ret
+db function ret_a -r any ret
do_execsql_test 17.0 {
SELECT quote( add_i(2, 3) );
- SELECT quote( add_r(2, 3) );
- SELECT quote( add_t(2, 3) );
- SELECT quote( add_b(2, 3) );
- SELECT quote( add_a(2, 3) );
+ SELECT quote( add_r(2, 3) );
+ SELECT quote( add_t(2, 3) );
+ SELECT quote( add_b(2, 3) );
+ SELECT quote( add_a(2, 3) );
} {5 5.0 '5' X'35' 5}
do_execsql_test 17.1 {
SELECT quote( add_i(2.2, 3.3) );
- SELECT quote( add_r(2.2, 3.3) );
- SELECT quote( add_t(2.2, 3.3) );
- SELECT quote( add_b(2.2, 3.3) );
- SELECT quote( add_a(2.2, 3.3) );
+ SELECT quote( add_r(2.2, 3.3) );
+ SELECT quote( add_t(2.2, 3.3) );
+ SELECT quote( add_b(2.2, 3.3) );
+ SELECT quote( add_a(2.2, 3.3) );
} {5.5 5.5 '5.5' X'352E35' 5.5}
do_execsql_test 17.2 {
SELECT quote( ret_i(2.5) );
- SELECT quote( ret_r(2.5) );
- SELECT quote( ret_t(2.5) );
- SELECT quote( ret_b(2.5) );
- SELECT quote( ret_a(2.5) );
+ SELECT quote( ret_r(2.5) );
+ SELECT quote( ret_t(2.5) );
+ SELECT quote( ret_b(2.5) );
+ SELECT quote( ret_a(2.5) );
} {2.5 2.5 '2.5' X'322E35' 2.5}
do_execsql_test 17.3 {
SELECT quote( ret_i('2.5') );
- SELECT quote( ret_r('2.5') );
- SELECT quote( ret_t('2.5') );
- SELECT quote( ret_b('2.5') );
- SELECT quote( ret_a('2.5') );
+ SELECT quote( ret_r('2.5') );
+ SELECT quote( ret_t('2.5') );
+ SELECT quote( ret_b('2.5') );
+ SELECT quote( ret_a('2.5') );
} {2.5 2.5 '2.5' X'322E35' '2.5'}
do_execsql_test 17.4 {
SELECT quote( ret_i('abc') );
- SELECT quote( ret_r('abc') );
- SELECT quote( ret_t('abc') );
- SELECT quote( ret_b('abc') );
- SELECT quote( ret_a('abc') );
+ SELECT quote( ret_r('abc') );
+ SELECT quote( ret_t('abc') );
+ SELECT quote( ret_b('abc') );
+ SELECT quote( ret_a('abc') );
} {'abc' 'abc' 'abc' X'616263' 'abc'}
do_execsql_test 17.5 {
SELECT quote( ret_i(X'616263') );
- SELECT quote( ret_r(X'616263') );
- SELECT quote( ret_t(X'616263') );
- SELECT quote( ret_b(X'616263') );
- SELECT quote( ret_a(X'616263') );
+ SELECT quote( ret_r(X'616263') );
+ SELECT quote( ret_t(X'616263') );
+ SELECT quote( ret_b(X'616263') );
+ SELECT quote( ret_a(X'616263') );
} {'abc' 'abc' 'abc' X'616263' X'616263'}
do_test 17.6.1 {
@@ -848,21 +861,70 @@ do_catchsql_test 19.911 {
} {1 {invalid command name "bind_fallback_does_not_exist"}}
db bind_fallback {}
-#-------------------------------------------------------------------------
+# 2025-05-05: the -asdict eval flag
+#
do_test 20.0 {
+ execsql {CREATE TABLE tad(a,b)}
+ execsql {INSERT INTO tad(a,b) VALUES('aa','bb'),('AA','BB')}
+ db eval -asdict {
+ SELECT a, b FROM tad WHERE 0
+ } D {}
+ set D
+} {* {a b}}
+
+do_test 20.1 {
+ unset D
+ set i 0
+ set res {}
+ set colNames {}
+ db eval -asdict {
+ SELECT a, b FROM tad ORDER BY a
+ } D {
+ dict set D i [incr i]
+ lappend res $i [dict get $D a] [dict get $D b]
+ if {1 == $i} {
+ set colNames [dict get $D *]
+ }
+ }
+ lappend res $colNames
+ unset D
+ set res
+} {1 AA BB 2 aa bb {a b}}
+
+do_test 20.2 {
+ set res {}
+ db eval -asdict -withoutnulls {
+ SELECT n, a, b FROM (
+ SELECT 1 as n, 'aa' as a, NULL as b
+ UNION ALL
+ SELECT 2 as n, NULL as a, 'bb' as b
+ )
+ ORDER BY n
+ } D {
+ dict unset D *
+ lappend res [dict values $D]
+ }
+ unset D
+ execsql {DROP TABLE tad}
+ set res
+} {{1 aa} {2 bb}}
+
+#-------------------------------------------------------------------------
+do_test 21.0 {
db transaction {
db close
}
} {}
-do_test 20.1 {
+do_test 21.1 {
sqlite3 db test.db
set rc [catch {
db eval {SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3} { db close }
} msg]
list $rc $msg
} {1 {invalid command name "db"}}
-
+
+
proc closedb {} {
db close
@@ -874,7 +936,7 @@ sqlite3 db test.db
db func closedb closedb
db func func1 func1
-do_test 20.2 {
+do_test 21.2 {
set rc [catch {
db eval {
SELECT closedb(),func1() UNION ALL SELECT 20,30 UNION ALL SELECT 30,40
@@ -884,9 +946,10 @@ do_test 20.2 {
} {0 {10 1 20 30 30 40}}
sqlite3 db :memory:
-do_test 21.1 {
+do_test 22.1 {
catch {db eval {SELECT 1 2 3;}} msg
db erroroffset
} {9}
+
finish_test
diff --git a/test/vacuum.test b/test/vacuum.test
index 57429c29e..82dd00d09 100644
--- a/test/vacuum.test
+++ b/test/vacuum.test
@@ -401,4 +401,25 @@ do_test vacuum-10.1 {
} {}
do_test vacuum-10.2 { execsql VACUUM } {}
+# Verify that VACUUM still works if ATTACH is disabled.
+#
+do_execsql_test vacuum-11.1 {
+ PRAGMA page_size=1024;
+ VACUUM;
+ PRAGMA page_size;
+} {1024}
+sqlite3_db_config db ATTACH_CREATE 0
+do_execsql_test vacuum-11.2 {
+ PRAGMA page_size=2048;
+ VACUUM;
+ PRAGMA page_size;
+} {2048}
+sqlite3_db_config db ATTACH_CREATE 1
+sqlite3_db_config db ATTACH_WRITE 0
+do_execsql_test vacuum-11.3 {
+ PRAGMA page_size=4096;
+ VACUUM;
+ PRAGMA page_size;
+} {4096}
+
finish_test
diff --git a/test/walsetlk_recover.test b/test/walsetlk_recover.test
new file mode 100644
index 000000000..1daece747
--- /dev/null
+++ b/test/walsetlk_recover.test
@@ -0,0 +1,104 @@
+# 2025 May 30
+#
+# 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.
+#
+#***********************************************************************
+#
+# TESTRUNNER: slow
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+set testprefix walsetlk_recover
+
+ifcapable !wal {finish_test ; return }
+# ifcapable !setlk_timeout {finish_test ; return }
+
+do_execsql_test 1.0 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(3, 4);
+ INSERT INTO t1 VALUES(5, 6);
+} {wal}
+
+db_save_and_close
+db_restore
+
+testfixture_nb myvar {
+
+ testvfs tvfs -fullshm 1
+ sqlite3 db test.db -vfs tvfs
+ tvfs script vfs_callback
+ tvfs filter xRead
+
+ set ::done 0
+ proc vfs_callback {method file args} {
+ if {$::done==0 && [string match *wal $file]} {
+ after 4000
+ set ::done 1
+ }
+ return "SQLITE_OK"
+ }
+
+ db eval {
+ SELECT * FROM t1
+ }
+
+ db close
+}
+
+# Give the [testfixture_nb] command time to start
+after 1000 {set xyz 1}
+vwait xyz
+
+testvfs tvfs -fullshm 1
+sqlite3 db test.db -vfs tvfs
+
+tvfs script sleep_callback
+tvfs filter xSleep
+set ::sleep_count 0
+proc sleep_callback {args} {
+ incr ::sleep_count
+}
+
+sqlite3 db test.db -vfs tvfs
+db timeout 500
+set tm [lindex [time {
+ catch {
+ db eval {SELECT * FROM t1}
+ } msg
+}] 0]
+
+do_test 1.2 { set ::msg } {database is locked}
+do_test 1.3.($::tm) { expr $::tm>400000 && $::tm<2000000 } 1
+
+vwait myvar
+
+do_execsql_test 1.4 {
+ SELECT * FROM t1
+} {1 2 3 4 5 6}
+
+db close
+tvfs delete
+
+# All SQLite builds should pass the tests above. SQLITE_ENABLE_SETLK_TIMEOUT=1
+# builds do so without calling the VFS xSleep method.
+if {$::sqlite_options(setlk_timeout)==1} {
+ do_test 1.5.1 {
+ set ::sleep_count
+ } 0
+} else {
+ do_test 1.5.2 {
+ expr $::sleep_count>0
+ } 1
+}
+
+finish_test
+
diff --git a/test/walsetlk_snapshot.test b/test/walsetlk_snapshot.test
new file mode 100644
index 000000000..e05ad69cc
--- /dev/null
+++ b/test/walsetlk_snapshot.test
@@ -0,0 +1,109 @@
+# 2025 May 30
+#
+# 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.
+#
+#***********************************************************************
+#
+# TESTRUNNER: slow
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+set testprefix walsetlk_snapshot
+
+ifcapable !wal {finish_test ; return }
+ifcapable !snapshot {finish_test; return}
+
+db close
+testvfs tvfs -fullshm 1
+sqlite3 db test.db -vfs tvfs
+tvfs script sleep_callback
+tvfs filter xSleep
+set ::sleep_count 0
+proc sleep_callback {args} {
+ incr ::sleep_count
+}
+
+do_execsql_test 1.0 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(3, 4);
+ INSERT INTO t1 VALUES(5, 6);
+} {wal}
+
+do_test 1.1 {
+ db eval BEGIN
+ set ::snap [sqlite3_snapshot_get db main]
+ db eval {
+ INSERT INTO t1 VALUES(7, 8);
+ COMMIT;
+ }
+} {}
+
+testfixture_nb myvar {
+
+ testvfs tvfs -fullshm 1
+ sqlite3 db test.db -vfs tvfs
+ tvfs script vfs_callback
+ tvfs filter {xWrite}
+
+ set ::done 0
+ proc vfs_callback {args} {
+ if {$::done==0} {
+ after 4000
+ set ::done 1
+ }
+ return "SQLITE_OK"
+ }
+
+ db eval {
+ PRAGMA wal_checkpoint;
+ }
+
+ db close
+}
+
+# Give the [testfixture_nb] command time to start
+after 1000 {set xyz 1}
+vwait xyz
+
+db timeout 500
+set tm [lindex [time {
+ catch {
+ db eval BEGIN
+ sqlite3_snapshot_open db main $::snap
+ } msg
+}] 0]
+
+do_test 1.2 { set ::msg } {SQLITE_BUSY}
+do_test 1.3.($::tm) { expr $::tm<2000000 } 1
+
+do_execsql_test 1.4 {
+ SELECT * FROM t1
+} {1 2 3 4 5 6 7 8}
+
+sqlite3_snapshot_free $::snap
+
+vwait myvar
+
+# All SQLite builds should pass the tests above. SQLITE_ENABLE_SETLK_TIMEOUT=1
+# builds do so without calling the VFS xSleep method.
+if {$::sqlite_options(setlk_timeout)==1} {
+ do_test 1.5.1 {
+ set ::sleep_count
+ } 0
+} else {
+ do_test 1.5.2 {
+ expr $::sleep_count>0
+ } 1
+}
+
+finish_test
+
diff --git a/tool/sqlite3_rsync.c b/tool/sqlite3_rsync.c
index 46ff2e50e..03a74f365 100644
--- a/tool/sqlite3_rsync.c
+++ b/tool/sqlite3_rsync.c
@@ -1538,7 +1538,7 @@ static void originSide(SQLiteRsync *p){
sqlite3_finalize(pInsHash);
pCkHash = 0;
pInsHash = 0;
- if( mxHash<p->nPage ){
+ if( mxHash<=p->nPage ){
runSql(p, "WITH RECURSIVE c(n) AS"
" (VALUES(%d) UNION ALL SELECT n+1 FROM c WHERE n<%d)"
" INSERT INTO badHash SELECT n, 1 FROM c",
@@ -1797,6 +1797,7 @@ static void replicaSide(SQLiteRsync *p){
closeDb(p);
break;
}
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
runSql(p, "ATTACH %Q AS 'replica'", p->zReplica);
if( p->wrongEncoding ){
p->wrongEncoding = 0;