diff --git a/Makefile.msc b/Makefile.msc
index 60669993c1..1e20849107 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -66,6 +66,14 @@ USE_STDCALL = 0
USE_SEH = 1
!ENDIF
+# Use STATICALLY_LINK_TCL=1 to statically link against TCL
+#
+!IFNDEF STATICALLY_LINK_TCL
+STATICALLY_LINK_TCL = 0
+!ELSEIF $(STATICALLY_LINK_TCL)!=0
+CCOPTS = $(CCOPTS) -DSTATIC_BUILD
+!ENDIF
+
# Set this non-0 to have the shell executable link against the core dynamic
# link library.
#
@@ -929,10 +937,9 @@ TCC = $(TCC) /fsanitize=address
# prior to running nmake in order to match the actual installed location and
# version on this machine.
#
-!IFNDEF TCLVERSION
-TCLVERSION = 86
+!IF $(STATICALLY_LINK_TCL)!=0
+TCLSUFFIX = s
!ENDIF
-
!IFNDEF TCLSUFFIX
TCLSUFFIX =
!ENDIF
@@ -941,6 +948,19 @@ TCLSUFFIX =
TCLDIR = C:\Tcl
!ENDIF
+!IFNDEF TCLVERSION
+!IF EXISTS("$(TCLDIR)\lib\tcl90$(TCLSUFFIX).lib")
+TCLVERSION = 90
+!ELSEIF EXISTS("$(TCLDIR)\lib\tcl86$(TCLSUFFIX).lib")
+TCLVERSION = 86
+!ELSEIF EXISTS("$(TCLDIR)\lib\tcl86t.lib")
+TCLSUFFIX = t
+TCLVERSION = 86
+!ELSE
+TCLVERSION = 90
+!ENDIF
+!ENDIF
+
!IFNDEF TCLINCDIR
TCLINCDIR = $(TCLDIR)\include
!ENDIF
@@ -953,9 +973,21 @@ TCLLIBDIR = $(TCLDIR)\lib
LIBTCL = tcl$(TCLVERSION)$(TCLSUFFIX).lib
!ENDIF
+!IFNDEF TCLLIBS
+!IF $(STATICALLY_LINK_TCL)!=0
+TCLLIBS = /NODEFAULTLIB:libucrt.lib netapi32.lib user32.lib ucrt.lib
+!ELSE
+TCLLIBS =
+!ENDIF
+!ENDIF
+
!IFNDEF LIBTCLSTUB
+!IF EXISTS("$(TCLLIBDIR)\tclstub$(TCLSUFFIX).lib")
+LIBTCLSTUB = tclstub$(TCLSUFFIX).lib
+!ELSE
LIBTCLSTUB = tclstub$(TCLVERSION)$(TCLSUFFIX).lib
!ENDIF
+!ENDIF
!IFNDEF LIBTCLPATH
LIBTCLPATH = $(TCLDIR)\bin
@@ -1013,10 +1045,18 @@ LIBICU = icuuc.lib icuin.lib
# specific Tcl shell to use.
#
!IFNDEF TCLSH_CMD
-!IF $(USE_TCLSH_IN_PATH)!=0 || !EXIST("$(TCLDIR)\bin\tclsh.exe")
-TCLSH_CMD = tclsh
-!ELSE
+!IF EXISTS("$(TCLDIR)\bin\tclsh$(TCLVERSION).exe")
+TCLSH_CMD = $(TCLDIR)\bin\tclsh$(TCLVERSION).exe
+!ELSEIF EXISTS("$(TCLDIR)\bin\tclsh90.exe")
+TCLSH_CMD = $(TCLDIR)\bin\tclsh90.exe
+!ELSEIF EXISTS("$(TCLDIR)\bin\tclsh86.exe")
+TCLSH_CMD = $(TCLDIR)\bin\tclsh86.exe
+!ELSEIF EXISTS("$(TCLDIR)\bin\tclsh86t.exe")
+TCLSH_CMD = $(TCLDIR)\bin\tclsh86t.exe
+!ELSEIF EXISTS("$(TCLDIR)\bin\tclsh.exe")
TCLSH_CMD = $(TCLDIR)\bin\tclsh.exe
+!ELSE
+TCLSH_CMD = tclsh
!ENDIF
!ENDIF
# <>
@@ -1824,7 +1864,7 @@ tclsqlite3.def: tclsqlite.lo
pkgIndex.tcl: $(TOP)\VERSION
for /F %%V in ('type "$(TOP)\VERSION"') do ( \
- echo package ifneeded sqlite3 @version@ [list load [file join $$dir $(SQLITE3TCLDLL)] sqlite3] \
+ echo package ifneeded sqlite3 @version@ [list load [file join $$dir $(SQLITE3TCLDLL)] Sqlite3] \
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact @version@ %%V > pkgIndex.tcl \
)
@@ -1868,7 +1908,7 @@ dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
RSYNC_SRC = \
- $(TOP)\tool\sqlite3-rsync.c \
+ $(TOP)\tool\sqlite3_rsync.c \
$(SQLITE3C)
RSYNC_OPT = \
@@ -1877,7 +1917,7 @@ RSYNC_OPT = \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_OMIT_DEPRECATED
-sqlite3-rsync.exe: $(RSYNC_SRC) $(LIBRESOBJS)
+sqlite3_rsync.exe: $(RSYNC_SRC) $(LIBRESOBJS)
$(LTLINK) $(RSYNC_OPT) $(NO_WARN) $(RSYNC_SRC) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H)
@@ -2537,7 +2577,7 @@ extensiontest: testfixture.exe testloadext.dll
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
-tool-zip: testfixture.exe sqlite3.exe sqldiff.exe sqlite3_analyzer.exe $(TOP)\tool\mktoolzip.tcl
+tool-zip: testfixture.exe sqlite3.exe sqldiff.exe sqlite3_analyzer.exe sqlite3_rsync.exe $(TOP)\tool\mktoolzip.tcl
.\testfixture.exe $(TOP)\tool\mktoolzip.tcl
coretestprogs: testfixture.exe sqlite3.exe
@@ -2746,6 +2786,16 @@ THREADTEST3_SRC = \
threadtest3.exe: $(THREADTEST3_SRC) $(TOP)\src\test_multiplex.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\test\threadtest3.c $(TOP)\src\test_multiplex.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
+# Display key variables that control which version of TCL is to be used.
+#
+tcl-env:
+ @echo TCLDIR = $(TCLDIR)
+ @echo TCLVERSION = $(TCLVERSION)
+ @echo TCLSUFFIX = $(TCLSUFFIX)
+ @echo LIBTCL = $(LIBTCL)
+ @echo LIBTCLSTUB = $(LIBTCLSTUB)
+ @echo TCLSH_CMD = $(TCLSH_CMD)
+
LSMDIR=$(TOP)\ext\lsm1
!INCLUDE $(LSMDIR)\Makefile.msc
@@ -2779,7 +2829,7 @@ clean:
del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL
del /Q sqlite3rc.h 2>NUL
del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL
- del /Q sqlite3_analyzer.exe sqlite3_analyzer.c sqlite3-rsync.exe 2>NUL
+ del /Q sqlite3_analyzer.exe sqlite3_analyzer.c sqlite3_rsync.exe 2>NUL
del /Q sqlite-*-output.vsix 2>NUL
del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL
del /Q sqltclsh.* 2>NUL
diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc
index f8a65e90cc..efebc9931a 100644
--- a/autoconf/Makefile.msc
+++ b/autoconf/Makefile.msc
@@ -66,6 +66,14 @@ USE_STDCALL = 0
USE_SEH = 1
!ENDIF
+# Use STATICALLY_LINK_TCL=1 to statically link against TCL
+#
+!IFNDEF STATICALLY_LINK_TCL
+STATICALLY_LINK_TCL = 0
+!ELSEIF $(STATICALLY_LINK_TCL)!=0
+CCOPTS = $(CCOPTS) -DSTATIC_BUILD
+!ENDIF
+
# Set this non-0 to have the shell executable link against the core dynamic
# link library.
#
diff --git a/autoconf/tea/README b/autoconf/tea/README.txt
similarity index 66%
rename from autoconf/tea/README
rename to autoconf/tea/README.txt
index 99dc8b8f03..ea7eb930f2 100644
--- a/autoconf/tea/README
+++ b/autoconf/tea/README.txt
@@ -3,6 +3,27 @@ Architecture (TEA). For additional information on SQLite see
http://www.sqlite.org/
+-------------------------------------------------------------------
+Update 2024-10-11:
+
+A better way to build the TCL extension for SQLite is to use the
+canonical source code tarball. For Unix:
+
+ ./configure --with-tclsh=$(TCLSH)
+ make tclextension-install
+
+For Windows:
+
+ nmake /f Makefile.msc tclextension-install TCLSH_CMD=$(TCLSH)
+
+In both of the above, replace $(TCLSH) with the full pathname of
+of the tclsh that you want the SQLite extension to work with.
+
+This TEA builder is antiquated. It does not work for TCL9. The
+SQLite devs don't know how to fix it. If you would like to help
+fix it, contact us.
+------------------------------------------------------------------
+
UNIX BUILD
==========
diff --git a/autoconf/tea/pkgIndex.tcl.in b/autoconf/tea/pkgIndex.tcl.in
index f95f7d3893..666812dee7 100644
--- a/autoconf/tea/pkgIndex.tcl.in
+++ b/autoconf/tea/pkgIndex.tcl.in
@@ -3,8 +3,8 @@
#
if {[package vsatisfies [package provide Tcl] 9.0-]} {
package ifneeded sqlite3 @PACKAGE_VERSION@ \
- [list load [file join $dir @PKG_LIB_FILE9@] sqlite3]
+ [list load [file join $dir @PKG_LIB_FILE9@] Sqlite3]
} else {
package ifneeded sqlite3 @PACKAGE_VERSION@ \
- [list load [file join $dir @PKG_LIB_FILE8@] sqlite3]
+ [list load [file join $dir @PKG_LIB_FILE8@] Sqlite3]
}
diff --git a/autoconf/tea/win/makefile.vc b/autoconf/tea/win/makefile.vc
index da56e811fc..dacb7c6b3a 100644
--- a/autoconf/tea/win/makefile.vc
+++ b/autoconf/tea/win/makefile.vc
@@ -407,7 +407,7 @@ install-libraries:
@echo Installing package index in '$(SCRIPT_INSTALL_DIR)'
@type << >"$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
package ifneeded $(PROJECT) $(DOTVERSION) \
- [list load [file join $$dir $(PRJLIBNAME)] sqlite3]
+ [list load [file join $$dir $(PRJLIBNAME)] Sqlite3]
<<
install-docs:
diff --git a/configure.ac b/configure.ac
index 40d1dbd07f..cd5702a338 100644
--- a/configure.ac
+++ b/configure.ac
@@ -128,7 +128,7 @@ AC_ARG_ENABLE(tcl,
[use_tcl=$enableval],[use_tcl=yes])
original_use_tcl=${use_tcl}
if test x"${with_tclsh}" == x -a x"${with_tcl}" == x; then
- AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh tclsh9.0],none)
+ AC_CHECK_PROGS(TCLSH_CMD, [tclsh9.0 tclsh8.6 tclsh],none)
with_tclsh=${TCLSH_CMD}
fi
if test x"${with_tclsh}" != x -a x"${with_tclsh}" != xnone; then
diff --git a/doc/compile-for-unix.md b/doc/compile-for-unix.md
new file mode 100644
index 0000000000..ff5e2111a7
--- /dev/null
+++ b/doc/compile-for-unix.md
@@ -0,0 +1,58 @@
+# Notes On Compiling SQLite On All Kinds Of Unix
+
+Here are step-by-step instructions on how to build SQLite from
+canonical source on any modern machine that isn't Windows. These
+notes are tested (on 2024-10-11) on Ubuntu and on MacOS, but they
+are general and should work on most any modern unix platform.
+
+ 1. Install a C-compiler. GCC or Clang both work fine. If you are
+ reading this document, you've probably already done that.
+
+ 2. Install TCL9 development libraries. In this note, we'll do a
+ private install in the $HOME/local directory, but you can make
+ adjustments to install TCL9 wherever you like.
+ install the TCL development libraries in the "`c:\Tcl`" directory.
+
+ This document assumes you are working with TCL version 9.0.
+
+ - Get the TCL source archive, perhaps from
+ [https://www.tcl.tk/software/tcltk/download.html](https://www.tcl.tk/software/tcltk/download.html)
+ or [https://sqlite.org/tmp/tcl9.0.0.tar.gz](https://sqlite.org/tmp/tcl9.0.0.tar.gz)
+
- Untar the source archive. CD into the "unix/" subfolder
+ of the source tree.
+
- Run: `mkdir $HOME/local`
+
- Run: `./configure --prefix=$HOME/local`
+
- Run: `make install`
+
+
+ 4. Download the SQLite source tree and unpack it. CD into the
+ toplevel directory of the source tree.
+
+ 5. Run: `./configure --enable-all --with-tclsh=$HOME/local/bin/tclsh9.0`
+
+ You do not need to use --with-tclsh if the tclsh you want to use is the
+ first one on your PATH.
+
+ 6. Run the "`Makefile`" makefile with an appropriate target.
+ Examples:
+
+ - `make sqlite3.c`
+
- `make sqlite3`
+
- `make sqldiff`
+
- `make sqlite3_rsync`
+
- `make tclextension-install`
+
- `make devtest`
+
- `make releasetest`
+
- `make sqlite3_analyzer`
+
+
+ It is not required that you run the "tclextension-install" target prior to
+ running tests. However, the tests will run more smoothly if you do.
+ The version of SQLite used for the TCL extension does *not* need to
+ correspond to the version of SQLite under test. So you can install the
+ SQLite TCL extension once, and then use it to test many different versions
+ of SQLite.
+
+
+ 7. For a debugging build of the CLI, where the ".treetrace" and ".wheretrace"
+ commands work, add the the --enable-debug argument to configure.
diff --git a/doc/compile-for-windows.md b/doc/compile-for-windows.md
index 1627188acd..fe06697c56 100644
--- a/doc/compile-for-windows.md
+++ b/doc/compile-for-windows.md
@@ -1,7 +1,7 @@
# Notes On Compiling SQLite On Windows 11
Here are step-by-step instructions on how to build SQLite from
-canonical source on a new Windows 11 PC, as of 2023-11-01:
+canonical source on a new Windows 11 PC, as of 2024-10-09:
1. Install Microsoft Visual Studio. The free "community edition"
will work fine. Do a standard install for C++ development.
@@ -20,9 +20,11 @@ canonical source on a new Windows 11 PC, as of 2023-11-01:
install the TCL development libraries in the "`c:\Tcl`" directory.
Make adjustments
if you want TCL installed somewhere else. SQLite needs both the
- "tclsh.exe" command-line tool as part of the build process, and
- the "tcl86.lib" library in order to run tests. You will need
- TCL version 8.6 or later.
+ "tclsh90.exe" command-line tool as part of the build process, and
+ the "tcl90.lib" and "tclstub.lib" libraries in order to run tests.
+ This document assumes you are working with TCL version 9.0.
+ See versions of this document from prior to 2024-10-10 for
+ instructions on how to build using TCL version 8.6.
- Get the TCL source archive, perhaps from
[https://www.tcl.tk/software/tcltk/download.html](https://www.tcl.tk/software/tcltk/download.html).
@@ -30,13 +32,10 @@ canonical source on a new Windows 11 PC, as of 2023-11-01:
of the source tree.
- Run: `nmake /f makefile.vc release`
- Run: `nmake /f makefile.vc INSTALLDIR=c:\Tcl install`
-
- CD to `c:\Tcl\lib`. In that subfolder make a copy of the
- "`tcl86t.lib`" file to the alternative name "`tcl86.lib`"
- (omitting the second 't'). Leave the copy in the same directory
- as the original.
-
- CD to `c:\Tcl\bin`. Make a copy of the "`tclsh86t.exe`"
- file into "`tclsh.exe`" (without the "86t") in the same directory.
-
- Add `c:\Tcl\bin` to your %PATH%. To do this, go to Settings
+
- Optional: CD to `c:\Tcl\bin` and make a copy of
+ `tclsh90.exe` over into just `tclsh.exe`.
+
- Optional:
+ Add `c:\Tcl\bin` to your %PATH%. To do this, go to Settings
and search for "path". Select "edit environment variables for
your account" and modify your default PATH accordingly.
You will need to close and reopen your command prompts after
@@ -59,6 +58,7 @@ canonical source on a new Windows 11 PC, as of 2023-11-01:
- `nmake /f makefile.msc sqlite3.c`
- `nmake /f makefile.msc sqlite3.exe`
- `nmake /f makefile.msc sqldiff.exe`
+
- `nmake /f makefile.msc sqlite3_rsync.exe`
- `nmake /f makefile.msc tclextension-install`
- `nmake /f makefile.msc devtest`
- `nmake /f makefile.msc releasetest`
@@ -127,7 +127,7 @@ nmake /f Makefile.msc sqlite3_analyzer.exe
~~~~
And you will end up with a working executable. However, that executable
-will depend on having the "tcl86.dll" library somewhere on your %PATH%.
+will depend on having the "tcl98.dll" library somewhere on your %PATH%.
Use the following steps to build an executable that has the TCL library
statically linked so that it does not depend on separate DLL:
@@ -137,27 +137,26 @@ statically linked so that it does not depend on separate DLL:
2. Untar the TCL source tarball into a fresh directory. CD into
the "win/" subfolder.
- 3. Run: `nmake /f makefile.vc OPTS=nothreads,static shell`
-
+ 3. Run: `nmake /f makefile.vc OPTS=static shell`
4. CD into the "Release*" subfolder that is created (note the
wildcard - the full name of the directory might vary). There
- you will find the "tcl86s.lib" file. Copy this file into the
- same directory that you put the "tcl86.lib" on your initial
+ you will find the "tcl90s.lib" file. Copy this file into the
+ same directory that you put the "tcl90.lib" on your initial
installation. (In this document, that directory is
"`C:\Tcl32\lib`" for 32-bit builds and
"`C:\Tcl\lib`" for 64-bit builds.)
5. CD into your SQLite source code directory and build the desired
- utility program, but add the following extra arguments to the
+ utility program, but add the following extra argument to the
nmake command line:
- CCOPTS="-DSTATIC_BUILD" LIBTCL="tcl86s.lib netapi32.lib user32.lib"
+ STATICALLY_LINK_TCL=1
So, for example, to build a statically linked version of
sqlite3_analyzer.exe, you might type:
- nmake /f Makefile.msc CCOPTS="-DSTATIC_BUILD" LIBTCL="tcl86s.lib netapi32.lib user32.lib" sqlite3_analyzer.exe
+ nmake /f Makefile.msc STATICALLY_LINK_TCL=1 sqlite3_analyzer.exe
6. After your executable is built, you can verify that it does not
diff --git a/ext/expert/expert1.test b/ext/expert/expert1.test
index 239450442e..16bd149fa1 100644
--- a/ext/expert/expert1.test
+++ b/ext/expert/expert1.test
@@ -402,6 +402,19 @@ do_setup_rec_test $tn.19.0 {
SCAN t1 USING COVERING INDEX t1_idx_01a7214e
}
+ifcapable fts5 {
+ do_setup_rec_test $tn.20.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(a);
+ CREATE TABLE t1(x, y);
+ } {
+ SELECT * FROM ft, t1 WHERE a=x
+ } {
+ CREATE INDEX t1_idx_00000078 ON t1(x);
+ SCAN ft VIRTUAL TABLE INDEX 0:
+ SEARCH t1 USING INDEX t1_idx_00000078 (x=?)
+ }
+}
+
}
proc do_candidates_test {tn sql res} {
@@ -507,4 +520,65 @@ do_candidates_test 6.1 {
CREATE INDEX x1_idx_00000062 ON x1(b);
}
+#-------------------------------------------------------------------------
+ifcapable fts5 {
+ reset_db
+ do_execsql_test 7.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(a);
+ CREATE TABLE t1(x, y);
+ }
+
+ do_candidates_test 7.1 {
+ SELECT * FROM ft, t1 WHERE a=x
+ } {
+ CREATE INDEX t1_idx_00000078 ON t1(x);
+ }
+
+ register_tcl_module db
+ proc vtab_command {method args} {
+ global G
+
+ switch -- $method {
+ xConnect {
+ return "CREATE TABLE t1(a, b, c);"
+ }
+
+ xBestIndex {
+ return [list]
+ }
+
+ xFilter {
+ return [list sql "SELECT rowid, * FROM t0"]
+ }
+ }
+
+ return {}
+ }
+
+ do_execsql_test 7.2 {
+ CREATE TABLE t0(a, b, c);
+ INSERT INTO t0 VALUES(1, 2, 3), (11, 22, 33);
+ CREATE VIRTUAL TABLE t2 USING tcl(vtab_command);
+ }
+
+ do_execsql_test 7.3 {
+ SELECT * FROM t2
+ } {
+ 1 2 3
+ 11 22 33
+ }
+
+ do_candidates_test 7.4 {
+ SELECT * FROM ft, t1 WHERE a=x
+ } {
+ CREATE INDEX t1_idx_00000078 ON t1(x);
+ }
+
+ do_test 7.5 {
+ set expert [sqlite3_expert_new db]
+ list [catch { $expert sql "SELECT * FROM ft, t2 WHERE b=1" } msg] $msg
+ } {1 {no such table: t2}}
+ $expert destroy
+}
+
finish_test
diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c
index 3177339584..099a5235dd 100644
--- a/ext/expert/sqlite3expert.c
+++ b/ext/expert/sqlite3expert.c
@@ -1392,6 +1392,66 @@ static int idxProcessTriggers(sqlite3expert *p, char **pzErr){
return rc;
}
+/*
+** This function tests if the schema of the main database of database handle
+** db contains an object named zTab. Assuming no error occurs, output parameter
+** (*pbContains) is set to true if zTab exists, or false if it does not.
+**
+** Or, if an error occurs, an SQLite error code is returned. The final value
+** of (*pbContains) is undefined in this case.
+*/
+static int expertDbContainsObject(
+ sqlite3 *db,
+ const char *zTab,
+ int *pbContains /* OUT: True if object exists */
+){
+ const char *zSql = "SELECT 1 FROM sqlite_schema WHERE name = ?";
+ sqlite3_stmt *pSql = 0;
+ int rc = SQLITE_OK;
+ int ret = 0;
+
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_text(pSql, 1, zTab, -1, SQLITE_STATIC);
+ if( SQLITE_ROW==sqlite3_step(pSql) ){
+ ret = 1;
+ }
+ rc = sqlite3_finalize(pSql);
+ }
+
+ *pbContains = ret;
+ return rc;
+}
+
+/*
+** Execute SQL command zSql using database handle db. If no error occurs,
+** set (*pzErr) to NULL and return SQLITE_OK.
+**
+** If an error does occur, return an SQLite error code and set (*pzErr) to
+** point to a buffer containing an English language error message. Except,
+** if the error message begins with "no such module:", then ignore the
+** error and return as if the SQL statement had succeeded.
+**
+** This is used to copy as much of the database schema as possible while
+** ignoring any errors related to missing virtual table modules.
+*/
+static int expertSchemaSql(sqlite3 *db, const char *zSql, char **pzErr){
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+
+ rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
+ if( rc!=SQLITE_OK && zErr ){
+ int nErr = STRLEN(zErr);
+ if( nErr>=15 && memcmp(zErr, "no such module:", 15)==0 ){
+ sqlite3_free(zErr);
+ rc = SQLITE_OK;
+ zErr = 0;
+ }
+ }
+
+ *pzErr = zErr;
+ return rc;
+}
static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
int rc = idxRegisterVtab(p);
@@ -1403,22 +1463,29 @@ static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
** 2) Create the equivalent virtual table in dbv.
*/
rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
- "SELECT type, name, sql, 1 FROM sqlite_schema "
+ "SELECT type, name, sql, 1, sql LIKE 'create virtual%' "
+ "FROM sqlite_schema "
"WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
" UNION ALL "
- "SELECT type, name, sql, 2 FROM sqlite_schema "
+ "SELECT type, name, sql, 2, 0 FROM sqlite_schema "
"WHERE type = 'trigger'"
" AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
- "ORDER BY 4, 1"
+ "ORDER BY 4, 5 DESC, 1"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
+ int bVirtual = sqlite3_column_int(pSchema, 4);
+ int bExists = 0;
if( zType==0 || zName==0 ) continue;
- if( zType[0]=='v' || zType[1]=='r' ){
- if( zSql ) rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
+ rc = expertDbContainsObject(p->dbv, zName, &bExists);
+ if( rc || bExists ) continue;
+
+ if( zType[0]=='v' || zType[1]=='r' || bVirtual ){
+ /* A view. Or a trigger on a view. */
+ if( zSql ) rc = expertSchemaSql(p->dbv, zSql, pzErrmsg);
}else{
IdxTable *pTab;
rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
@@ -1957,12 +2024,18 @@ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
if( rc==SQLITE_OK ){
sqlite3_stmt *pSql = 0;
rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
- "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
- " AND sql NOT LIKE 'CREATE VIRTUAL %%' ORDER BY rowid"
+ "SELECT sql, name "
+ " FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
+ " ORDER BY rowid"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
- if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
+ const char *zName = (const char*)sqlite3_column_text(pSql, 1);
+ int bExists = 0;
+ rc = expertDbContainsObject(pNew->dbm, zName, &bExists);
+ if( rc==SQLITE_OK && zSql && bExists==0 ){
+ rc = expertSchemaSql(pNew->dbm, zSql, pzErrmsg);
+ }
}
idxFinalize(&rc, pSql);
}
diff --git a/ext/fts5/fts5_tokenize.c b/ext/fts5/fts5_tokenize.c
index f92529b840..f9581b080c 100644
--- a/ext/fts5/fts5_tokenize.c
+++ b/ext/fts5/fts5_tokenize.c
@@ -198,7 +198,7 @@ static const unsigned char sqlite3Utf8Trans1[] = {
c = *(zIn++); \
if( c>=0xc0 ){ \
c = sqlite3Utf8Trans1[c-0xc0]; \
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
+ while( zIniColumn==SERIES_COLUMN_VALUE ){
- switch( op ){
- case SQLITE_INDEX_CONSTRAINT_EQ:
- case SQLITE_INDEX_CONSTRAINT_IS: {
- idxNum |= 0x0080;
- idxNum &= ~0x3300;
- aIdx[5] = i;
- aIdx[6] = -1;
- bStartSeen = 1;
- break;
- }
- case SQLITE_INDEX_CONSTRAINT_GE: {
- if( idxNum & 0x0080 ) break;
- idxNum |= 0x0100;
- idxNum &= ~0x0200;
- aIdx[5] = i;
- bStartSeen = 1;
- break;
- }
- case SQLITE_INDEX_CONSTRAINT_GT: {
- if( idxNum & 0x0080 ) break;
- idxNum |= 0x0200;
- idxNum &= ~0x0100;
- aIdx[5] = i;
- bStartSeen = 1;
- break;
- }
- case SQLITE_INDEX_CONSTRAINT_LE: {
- if( idxNum & 0x0080 ) break;
- idxNum |= 0x1000;
- idxNum &= ~0x2000;
- aIdx[6] = i;
- break;
- }
- case SQLITE_INDEX_CONSTRAINT_LT: {
- if( idxNum & 0x0080 ) break;
- idxNum |= 0x2000;
- idxNum &= ~0x1000;
- aIdx[6] = i;
- break;
+ if( pConstraint->iColumniColumn==SERIES_COLUMN_VALUE ){
+ switch( op ){
+ case SQLITE_INDEX_CONSTRAINT_EQ:
+ case SQLITE_INDEX_CONSTRAINT_IS: {
+ idxNum |= 0x0080;
+ idxNum &= ~0x3300;
+ aIdx[5] = i;
+ aIdx[6] = -1;
+ bStartSeen = 1;
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_GE: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x0100;
+ idxNum &= ~0x0200;
+ aIdx[5] = i;
+ bStartSeen = 1;
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_GT: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x0200;
+ idxNum &= ~0x0100;
+ aIdx[5] = i;
+ bStartSeen = 1;
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_LE: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x1000;
+ idxNum &= ~0x2000;
+ aIdx[6] = i;
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_LT: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x2000;
+ idxNum &= ~0x1000;
+ aIdx[6] = i;
+ break;
+ }
}
}
continue;
diff --git a/ext/misc/sqlite3_stdio.c b/ext/misc/sqlite3_stdio.c
index 46f12dff36..5bb26084c2 100644
--- a/ext/misc/sqlite3_stdio.c
+++ b/ext/misc/sqlite3_stdio.c
@@ -31,27 +31,21 @@
#include
/*
-** If the SQLITE_U8TEXT_ONLY option is defined, then only use
-** _O_U8TEXT, _O_WTEXT, and similar together with the UTF-16
-** interfaces to the Windows CRT. The use of ANSI-only routines
-** like fputs() and ANSI modes like _O_TEXT and _O_BINARY is
-** avoided.
+** If the SQLITE_U8TEXT_ONLY option is defined, then use O_U8TEXT
+** when appropriate on all output. (Sometimes use O_BINARY when
+** rendering ASCII text in cases where NL-to-CRLF expansion would
+** not be correct.)
**
-** The downside of using SQLITE_U8TEXT_ONLY is that it becomes
-** impossible to output a bare newline character (0x0a) - that is,
-** a newline that is not preceded by a carriage return (0x0d).
-** And without that capability, sometimes the output will be slightly
-** incorrect, as extra 0x0d characters will have been inserted where
-** they do not belong.
+** If the SQLITE_U8TEXT_STDIO option is defined, then use O_U8TEXT
+** when appropriate when writing to stdout or stderr. Use O_BINARY
+** or O_TEXT (depending on things like the .mode and the .crlf setting
+** in the CLI, or other context clues in other applications) for all
+** other output channels.
**
-** The SQLITE_U8TEXT_STDIO compile-time option is a compromise.
-** It always enables _O_WTEXT or similar for stdin, stdout, stderr,
-** but allows other streams to be _O_TEXT and/or O_BINARY. The
-** SQLITE_U8TEXT_STDIO option has the same downside as SQLITE_U8TEXT_ONLY
-** in that stray 0x0d characters might appear where they ought not, but
-** at least with this option those characters only appear on standard
-** I/O streams, and not on new streams that might be created by the
-** application using sqlite3_fopen() or sqlite3_popen().
+** The default behavior, if neither of the above is defined is to
+** use O_U8TEXT when writing to the Windows console (or anything
+** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
+** for all other output channels.
*/
#if defined(SQLITE_U8TEXT_ONLY)
# define UseWtextForOutput(fd) 1
@@ -67,6 +61,31 @@
# define IsConsole(fd) 1
#endif
+/*
+** Global variables determine if simulated O_BINARY mode is to be
+** used for stdout or other, respectively. Simulated O_BINARY mode
+** means the mode is usually O_BINARY, but switches to O_U8TEXT for
+** unicode characters U+0080 or greater (any character that has a
+** multi-byte representation in UTF-8). This is the only way we
+** have found to render Unicode characters on a Windows console while
+** at the same time avoiding undesirable \n to \r\n translation.
+*/
+static int simBinaryStdout = 0;
+static int simBinaryOther = 0;
+
+
+/*
+** Determine if simulated binary mode should be used for output to fd
+*/
+static int UseBinaryWText(FILE *fd){
+ if( fd==stdout || fd==stderr ){
+ return simBinaryStdout;
+ }else{
+ return simBinaryOther;
+ }
+}
+
+
/*
** Work-alike for the fopen() routine from the standard C library.
*/
@@ -88,6 +107,7 @@ FILE *sqlite3_fopen(const char *zFilename, const char *zMode){
}
free(b1);
free(b2);
+ simBinaryOther = 0;
return fp;
}
@@ -143,13 +163,53 @@ char *sqlite3_fgets(char *buf, int sz, FILE *in){
}
}
+/*
+** Send ASCII text as O_BINARY. But for Unicode characters U+0080 and
+** greater, switch to O_U8TEXT.
+*/
+static void piecemealOutput(wchar_t *b1, int sz, FILE *out){
+ int i;
+ wchar_t c;
+ while( sz>0 ){
+ for(i=0; i=0x80; i++){}
+ if( i>0 ){
+ c = b1[i];
+ b1[i] = 0;
+ fflush(out);
+ _setmode(_fileno(out), _O_U8TEXT);
+ fputws(b1, out);
+ fflush(out);
+ b1 += i;
+ b1[0] = c;
+ sz -= i;
+ }else{
+ fflush(out);
+ _setmode(_fileno(out), _O_TEXT);
+ _setmode(_fileno(out), _O_BINARY);
+ fwrite(&b1[0], 1, 1, out);
+ for(i=1; iaCol[ii].iBind
+ "%z%sescape_crlf(quote(?%d))", zBind, zSqlSep, pTab->aCol[ii].iBind
);
zSqlSep = "||', '||";
}else{
diff --git a/main.mk b/main.mk
index f0f41736d1..3c2c379a39 100644
--- a/main.mk
+++ b/main.mk
@@ -569,7 +569,7 @@ dbhash$(EXE): $(TOP)/tool/dbhash.c sqlite3.c sqlite3.h
$(TOP)/tool/dbhash.c sqlite3.c $(TLIBS) $(THREADLIB)
RSYNC_SRC = \
- $(TOP)/tool/sqlite3-rsync.c \
+ $(TOP)/tool/sqlite3_rsync.c \
sqlite3.c
RSYNC_OPT = \
@@ -578,7 +578,7 @@ RSYNC_OPT = \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_OMIT_DEPRECATED
-sqlite3-rsync$(EXE): $(RSYNC_SRC)
+sqlite3_rsync$(EXE): $(RSYNC_SRC)
$(TCC) -o $@ $(RSYNC_OPT) $(RSYNC_SRC) $(TLIBS)
scrub$(EXE): $(TOP)/ext/misc/scrub.c sqlite3.o
@@ -1159,7 +1159,7 @@ clean:
rm -f showjournal$(TEXE) showstat4$(TEXE) showwal$(TEXE) speedtest1$(TEXE)
rm -f wordcount$(TEXE) changeset$(TEXE) version-info$(TEXE)
rm -f *.dll *.lib *.exp *.def *.pc *.vsix
- rm -f sqlite3_analyzer$(TEXE) sqlite3-rsync$(TEXE)
+ rm -f sqlite3_analyzer$(TEXE) sqlite3_rsync$(TEXE)
rm -f mptester$(TEXE) rbu$(TEXE) srcck1$(TEXE)
rm -f fuzzershell$(TEXE) fuzzcheck$(TEXE) sqldiff$(TEXE) dbhash$(TEXE)
rm -f threadtest5$(TEXE)
diff --git a/manifest b/manifest
index 33eeb2bba9..9848bfb321 100644
--- a/manifest
+++ b/manifest
@@ -1,11 +1,11 @@
-C Add\ssqlite3rc.h\sbuild.
-D 2024-10-09T13:26:01.411
+C Merge\strunk\sinto\sthis\sbranch.
+D 2024-10-16T13:02:07.918
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F Makefile.in e09c278841effbb93503fe3846337350bebc215f06c63f2c998e8cce7b109e8b
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
-F Makefile.msc 9c6d80d9d103fa42e931f4c464884a5e577fae8563acc7589bff4e43fbe8f864
+F Makefile.msc 58b69eda1faad5d475092b8aeffab9156ee4901a82db089b166607f2ec907ee4
F README.md c3c0f19532ce28f6297a71870f3c7b424729f0e6d9ab889616d3587dd2332159
F VERSION 0db40f92c04378404eb45bff93e9e42c148c7e54fd3da99469ed21e22411f5a6
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@@ -18,20 +18,20 @@ F auto.def 42b2334f320fafcebb09673453fc9df470839e136d84ddeb74699af16b08b056
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
F autoconf/Makefile.am adedc1324b6a87fdd1265ddd336d2fb7d4f36a0e77b86ea553ae7cc4ea239347
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
-F autoconf/Makefile.msc 2aced6442addab13ed115696eba28d9ed29caa3dd604a31392c2c7a5da301492
+F autoconf/Makefile.msc 0a1fdef1f2c618815cf7c82c817a7369c1e07b3cfed490803db16fb43326d506
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
F autoconf/README.txt 42cfd21d0b19dc7d5d85fb5c405c5f3c6a4c923021c39128f6ba685355d8fd56
F autoconf/configure.ac ec7fa914c5e74ff212fe879f9bb6918e1234497e05facfb641f30c4d5893b277
F autoconf/tea/Makefile.in 106a96f2f745d41a0f6193f1de98d7355830b65d45032c18cd7c90295ec24196
-F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
+F autoconf/tea/README.txt 94fa2472d3ee4139ab24b364d99a70445d0a25531dac3ce03af2055d581f76b4 w autoconf/tea/README
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
F autoconf/tea/configure.ac 0deb5d6c49c8119f75f436488219fc043127d72057af5dfba2c9ce096a5734bc
F autoconf/tea/doc/sqlite3.n e1fe45d4f5286ee3d0ccc877aca2a0def488e9bb
F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523
-F autoconf/tea/pkgIndex.tcl.in b9eb6dd37f64e08e637d576b3c83259814b9cddd78bec4af2e5abfc6c5c750ce
+F autoconf/tea/pkgIndex.tcl.in 55aec3c6d7e9a1de9b8d2fdc9c27fd055da3ac3a51b572195e2ae7300bcfd3a2
F autoconf/tea/tclconfig/install-sh bdd5e293591621ae60d9824d86a4b1c5f22c3d00
F autoconf/tea/tclconfig/tcl.m4 c6e5f2fc7178f40d087403daa044ef3b86a8e30793f3b121bdcbdf152c6a776a
-F autoconf/tea/win/makefile.vc 2c478a9a962e48b2bf9062734e04d7c63c556e217095419173f9d7938d7d78f7
+F autoconf/tea/win/makefile.vc 9b33af4214a5c8360549b96380f55ece1a2df76a51ab4c726296e5c43d8a2227
F autoconf/tea/win/nmakehlp.c b01f822eabbe1ed2b64e70882d97d48402b42d2689a1ea00342d1a1a7eaa19cb
F autoconf/tea/win/rules.vc 7b3bb2ef32ade0f3f14d951231811678722725e3bca240dd9727ae0dfe10f6a5
F autosetup/LICENSE 41a26aebdd2cd185d1e2b210f71b7ce234496979f6b35aef2cbf6b80cbed4ce4
@@ -55,10 +55,11 @@ F autosetup/tmake.tcl a275793ec1b6f8708179af0acef1f6f10d46c2920739743f7a8720c6d7
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x
-F configure.ac 934d33880d4c7dbff05c2ebaa3820e344e1321d5fff6d6393963e50c3a613e40
+F configure.ac 6bb3470ed862e753a5e6754cc0eea16e1de7e8c6aac458de1ee7706a8da26f19
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
-F doc/compile-for-windows.md 4d4bfafda42a7a33f166d23aed4db1bb4ea1e5751595a5cced2bad349fd14652
+F doc/compile-for-unix.md 90f17554cc3d19b2dae8142b5aeda1a8890692d5f2e091ed4a6f9b46b8f10f62
+F doc/compile-for-windows.md a9ab9f6c49763d63d177a386a9e53ee670101f80e8bcb73cafca438156229076
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/jsonb.md 5fab4b8613aa9153fbeb6259297bd4697988af8b3d23900deba588fa7841456b
F doc/lemon.html 8b266ff711d2ec7f867c3dca37634963f48a630329908cc282beebfa8c708706
@@ -76,8 +77,8 @@ F ext/consio/console_io.c d2b74afae8d301de2e8447b1045fcd33eb59df13bf581d906d99c7
F ext/consio/console_io.h b5ebe34aa15b357621ebbea3d3f2e2b24750d4280b5802516409e23947fd9ee5
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
-F ext/expert/expert1.test b10f9e20f64102a015c0fcf54cb7b7680266b397e91d93cdad45f57857cdfba6
-F ext/expert/sqlite3expert.c df417a6d91873a74d35daa9259171647c23c6601415e938e8a71702703f3d677
+F ext/expert/expert1.test 1fa0201d8610883c32214b1d83e3a6cc582694ac1067be8319b280235145a555
+F ext/expert/sqlite3expert.c b7cbbd7cc109c66ebdf6091467d790abb9d7c25ae3b822bb76388509641d37de
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
F ext/expert/test_expert.c b767b2039a0df707eb3147e86bcf68b252d8455d9a41774b1a836cd052ceca70
F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c7cc3bf59ee
@@ -124,7 +125,7 @@ F ext/fts5/fts5_storage.c 337b05e4c66fc822d031e264d65bde807ec2fab08665ca2cc8aaf9
F ext/fts5/fts5_tcl.c 4db9258a7882c5eac0da4433042132aaf15b87dd1e1636c7a6ca203abd2c8bfe
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
-F ext/fts5/fts5_tokenize.c ae9c4fa93174ef06ffc138bd4280a1c37f7e13624d3d2706aad4b80573f23c41
+F ext/fts5/fts5_tokenize.c 033e2e43b8e852c0ef6cecc611266d61e2346e52ec7dcfb76a428fe56a07efa9
F ext/fts5/fts5_unicode2.c 6f9b0fb79a8facaed76628ffd4eb9c16d7f2b84b52872784f617cf3422a9b043
F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d09885d1dadf80
F ext/fts5/fts5_vocab.c e4830b00809e5da53bc10f93adc59e321407b0f801c7f4167c0e47f5552267e0
@@ -440,13 +441,13 @@ F ext/misc/regexp.c 4bdd0045912f81c84908bd535ec5ad3b1c8540b4287c70ab840709636240
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
-F ext/misc/series.c a6089b5e8e3002bd1e5d9877cee6aead0b9a6426e406c09a399817db9e9ae823
+F ext/misc/series.c 596afbfbbc81ccf4ea6da11f016f7eed630ed195b5e9d548117e19f06d63f641
F ext/misc/sha1.c cb5002148c2661b5946f34561701e9105e9d339b713ec8ac057fd888b196dcb9
F ext/misc/shathree.c 1821d90a0040c9accdbe3e3527d378d30569475d758aa70f6848924c0b430e8c
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F ext/misc/spellfix.c bcc42ef3fd29429bc01a83e751332b8d4690e65d45008449bdffe7656371487f
F ext/misc/sqlar.c a6175790482328171da47095f87608b48a476d4fac78d8a9ff18b03a2454f634
-F ext/misc/sqlite3_stdio.c f110e6f2dc97c67e89f941f82af7dbd221193fa44d1e3ef38a691454a2cbccda
+F ext/misc/sqlite3_stdio.c 73192f75e1e89722fbdf209056a562ca2a35df3c9e998f9270331e03cb621e7a
F ext/misc/sqlite3_stdio.h f05eaf5e0258f0573910324a789a9586fc360a57678c57a6d63cfaa2245b6176
F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321
F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc
@@ -527,7 +528,7 @@ F ext/recover/recoverpgsz.test 88766fcb810e52ee05335c456d4e5fb06d02b73d3ccb48c52
F ext/recover/recoverrowid.test f948bf4024a5f41b0e21b8af80c60564c5b5d78c05a8d64fc00787715ff9f45f
F ext/recover/recoverslowidx.test 5205a9742dd9490ee99950dabb622307355ef1662dea6a3a21030057bfd81411
F ext/recover/recoversql.test e66d01f95302a223bcd3fd42b5ee58dc2b53d70afa90b0d00e41e4b8eab20486
-F ext/recover/sqlite3recover.c 2dcf6b56c5e0e2b43fc4c6115b689ab194c374ced7f7f8380ad9a24d8ef24ac9
+F ext/recover/sqlite3recover.c e822ecbb05a04a5c85d1309765fcd6cf392d100d02d2227cd7720c9d6921a17a
F ext/recover/sqlite3recover.h 011c799f02deb70ab685916f6f538e6bb32c4e0025e79bfd0e24ff9c74820959
F ext/recover/test_recover.c 072260d7452a3b81aba995b2b3269e7ec2aa7f06725544ba4c25b1b0a1dbc61a
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
@@ -708,7 +709,7 @@ F ext/wasm/wasmfs.make bc8bb227f35d5bd3863a7bd2233437c37472a0d81585979f058f9b9b5
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
-F main.mk 0a55ebec3508ca1bdb593d86f3aa19d7fa42a2ddd3220703e6dc0a65f1338a43
+F main.mk c6501abe2d915ed1a2ec3d074e652c096177f93c50ac91f815c831e3417f9019
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
@@ -738,10 +739,10 @@ F src/date.c 89ce1ff20512a7fa5070ba6e7dd5c171148ca7d580955795bf97c79c2456144a
F src/dbpage.c db1be8adaf1f839ad733c08baeac5c22aa912f7b535865c0c061382602081360
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
-F src/expr.c 6d5f2c38fe3ec06a7eac599dac822788b36064124e20112a844e9cd5156cb239
+F src/expr.c a9d9f5fdfbdd3b2c94d7af1b11f181464b8a641736cf32cb92fa3c5e7ecb30df
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
-F src/func.c df400a1d3f4625997d4dd8a81951c303e066277c29b861d37e03cd152d7858dd
+F src/func.c 1d093b93b8f097665721e59a1c404d7db4dc591e1a777a7a1022dfbda21e108b
F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
@@ -772,7 +773,7 @@ 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 779e83666ecd535f6725497ba6da069c1d15138ff6a4ee123edad1ae0cdfbe83
+F src/os_unix.c 14d0f80e4779f5f76bcc71e7af97e3efe318fa3d0b22335623c59fab7d39302b
F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c b08600ebf0db90b6d1e9b8b6577c6fa3877cbe1a100bd0b2899e4c6e9adad4b3
@@ -781,23 +782,23 @@ F src/parse.y a7a8d42eeff01d267444ddb476029b0b1726fb70ae3d77984140f17ad02e2d61
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 49516ad7718a3626f28f710fa7448ef1fce3c07fd169acbb4817341950264319
-F src/pragma.c 52bfbf6dfd668b69b5eb9bd1186e3a67367c8453807150d6e75239229924f684
+F src/pragma.c cd613126f7cdd0c2ded4648c3c7b7b0239e678d7f3489e88c4b6d6858372fd07
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c 3ba0ad907b7773ed642f66cea8a2c9c8edc18841aa1050b6218dbb3479e86225
F src/printf.c 6a87534ebfb9e5346011191b1f3a7ebc457f5938c7e4feeea478ecf53f6a41b2
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
-F src/resolve.c 9750a281f7ba073b4e6da2be1a6c4071f5d841a7746c5fb3f70d6d793b6675ea
+F src/resolve.c c8a5372b97b2a2e972a280676f06ddb5b74e885d3b1f5ce383f839907b57ef68
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 4b14337a2742f0c0beeba490e9a05507e9b4b12184b9cd12773501d08d48e3fe
-F src/shell.c.in 981efe98f98a983c1d0193d18528eb2d765207c0c82b67b610be60f17995a43e
-F src/sqlite.h.in 1def838497ad53c81486649ce79821925d1ac20a9843af317a344d507efe116e
+F src/shell.c.in 0662f9bcf0725461778d0254a06150e5d61c08c5a87a7281ccdf45552050c79d
+F src/sqlite.h.in add9e064d6b42af8f1a4a3322bddadec76696e520aedebd83e0d3211c15ac999
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h 989dca8b25ca11f5c52e5a457cc500042c43b0b3e5fea9a12d9020d0350722cd
+F src/sqliteInt.h ad02397dc4d22b77f9a331412d46e4c1e49459dd386fba8373fa148998e1e7d0
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c c6888598f08dee3d9112a38ef42c8f5c89ca7f3190f4694744d0b84250f4bf8c
+F src/tclsqlite.c e2b752dd08034c834e3639afa3300940d6e847fcd94207e1f2f1b83ce08b87be
F src/tclsqlite.h c6af51f31a2b2172d674608763a4b98fdf5cd587e4025053e546fb8077757262
F src/test1.c 8bf8b74145b768f42386787f93f6d6dad7bc400a4ee2d50e4ad5a06a20a97ef1
F src/test2.c 7ebc518e6735939d8979273a6f7b1d9b5702babf059f6ad62499f7f60a9eb9a3
@@ -855,7 +856,7 @@ F src/treeview.c 88aa39b754f5ef7214385c1bbbdd2f3dc20efafeed0cf590e8d1199b9c6e44a
F src/trigger.c 0bb986a5b96047fd597c6aac28588853df56064e576e6b81ba777ef2ccaac461
F src/update.c 0e01aa6a3edf9ec112b33eb714b9016a81241497b1fb7c3e74332f4f71756508
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
-F src/utf.c 7bc550af6f3ddd5f5dc82d092c41f728acb760c92e0b47f391963b01ae52569b
+F src/utf.c 8b29d9a5956569ea2700f869669b8ef67a9662ee5e724ff77ab3c387e27094ba
F src/util.c 4d57ae861d0e234019be9596818228d7715e44e6efaccb612cf4498bedc2e023
F src/vacuum.c b763b6457bd058d2072ef9364832351fd8d11e8abf70cbb349657360f7d55c40
F src/vdbe.c be5f58bc29f60252e041a618eae59e8d57d460ba136c5403cf0abf955560c457
@@ -873,10 +874,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c a0d42bfdef935e1389737152394d08e59e7c48697f40a9fc2e0552cb19dc731f
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
-F src/where.c 461d41017d900d4248a268df96d2d30506c4dcc2257f4167c4f46072003ce2cf
+F src/where.c 12fe24880901997372b88fd7ca9a21457404ad35201712c02cc57978578abb10
F src/whereInt.h a5d079c346a658b7a6e9e47bb943d021e02fa1e6aed3b964ca112112a4892192
F src/wherecode.c 5172d647798134e7c92536ddffe7e530c393d79b5dedd648b88faf2646c65baf
-F src/whereexpr.c 44f41ae554c7572e1de1485b3169b233ee04d464b2ee5881687ede3bf07cacfa
+F src/whereexpr.c 0f93a29cabd3a338d09a1f5c6770620a1ac51ec1157f3229502a7e7767c60b6f
F src/window.c 499d48f315a09242dc68f2fac635ed27dcf6bbb0d9ab9084857898c64489e975
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@@ -1061,7 +1062,7 @@ F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
F test/corruptK.test ac13504593d89d69690d45479547616ed12644d42b5cb7eeb2e759a76fc23dcb
F test/corruptL.test 652fc8ac0763a6fd3eb28b951d481924167b2d9936083bcc68253b2274a0c8fe
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
-F test/corruptN.test 7c099d153a554001b4fb829c799b01f2ea6276cbc32479131e0db0da4efd9cc4
+F test/corruptN.test 40bc47aee4af9aadff902be43f14d69dc17b3731448dad6c7cc722da913f1455
F test/cost.test cc434a026b1e9d0d98137a147e24e5daf1b1ad09e9ff7da63b34c83ddd136d92
F test/count.test cd4bd531066e8d77ef8fe1e3fc8253d042072e117ccab214b290cf83f1602249
F test/countofview.test 4088e461a10ee33e69803c177a69aa1d7bba81a9ffc2df66d76465a22ca7fdfc
@@ -1343,6 +1344,7 @@ F test/indexA.test 11d84f6995e6e5b9d8315953fb1b6d29772ee7c7803ee9112715e7e4dd3e4
F test/indexedby.test f21eca4f7a6ffe14c8500a7ad6cd53166666c99e5ccd311842a28bc94a195fe0
F test/indexexpr1.test 24fa85a12da384dd1d56f7b24e593c51a8a54b4c5e2e8bbb9e5fdf1099427faf
F test/indexexpr2.test 1c382e81ef996d8ae8b834a74f2a9013dddf59214c32201d7c8a656d739f999a
+F test/indexexpr3.test 9d893bf440937ebcc1e59c7c9c1505c40c918346a3ddde76a69078f3c733c45d
F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test 4e3f0de67aac3c5be1f4aaedbcea11638f1b5cdc9a3115be14d19aa9db7623c6
@@ -1409,7 +1411,7 @@ F test/kvtest.c 6e0228409ea7ca0497dad503fbd109badb5e59545d131014b6aaac68b56f484a
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/lemon-test01.y 70110eff607ab137ccc851edb2bc7e14a6d4f246b5d2d25f82a60b69d87a9ff2
-F test/like.test 242ee7f5d08a031144c0daf63bbd7e7710c847ccf387a83347e0b61b3aa69526
+F test/like.test b3ea2ba3558199aa8f25a42ddeb54772e234fab50868c9f066047acdbda8fc58
F test/like2.test d3be15fefee3e02fc88942a9b98f26c5339bbdef7783c90023c092c4955fe3d3
F test/like3.test a76e5938fadbe6d32807284c796bafd869974a961057bc5fc5a28e06de98745c
F test/limit.test 350f5d03c29e7dff9a2cde016f84f8d368d40bcd02fa2b2a52fa10c4bf3cbfaf
@@ -1423,7 +1425,7 @@ F test/lock.test be4fe08118fb988fed741f429b7dd5d65e1c90db
F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff
F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00
F test/lock4.test 27143363eda1622f03c133efc8db808fc331afd973486cb571ea71cd717d37b8
-F test/lock5.test 24693e40a805f71d80836f720d1f2034684a39b64f1e1990989002c7968c11ee
+F test/lock5.test 583cae05992af0f66607286917f7d5f8aed3b6053c52df5994efb98f2a8fdbaf
F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5
F test/lock7.test 49f1eaff1cdc491cc5dee3669f3c671d9f172431
F test/lock_common.tcl 2f3f7f2e9637f93ccf609df48ef5b27a50278b6b1cd752b445d52262e5841413
@@ -1647,7 +1649,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test b02d628494fa284cdb2b7b2fecdadea96913796afd623f340a79d68f055dcb7e
+F test/shell1.test 5d84e415adf7cc4edd5913c4f23c761104ff135b9c190fcf7b430a4cbca6cb65
F test/shell2.test 01a01f76ed98088ce598794fbf5b359e148271541a8ddbf79d21cc353cc67a24
F test/shell3.test db1953a8e59d08e9240b7cc5948878e184f7eb2623591587f8fd1f1a5bd536d8
F test/shell4.test 522fdc628c55eff697b061504fb0a9e4e6dfc5d9087a633ab0f3dd11bcc4f807
@@ -1746,7 +1748,7 @@ F test/thread005.test 50d10b5684399676174bd96c94ad4250b1a2c8b6
F test/thread1.test df115faa10a4ba1d456e9d4d9ec165016903eae4
F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46
F test/thread3.test a12656a56cdf67acb6a2ff7638826c6d6a645f79909d86df521045ad31cf547d
-F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd
+F test/thread_common.tcl b3b19a769fe30ef5537cdfa60acd49b78f771301627720d1add2d3bac77d9039
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
F test/threadtest2.c a70a8e94bef23339d34226eb9521015ef99f4df8
F test/threadtest3.c 655bff6c0895ec03f014126aa65e808fac9aae8c5a7a7da58a510cbe8b43b781
@@ -2168,7 +2170,7 @@ F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6
F tool/mksqlite3c.tcl c6acfdf4e4ef93478ff3ce3cd593e17abb03f446036ce710c3156bcfa18665e0
F tool/mksqlite3h.tcl d391cff7cad0a372ee1406faee9ccc7dad9cb80a0c95cae0f73d10dd26e06762
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
-F tool/mktoolzip.tcl c7a9b685f5131d755e7d941cec50cee7f34178b9e34c9a89811eeb08617f8423
+F tool/mktoolzip.tcl 1b3383c6cd1ca3e1bfdf157d1383f29d6264b9600c381e682789c83617dc1014
F tool/mkvsix.tcl 67b40996a50f985a573278eea32fc5a5eb6110bdf14d33f1d8086e48c69e540a
F tool/offsets.c 8ed2b344d33f06e71366a9b93ccedaa38c096cc1dbd4c3c26ad08c6115285845
F tool/omittest-msvc.tcl d6b8f501ac1d7798c4126065030f89812379012cad98a1735d6d7221492abc08
@@ -2196,11 +2198,11 @@ F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d40618 x
F tool/split-sqlite3c.tcl 5aa60643afca558bc732b1444ae81a522326f91e1dc5665b369c54f09e20de60
F tool/sqldiff.c 2a0987d183027c795ced13d6749061c1d2f38e24eddb428f56fa64c3a8f51e4b
-F tool/sqlite3-rsync.c 2f06f02ee3a28f847b3fb8c0f32e3b3296571e0f8027939b95d32df5edfe1dd9
F tool/sqlite3_analyzer.c.in 348ba349bbdc93c9866439f9f935d7284866a2a4e6898bc906ae1204ade56918
+F tool/sqlite3_rsync.c 2a2b79a0463d400696aa9429be5c0ddec6b1f7ceefa5fed7acfdc859a435221f w tool/sqlite3-rsync.c
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
-F tool/src-verify.c 41c586dee84d0b190ad13e0282ed83d4a65ec9fefde9adf4943efdf6558eea7f
+F tool/src-verify.c d00f93263aa2fa6ba0cba0106d95458e6effb94fdb5fc634f56834f90c05bbb4
F tool/srcck1.c 371de5363b70154012955544f86fdee8f6e5326f
F tool/srctree-check.tcl c15f860a3c97d5f7b4c14b60392d9466af29dd006c4ef18127f502641e2977a8
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
@@ -2236,8 +2238,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 292ad7d519d39f16f130d082d3f134deadd5409d56ffb5340064a1996f4b4d57
-R b2998251d1a1c77a7b55806ea3c31919
+P 8d5f99f7e3f0ff9eaea1cb550369864e49a0fe0b00a53b1eba6ed099b61d8d24 86e794cbaa5ae600635c933b46298a39f2465daf4c5cd1570f2a03e19ac08d9d
+R 0f51619208545f999beb801583f35ef3
U stephan
-Z 2c5ae792bbaf5eea557dff2e61da4cd7
+Z b40f13e331b5567249a3bbe5622b7fa3
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index d3ad4492e4..6dac849c2d 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-8d5f99f7e3f0ff9eaea1cb550369864e49a0fe0b00a53b1eba6ed099b61d8d24
+9c3bb3dc4f5b5cd7db6cd50d22dbe8f933cccf5f2fd253467bb50f36b3207a93
diff --git a/src/expr.c b/src/expr.c
index 1b18828dd6..cc915987dd 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -4554,6 +4554,59 @@ static int exprCodeInlineFunction(
return target;
}
+/*
+** Expression Node callback for sqlite3ExprCanReturnSubtype().
+**
+** Only a function call is able to return a subtype. So if the node
+** is not a function call, return WRC_Prune immediately.
+**
+** A function call is able to return a subtype if it has the
+** SQLITE_RESULT_SUBTYPE property.
+**
+** Assume that every function is able to pass-through a subtype from
+** one of its argument (using sqlite3_result_value()). Most functions
+** are not this way, but we don't have a mechanism to distinguish those
+** that are from those that are not, so assume they all work this way.
+** That means that if one of its arguments is another function and that
+** other function is able to return a subtype, then this function is
+** able to return a subtype.
+*/
+static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
+ int n;
+ FuncDef *pDef;
+ sqlite3 *db;
+ if( pExpr->op!=TK_FUNCTION ){
+ return WRC_Prune;
+ }
+ assert( ExprUseXList(pExpr) );
+ db = pWalker->pParse->db;
+ n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0;
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
+ if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
+ pWalker->eCode = 1;
+ return WRC_Prune;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Return TRUE if expression pExpr is able to return a subtype.
+**
+** A TRUE return does not guarantee that a subtype will be returned.
+** It only indicates that a subtype return is possible. False positives
+** are acceptable as they only disable an optimization. False negatives,
+** on the other hand, can lead to incorrect answers.
+*/
+static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.pParse = pParse;
+ w.xExprCallback = exprNodeCanReturnSubtype;
+ sqlite3WalkExpr(&w, pExpr);
+ return w.eCode;
+}
+
+
/*
** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
** If it is, then resolve the expression by reading from the index and
@@ -4586,6 +4639,17 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
continue;
}
+
+ /* Functions that might set a subtype should not be replaced by the
+ ** value taken from an expression index if they are themselves an
+ ** argument to another scalar function or aggregate.
+ ** https://sqlite.org/forum/forumpost/68d284c86b082c3e */
+ if( ExprHasProperty(pExpr, EP_SubtArg)
+ && sqlite3ExprCanReturnSubtype(pParse, pExpr)
+ ){
+ continue;
+ }
+
v = pParse->pVdbe;
assert( v!=0 );
if( p->bMaybeNullRow ){
diff --git a/src/func.c b/src/func.c
index a634a7fbea..2de16b8aa9 100644
--- a/src/func.c
+++ b/src/func.c
@@ -2535,7 +2535,13 @@ static void signFunc(
** Implementation of fpdecode(x,y,z) function.
**
** x is a real number that is to be decoded. y is the precision.
-** z is the maximum real precision.
+** z is the maximum real precision. Return a string that shows the
+** results of the sqlite3FpDecode() function.
+**
+** Used for testing and debugging only, specifically testing and debugging
+** of the sqlite3FpDecode() function. This SQL function does not appear
+** in production builds. This function is not an API and is subject to
+** modification or removal in future versions of SQLite.
*/
static void fpdecodeFunc(
sqlite3_context *context,
@@ -2562,6 +2568,82 @@ static void fpdecodeFunc(
}
#endif /* SQLITE_DEBUG */
+#ifdef SQLITE_DEBUG
+/*
+** Implementation of parseuri(uri,flags) function.
+**
+** Required Arguments:
+** "uri" The URI to parse.
+** "flags" Bitmask of flags, as if to sqlite3_open_v2().
+**
+** Additional arguments beyond the first two make calls to
+** sqlite3_uri_key() for integers and sqlite3_uri_parameter for
+** anything else.
+**
+** The result is a string showing the results of calling sqlite3ParseUri().
+**
+** Used for testing and debugging only, specifically testing and debugging
+** of the sqlite3ParseUri() function. This SQL function does not appear
+** in production builds. This function is not an API and is subject to
+** modification or removal in future versions of SQLite.
+*/
+static void parseuriFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_str *pResult;
+ const char *zVfs;
+ const char *zUri;
+ unsigned int flgs;
+ int rc;
+ sqlite3_vfs *pVfs = 0;
+ char *zFile = 0;
+ char *zErr = 0;
+
+ if( argc<2 ) return;
+ pVfs = sqlite3_vfs_find(0);
+ assert( pVfs );
+ zVfs = pVfs->zName;
+ zUri = (const char*)sqlite3_value_text(argv[0]);
+ if( zUri==0 ) return;
+ flgs = (unsigned int)sqlite3_value_int(argv[1]);
+ rc = sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr);
+ pResult = sqlite3_str_new(0);
+ if( pResult ){
+ int i;
+ sqlite3_str_appendf(pResult, "rc=%d", rc);
+ sqlite3_str_appendf(pResult, ", flags=0x%x", flgs);
+ sqlite3_str_appendf(pResult, ", vfs=%Q", pVfs ? pVfs->zName: 0);
+ sqlite3_str_appendf(pResult, ", err=%Q", zErr);
+ sqlite3_str_appendf(pResult, ", file=%Q", zFile);
+ if( zFile ){
+ const char *z = zFile;
+ z += sqlite3Strlen30(z)+1;
+ while( z[0] ){
+ sqlite3_str_appendf(pResult, ", %Q", z);
+ z += sqlite3Strlen30(z)+1;
+ }
+ for(i=2; ieFileLock<=SHARED_LOCK );
- /* Check if a thread in this process holds such a lock */
- if( pFile->eFileLock>SHARED_LOCK ){
- reserved = 1;
- }
+ /* The flock VFS only ever takes exclusive locks (see function flockLock).
+ ** Therefore, if this connection is holding any lock at all, no other
+ ** connection may be holding a RESERVED lock. So set *pResOut to 0
+ ** in this case.
+ **
+ ** Or, this connection may be holding no lock. In that case, set *pResOut to
+ ** 0 as well. The caller will then attempt to take an EXCLUSIVE lock on the
+ ** db in order to roll the hot journal back. If there is another connection
+ ** holding a lock, that attempt will fail and an SQLITE_BUSY returned to
+ ** the user. With other VFS, we try to avoid this, in order to allow a reader
+ ** to proceed while a writer is preparing its transaction. But that won't
+ ** work with the flock VFS - as it always takes EXCLUSIVE locks - so it is
+ ** not a problem in this case. */
+ *pResOut = 0;
- /* Otherwise see if some other process holds it. */
- if( !reserved ){
- /* attempt to get the lock */
- int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
- if( !lrc ){
- /* got the lock, unlock it */
- lrc = robust_flock(pFile->h, LOCK_UN);
- if ( lrc ) {
- int tErrno = errno;
- /* unlock failed with an error */
- lrc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
- } else {
- int tErrno = errno;
- reserved = 1;
- /* someone else might have it reserved */
- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if( IS_LOCK_ERROR(lrc) ){
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
- }
- }
- OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
-
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if( (rc & 0xff) == SQLITE_IOERR ){
- rc = SQLITE_OK;
- reserved=1;
- }
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- *pResOut = reserved;
- return rc;
+ return SQLITE_OK;
}
/*
diff --git a/src/pragma.c b/src/pragma.c
index a8045aab1e..07139015f9 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -1761,6 +1761,7 @@ void sqlite3Pragma(
/* Make sure sufficient number of registers have been allocated */
sqlite3TouchRegister(pParse, 8+cnt);
+ sqlite3VdbeAddOp3(v, OP_Null, 0, 8, 8+cnt);
sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
diff --git a/src/resolve.c b/src/resolve.c
index 8e8da66910..d6a5144af8 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -1183,6 +1183,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
}
#endif
+
+ /* If the function may call sqlite3_value_subtype(), then set the
+ ** EP_SubtArg flag on all of its argument expressions. This prevents
+ ** where.c from replacing the expression with a value read from an
+ ** index on the same expression, which will not have the correct
+ ** subtype. Also set the flag if the function expression itself is
+ ** an EP_SubtArg expression. In this case subtypes are required as
+ ** the function may return a value with a subtype back to its
+ ** caller using sqlite3_result_value(). */
+ if( (pDef->funcFlags & SQLITE_SUBTYPE)
+ || ExprHasProperty(pExpr, EP_SubtArg)
+ ){
+ int ii;
+ for(ii=0; iia[ii].pExpr, EP_SubtArg);
+ }
+ }
+
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
/* For the purposes of the EP_ConstFunc flag, date and time
** functions and other functions that change slowly are considered
diff --git a/src/shell.c.in b/src/shell.c.in
index 140fd0d9de..bbf08f8098 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -1448,6 +1448,7 @@ struct ShellState {
u8 bSafeMode; /* True to prohibit unsafe operations */
u8 bSafeModePersist; /* The long-term value of bSafeMode */
u8 eRestoreState; /* See comments above doAutoDetectRestore() */
+ u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */
ColModeOpts cmOpts; /* Option values affecting columnar mode output */
unsigned statsOn; /* True to display memory stats before each finalize */
unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
@@ -1628,13 +1629,7 @@ static const char *modeDescr[] = {
#define SEP_Tab "\t"
#define SEP_Space " "
#define SEP_Comma ","
-#ifdef SQLITE_U8TEXT_ONLY
- /* With the SQLITE_U8TEXT_ONLY option, the output will always be in
- ** text mode. The \r will be inserted automatically. */
-# define SEP_CrLf "\n"
-#else
-# define SEP_CrLf "\r\n"
-#endif
+#define SEP_CrLf "\r\n"
#define SEP_Unit "\x1F"
#define SEP_Record "\x1E"
@@ -1719,7 +1714,7 @@ static void editFunc(
char *zCmd = 0;
int bBin;
int rc;
- int hasCRNL = 0;
+ int hasCRLF = 0;
FILE *f = 0;
sqlite3_int64 sz;
sqlite3_int64 x;
@@ -1764,7 +1759,7 @@ static void editFunc(
}else{
const char *z = (const char*)sqlite3_value_text(argv[0]);
/* Remember whether or not the value originally contained \r\n */
- if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
+ if( z && strstr(z,"\r\n")!=0 ) hasCRLF = 1;
x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
}
fclose(f);
@@ -1809,7 +1804,7 @@ static void editFunc(
sqlite3_result_blob64(context, p, sz, sqlite3_free);
}else{
sqlite3_int64 i, j;
- if( hasCRNL ){
+ if( hasCRLF ){
/* If the original contains \r\n then do no conversions back to \n */
}else{
/* If the file did not originally contain \r\n then convert any new
@@ -1851,6 +1846,21 @@ static void outputModePop(ShellState *p){
memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
}
+/*
+** Set output mode to text or binary for Windows.
+*/
+static void setCrlfMode(ShellState *p){
+#ifdef _WIN32
+ if( p->crlfMode ){
+ sqlite3_fsetmode(p->out, _O_TEXT);
+ }else{
+ sqlite3_fsetmode(p->out, _O_BINARY);
+ }
+#else
+ UNUSED_PARAMETER(p);
+#endif
+}
+
/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
@@ -1901,9 +1911,10 @@ static const char *unused_string(
**
** See also: output_quoted_escaped_string()
*/
-static void output_quoted_string(FILE *out, const char *z){
+static void output_quoted_string(ShellState *p, const char *z){
int i;
char c;
+ FILE *out = p->out;
sqlite3_fsetmode(out, _O_BINARY);
if( z==0 ) return;
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
@@ -1929,7 +1940,7 @@ static void output_quoted_string(FILE *out, const char *z){
}
sqlite3_fputs("'", out);
}
- sqlite3_fsetmode(out, _O_TEXT);
+ setCrlfMode(p);
}
/*
@@ -1941,9 +1952,10 @@ static void output_quoted_string(FILE *out, const char *z){
** This is like output_quoted_string() but with the addition of the \r\n
** escape mechanism.
*/
-static void output_quoted_escaped_string(FILE *out, const char *z){
+static void output_quoted_escaped_string(ShellState *p, const char *z){
int i;
char c;
+ FILE *out = p->out;
sqlite3_fsetmode(out, _O_BINARY);
for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
if( c==0 ){
@@ -1996,7 +2008,7 @@ static void output_quoted_escaped_string(FILE *out, const char *z){
sqlite3_fprintf(out, ",'%s',char(10))", zNL);
}
}
- sqlite3_fsetmode(stdout, _O_TEXT);
+ setCrlfMode(p);
}
/*
@@ -2793,7 +2805,7 @@ static int shell_callback(
}
sqlite3_fputs(p->rowSeparator, p->out);
}
- sqlite3_fsetmode(p->out, _O_TEXT);
+ setCrlfMode(p);
break;
}
case MODE_Insert: {
@@ -2821,9 +2833,9 @@ static int shell_callback(
sqlite3_fputs("NULL", p->out);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(p->out, azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else{
- output_quoted_escaped_string(p->out, azArg[i]);
+ output_quoted_escaped_string(p, azArg[i]);
}
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
sqlite3_fputs(azArg[i], p->out);
@@ -2852,9 +2864,9 @@ static int shell_callback(
}else if( isNumber(azArg[i], 0) ){
sqlite3_fputs(azArg[i], p->out);
}else if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(p->out, azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else{
- output_quoted_escaped_string(p->out, azArg[i]);
+ output_quoted_escaped_string(p, azArg[i]);
}
}
sqlite3_fputs(");\n", p->out);
@@ -2907,7 +2919,7 @@ static int shell_callback(
if( p->cnt==0 && p->showHeader ){
for(i=0; i0 ) sqlite3_fputs(p->colSeparator, p->out);
- output_quoted_string(p->out, azCol[i]);
+ output_quoted_string(p, azCol[i]);
}
sqlite3_fputs(p->rowSeparator, p->out);
}
@@ -2917,7 +2929,7 @@ static int shell_callback(
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
sqlite3_fputs("NULL", p->out);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- output_quoted_string(p->out, azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
sqlite3_fputs(azArg[i], p->out);
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
@@ -2932,7 +2944,7 @@ static int shell_callback(
}else if( isNumber(azArg[i], 0) ){
sqlite3_fputs(azArg[i], p->out);
}else{
- output_quoted_string(p->out, azArg[i]);
+ output_quoted_string(p, azArg[i]);
}
}
sqlite3_fputs(p->rowSeparator, p->out);
@@ -4751,7 +4763,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
- if( !dataOnly ) sqlite3_fputs("DELETE FROM sqlite_sequence;\n", p->out);
+ /* no-op */
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
if( !dataOnly ) sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
}else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
@@ -4936,10 +4948,7 @@ static const char *(azHelp[]) = {
".clone NEWDB Clone data into NEWDB from the existing database",
#endif
".connection [close] [#] Open or close an auxiliary database connection",
-#if defined(_WIN32) && !defined(SQLITE_U8TEXT_ONLY) \
- && !defined(SQLITE_U8TEXT_STDIO)
- ".crnl on|off Translate \\n to \\r\\n. Default ON",
-#endif /* _WIN32 && U8TEXT_ONLY && U8TEXT_STDIO */
+ ".crlf ?on|off? Whether or not to use \\r\\n line endings",
".databases List names and files of attached databases",
".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
#if SQLITE_SHELL_HAVE_RECOVER
@@ -5938,7 +5947,7 @@ static void output_file_close(FILE *f){
** recognized and do the right thing. NULL is returned if the output
** filename is "off".
*/
-static FILE *output_file_open(const char *zFile, int bTextMode){
+static FILE *output_file_open(const char *zFile){
FILE *f;
if( cli_strcmp(zFile,"stdout")==0 ){
f = stdout;
@@ -5947,7 +5956,7 @@ static FILE *output_file_open(const char *zFile, int bTextMode){
}else if( cli_strcmp(zFile, "off")==0 ){
f = 0;
}else{
- f = sqlite3_fopen(zFile, bTextMode ? "w" : "wb");
+ f = sqlite3_fopen(zFile, "w");
if( f==0 ){
sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
}
@@ -6420,6 +6429,7 @@ static void output_redir(ShellState *p, FILE *pfNew){
sqlite3_fputs("Output already redirected.\n", stderr);
}else{
p->out = pfNew;
+ setCrlfMode(p);
if( p->mode==MODE_Www ){
sqlite3_fputs(
"\n"
@@ -6475,6 +6485,7 @@ static void output_reset(ShellState *p){
}
p->outfile[0] = 0;
p->out = stdout;
+ setCrlfMode(p);
}
#else
# define output_redir(SS,pfO)
@@ -8427,9 +8438,9 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- /* Undocumented. Legacy only. See "crnl" below */
+ /* Undocumented. Legacy only. See "crlf" below */
if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
- eputz("The \".binary\" command is deprecated. Use \".crnl\" instead.\n");
+ eputz("The \".binary\" command is deprecated.\n");
rc = 1;
}else
@@ -8555,22 +8566,18 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='c' && n==4 && cli_strncmp(azArg[0], "crnl", n)==0 ){
-#if !defined(_WIN32) || defined(SQLITE_U8TEXT_ONLY) \
- || defined(SQLITE_U8TEXT_STDIO)
- sqlite3_fputs("The \".crnl\" command is disable in this build.\n", p->out);
-#else
+ if( c=='c' && n==4
+ && (cli_strncmp(azArg[0], "crlf", n)==0
+ || cli_strncmp(azArg[0], "crnl",n)==0)
+ ){
if( nArg==2 ){
- if( booleanValue(azArg[1]) ){
- sqlite3_fsetmode(p->out, _O_TEXT);
- }else{
- sqlite3_fsetmode(p->out, _O_BINARY);
- }
- }else{
- eputz("Usage: .crnl on|off\n");
- rc = 1;
- }
+#ifdef _WIN32
+ p->crlfMode = booleanValue(azArg[1]);
+#else
+ p->crlfMode = 0;
#endif
+ }
+ sqlite3_fprintf(stderr, "crlf is %s\n", p->crlfMode ? "ON" : "OFF");
}else
if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
@@ -9650,7 +9657,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
output_file_close(p->pLog);
if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout";
- p->pLog = output_file_open(zFile, 0);
+ p->pLog = output_file_open(zFile);
}
}else
@@ -9905,7 +9912,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|| (c=='w' && n==3 && cli_strcmp(azArg[0],"www")==0)
){
char *zFile = 0;
- int bTxtMode = 0;
int i;
int eMode = 0;
int bOnce = 0; /* 0: .output, 1: .once, 2: .excel/.www */
@@ -9987,11 +9993,9 @@ static int do_meta_command(char *zLine, ShellState *p){
/* web-browser mode. */
newTempFile(p, "html");
if( !bPlain ) p->mode = MODE_Www;
- bTxtMode = 1;
}else{
/* text editor mode */
newTempFile(p, "txt");
- bTxtMode = 1;
}
sqlite3_free(zFile);
zFile = sqlite3_mprintf("%s", p->zTempFile);
@@ -10015,7 +10019,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
#endif
}else{
- FILE *pfFile = output_file_open(zFile, bTxtMode);
+ FILE *pfFile = output_file_open(zFile);
if( pfFile==0 ){
if( cli_strcmp(zFile,"off")!=0 ){
sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
@@ -10023,13 +10027,13 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
} else {
output_redir(p, pfFile);
+ if( zBom ) sqlite3_fputs(zBom, pfFile);
if( bPlain && eMode=='w' ){
sqlite3_fputs(
"\n\n\n",
pfFile
);
}
- if( zBom ) sqlite3_fputs(zBom, pfFile);
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
}
@@ -10226,7 +10230,6 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifdef SQLITE_OMIT_POPEN
eputz("Error: pipes are not supported in this OS\n");
rc = 1;
- p->out = stdout;
#else
p->in = sqlite3_popen(azArg[1]+1, "r");
if( p->in==0 ){
@@ -11213,7 +11216,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* Begin redirecting output to the file "testcase-out.txt" */
if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
output_reset(p);
- p->out = output_file_open("testcase-out.txt", 0);
+ p->out = output_file_open("testcase-out.txt");
if( p->out==0 ){
eputz("Error: cannot open 'testcase-out.txt'\n");
}
@@ -11717,7 +11720,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else{
output_file_close(p->traceOut);
- p->traceOut = output_file_open(z, 0);
+ p->traceOut = output_file_open(z);
}
}
if( p->traceOut==0 ){
@@ -12594,6 +12597,9 @@ static void main_init(ShellState *data) {
memset(data, 0, sizeof(*data));
data->normalMode = data->cMode = data->mode = MODE_List;
data->autoExplain = 1;
+#ifdef _WIN32
+ data->crlfMode = 1;
+#endif
data->pAuxDb = &data->aAuxDb[0];
memcpy(data->colSeparator,SEP_Column, 2);
memcpy(data->rowSeparator,SEP_Row, 2);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 5108d3c1e9..7097e6bb55 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -4232,7 +4232,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
** is the number of bytes in the input string including
** the nul-terminator.
** Note that nByte measure the length of the input in bytes, not
-** characters, even for the UTF-16 inferfaces.
+** characters, even for the UTF-16 interfaces.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -9344,6 +9344,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** APIs are not strictly speaking threadsafe. If they are invoked at the
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
+**
+** Alternatives To Using The Backup API
+**
+** Other techniques for safely creating a consistent backup of an SQLite
+** database include:
+**
+**
+** - The [VACUUM INTO] command.
+**
- The [sqlite3_rsync] utility program.
+**
*/
sqlite3_backup *sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 0e0035ce60..f88b9e67c3 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3104,7 +3104,7 @@ struct Expr {
#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
- /* 0x80000000 // Available */
+#define EP_SubtArg 0x80000000 /* Is argument to SQLITE_SUBTYPE function */
/* The EP_Propagate mask is a set of properties that automatically propagate
** upwards into parent nodes.
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 0c8888fd48..9ed6669515 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -3981,7 +3981,7 @@ static int SQLITE_TCLAPI DbMain(
** The EXTERN macros are required by TCL in order to work on windows.
*/
EXTERN int Sqlite3_Init(Tcl_Interp *interp){
- int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR;
+ int rc = Tcl_InitStubs(interp, "8.5-", 0) ? TCL_OK : TCL_ERROR;
if( rc==TCL_OK ){
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
#ifndef SQLITE_3_SUFFIX_ONLY
@@ -4037,6 +4037,20 @@ EXTERN int sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
static const char *tclsh_main_loop(void){
static const char zMainloop[] =
"if {[llength $argv]>=1} {\n"
+#ifdef WIN32
+ "set new [list]\n"
+ "foreach arg $argv {\n"
+ "if {[file exists $arg]} {\n"
+ "lappend new $arg\n"
+ "} else {\n"
+ "foreach match [lsort [glob -nocomplain $arg]] {\n"
+ "lappend new $match\n"
+ "}\n"
+ "}\n"
+ "}\n"
+ "set argv $new\n"
+ "unset new\n"
+#endif
"set argv0 [lindex $argv 0]\n"
"set argv [lrange $argv 1 end]\n"
"source $argv0\n"
diff --git a/src/utf.c b/src/utf.c
index 083ada7882..c934bb234c 100644
--- a/src/utf.c
+++ b/src/utf.c
@@ -136,7 +136,7 @@ static const unsigned char sqlite3Utf8Trans1[] = {
c = *(zIn++); \
if( c>=0xc0 ){ \
c = sqlite3Utf8Trans1[c-0xc0]; \
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
+ while( zInop!=TK_FUNCTION ){
- return WRC_Prune;
- }
- assert( ExprUseXList(pExpr) );
- db = pWalker->pParse->db;
- n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
- if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
- pWalker->eCode = 1;
- return WRC_Prune;
- }
- return WRC_Continue;
-}
-
-/*
-** Return TRUE if expression pExpr is able to return a subtype.
-**
-** A TRUE return does not guarantee that a subtype will be returned.
-** It only indicates that a subtype return is possible. False positives
-** are acceptable as they only disable an optimization. False negatives,
-** on the other hand, can lead to incorrect answers.
-*/
-static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
- Walker w;
- memset(&w, 0, sizeof(w));
- w.pParse = pParse;
- w.xExprCallback = exprNodeCanReturnSubtype;
- sqlite3WalkExpr(&w, pExpr);
- return w.eCode;
-}
-
/*
** The index pIdx is used by a query and contains one or more expressions.
** In other words pIdx is an index on an expression. iIdxCur is the cursor
@@ -6387,12 +6335,6 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
continue;
}
if( sqlite3ExprIsConstant(0,pExpr) ) continue;
- if( pExpr->op==TK_FUNCTION && sqlite3ExprCanReturnSubtype(pParse,pExpr) ){
- /* Functions that might set a subtype should not be replaced by the
- ** value taken from an expression index since the index omits the
- ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */
- continue;
- }
p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
if( p==0 ) break;
p->pIENext = pParse->pIdxEpr;
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 7ea2956a75..2b6eb6a78d 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -219,20 +219,25 @@ static int isLikeOrGlob(
z = (u8*)pRight->u.zToken;
}
if( z ){
-
- /* Count the number of prefix characters prior to the first wildcard.
- ** If the underlying database has a UTF16LE encoding, then only consider
- ** ASCII characters. Note that the encoding of z[] is UTF8 - we are
- ** dealing with only UTF8 here in this code, but the database engine
- ** itself might be processing content using a different encoding. */
+ /* Count the number of prefix bytes prior to the first wildcard.
+ ** or U+fffd character. If the underlying database has a UTF16LE
+ ** encoding, then only consider ASCII characters. Note that the
+ ** encoding of z[] is UTF8 - we are dealing with only UTF8 here in
+ ** this code, but the database engine itself might be processing
+ ** content using a different encoding. */
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
- if( c==wc[3] && z[cnt]!=0 ){
+ if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){
cnt++;
- }else if( c>=0x80 && ENC(db)==SQLITE_UTF16LE ){
- cnt--;
- break;
+ }else if( c>=0x80 ){
+ const u8 *z2 = z+cnt-1;
+ if( sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){
+ cnt--;
+ break;
+ }else{
+ cnt = (int)(z2-z);
+ }
}
}
@@ -244,7 +249,7 @@ static int isLikeOrGlob(
** range search. The third is because the caller assumes that the pattern
** consists of at least one character after all escapes have been
** removed. */
- if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
+ if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && ALWAYS(255!=(u8)z[cnt-1]) ){
Expr *pPrefix;
/* A "complete" match if the pattern ends with "*" or "%" */
diff --git a/test/corruptN.test b/test/corruptN.test
index 376325f5c5..8108609c09 100644
--- a/test/corruptN.test
+++ b/test/corruptN.test
@@ -276,4 +276,31 @@ do_catchsql_test 6.3 {
UPDATE t1 SET x='hello world' WHERE rowid=1;
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 7.0 {
+ BEGIN;
+ CREATE TABLE p1(x PRIMARY KEY);
+ CREATE TABLE c1(y);
+
+ PRAGMA schema_version = 0;
+ PRAGMA writable_schema = RESET;
+
+ INSERT INTO c1 VALUES(1000);
+ ROLLBACK;
+}
+
+do_execsql_test 7.1 {
+ PRAGMA table_info = p1;
+} {0 x {} 0 {} 1}
+
+do_catchsql_test 7.2 {
+ SELECT * FROM p1;
+} {1 {database disk image is malformed}}
+
+do_catchsql_test 7.3 {
+ PRAGMA integrity_check
+} {1 {database disk image is malformed}}
+
+
finish_test
diff --git a/test/indexexpr3.test b/test/indexexpr3.test
new file mode 100644
index 0000000000..21e1d329ad
--- /dev/null
+++ b/test/indexexpr3.test
@@ -0,0 +1,83 @@
+# 2024-10-05
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this file is testing indexes on expressions.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix indexexpr3
+
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(a, j);
+ INSERT INTO t1 VALUES(1, '{x:"one"}');
+ INSERT INTO t1 VALUES(2, '{x:"two"}');
+ INSERT INTO t1 VALUES(3, '{x:"three"}');
+
+ CREATE INDEX i1 ON t1( json_extract(j, '$.x') );
+ CREATE INDEX i2 ON t1( a, json_extract(j, '$.x') );
+}
+
+proc do_hasfunction_test {tn sql res} {
+ set nFunction 0
+ db eval "EXPLAIN $sql" x {
+ if {$x(opcode)=="Function"} {
+ incr nFunction
+ }
+ }
+
+ do_execsql_test $tn "
+ SELECT $nFunction;
+ $sql
+ " $res
+}
+
+do_hasfunction_test 1.1 {
+ SELECT json_extract(j, '$.x') FROM t1 ORDER BY 1;
+} {
+ 0 one three two
+}
+
+do_hasfunction_test 1.2 {
+ SELECT json_extract(j, '$.x') FROM t1 WHERE a=2
+} {
+ 0 two
+}
+
+do_hasfunction_test 1.3 {
+ SELECT coalesce(json_extract(j, '$.x'), 'five') FROM t1 WHERE a=2
+} {
+ 0 two
+}
+
+do_hasfunction_test 1.4 {
+ SELECT json_extract(j, '$.x') || '.two' FROM t1 WHERE a=2
+} {
+ 0 two.two
+}
+
+do_hasfunction_test 1.5 {
+ SELECT json_insert( '{}', '$.y', json_extract(j, '$.x') ) FROM t1 WHERE a=2
+} {
+ 2 {{"y":"two"}}
+}
+
+do_hasfunction_test 1.6 {
+ SELECT json_insert( '{}', '$.y', coalesce( json_extract(j, '$.x'), 'five' ) )
+ FROM t1 WHERE a=2
+} {
+ 2 {{"y":"two"}}
+}
+
+
+finish_test
+
diff --git a/test/like.test b/test/like.test
index d314e96a19..0d732b569c 100644
--- a/test/like.test
+++ b/test/like.test
@@ -731,16 +731,16 @@ ifcapable like_opt&&!icu {
}
do_test like-9.5.1 {
set res [sqlite3_exec_hex db {
- SELECT x FROM t2 WHERE x LIKE '%fe%25'
+ SELECT 1 FROM t2 WHERE x LIKE '%fe%25'
}]
- } {0 {}}
+ } {0 {1 1}}
ifcapable explain {
do_test like-9.5.2 {
set res [sqlite3_exec_hex db {
EXPLAIN QUERY PLAN SELECT x FROM t2 WHERE x LIKE '%fe%25'
}]
regexp {INDEX i2} $res
- } {1}
+ } {0}
}
# Do an SQL statement. Append the search count to the end of the result.
diff --git a/test/lock5.test b/test/lock5.test
index e0c88aedcf..8ebc277018 100644
--- a/test/lock5.test
+++ b/test/lock5.test
@@ -146,6 +146,54 @@ do_test lock5-flock.8 {
db2 close
} {}
+do_test lock5-flock.9 {
+ sqlite3 db test.db -vfs unix-flock
+ execsql {
+ SELECT * FROM t1
+ }
+} {1 2}
+
+do_test lock5-flock.10 {
+ sqlite3 db2 test.db -vfs unix-flock
+ execsql {
+ SELECT * FROM t1
+ } db2
+} {1 2}
+
+do_test lock5-flock.10 {
+ execsql {
+ PRAGMA cache_size = 1;
+ BEGIN;
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000
+ )
+ INSERT INTO t1 SELECT i, i+1 FROM s;
+ }
+
+ catchsql {
+ SELECT * FROM t1
+ } db2
+} {1 {database is locked}}
+
+if {[permutation]!="inmemory_journal"} {
+ do_test lock5-flock.11 {
+ forcecopy test.db test.db2
+ forcecopy test.db-journal test.db2-journal
+ db2 close
+ sqlite3 db2 test.db2 -vfs unix-flock
+ catchsql {
+ SELECT * FROM t1
+ } db2
+ } {0 {1 2}}
+
+ do_test lock5-flock.12 {
+ file exists test.db2-journal
+ } 0
+}
+
+db close
+db2 close
+
}
#####################################################################
diff --git a/test/shell1.test b/test/shell1.test
index b4883e3521..a272295f55 100644
--- a/test/shell1.test
+++ b/test/shell1.test
@@ -1063,7 +1063,10 @@ do_test shell1-5.0 {
continue
}
# Tcl 8.7 maps 0x80 through 0x9f into valid UTF8. So skip those tests.
- if {$i>=0x80 && ($i<=0x9F || $tcl_version>=9.0)} continue
+ if {$i>=0x80} {
+ if {$i<=0x9F || $tcl_version>=9.0} continue
+ if {$tcl_platform(platform)=="windows"} continue
+ }
if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"} continue
if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"} continue
set hex [format %02X $i]
diff --git a/test/thread_common.tcl b/test/thread_common.tcl
index 6b17082ad4..1ebc6573a9 100644
--- a/test/thread_common.tcl
+++ b/test/thread_common.tcl
@@ -95,7 +95,7 @@ proc run_thread_tests {{print_warning 0}} {
if {[info commands sqlthread] eq ""} {
set zProblem "SQLite build is not threadsafe"
}
- if {![info exists ::tcl_platform(threaded)]} {
+ if {![tcl::pkgconfig get threaded]} {
set zProblem "Linked against a non-threadsafe Tcl build"
}
if {[info exists zProblem]} {
@@ -107,4 +107,3 @@ proc run_thread_tests {{print_warning 0}} {
}
return 0
-
diff --git a/tool/mktoolzip.tcl b/tool/mktoolzip.tcl
index 885bae960b..a5951168a8 100644
--- a/tool/mktoolzip.tcl
+++ b/tool/mktoolzip.tcl
@@ -54,16 +54,7 @@ close $in
scan $vers %d.%d.%d v1 v2 v3
set v2 [format 3%02d%02d00 $v2 $v3]
set name sqlite-tools-$OS-$ARCH-$v2.zip
-
-if {$OS=="win32"} {
- # The win32 tar.exe supports the -a ("auto-compress") option. This causes
- # tar to create an archive type based on the extension of the output file.
- # In this case, a zip file.
- puts "tar -a -cf $name sqlite3$EXE sqldiff$EXE sqlite3_analyzer$EXE"
- puts [exec tar -a -cf $name sqlite3$EXE sqldiff$EXE sqlite3_analyzer$EXE]
- puts "$name: [file size $name] bytes"
-} else {
- puts "zip $name sqlite3$EXE sqldiff$EXE sqlite3_analyzer$EXE"
- puts [exec zip $name sqlite3$EXE sqldiff$EXE sqlite3_analyzer$EXE]
- puts [exec ls -l $name]
-}
+set toollist "sqlite3$EXE sqldiff$EXE sqlite3_analyzer$EXE sqlite3_rsync$EXE"
+puts "zip $name {*}$toollist"
+exec zip $name {*}$toollist
+puts "$name: [file size $name] bytes"
diff --git a/tool/sqlite3-rsync.c b/tool/sqlite3_rsync.c
similarity index 99%
rename from tool/sqlite3-rsync.c
rename to tool/sqlite3_rsync.c
index 216390c182..688ff1efe3 100644
--- a/tool/sqlite3-rsync.c
+++ b/tool/sqlite3_rsync.c
@@ -21,7 +21,7 @@
#include "sqlite3.h"
static const char zUsage[] =
- "sqlite3-rsync ORIGIN REPLICA ?OPTIONS?\n"
+ "sqlite3_rsync ORIGIN REPLICA ?OPTIONS?\n"
"\n"
"One of ORIGIN or REPLICA is a pathname to a database on the local\n"
"machine and the other is of the form \"USER@HOST:PATH\" describing\n"
@@ -30,7 +30,7 @@ static const char zUsage[] =
"\n"
"OPTIONS:\n"
"\n"
- " --exe PATH Name of the sqlite3-rsync program on the remote side\n"
+ " --exe PATH Name of the sqlite3_rsync program on the remote side\n"
" --help Show this help screen\n"
" --ssh PATH Name of the SSH program used to reach the remote side\n"
" -v Verbose. Multiple v's for increasing output\n"
@@ -1197,6 +1197,7 @@ static void originSide(SQLiteRsync *p){
int c = 0;
unsigned int nPage = 0;
unsigned int iPage = 0;
+ unsigned int lockBytePage = 0;
unsigned int szPg = 0;
sqlite3_stmt *pCkHash = 0;
char buf[200];
@@ -1235,6 +1236,7 @@ static void originSide(SQLiteRsync *p){
p->nPage = nPage;
p->szPage = szPg;
p->iProtocol = PROTOCOL_VERSION;
+ lockBytePage = (1<<30)/szPg + 1;
}
}
@@ -1290,6 +1292,7 @@ static void originSide(SQLiteRsync *p){
" INSERT INTO badHash SELECT n FROM c",
iPage+1, p->nPage);
}
+ runSql(p, "DELETE FROM badHash WHERE pgno=%d", lockBytePage);
pStmt = prepareStmt(p,
"SELECT pgno, data"
" FROM badHash JOIN sqlite_dbpage('main') USING(pgno)");
@@ -1583,13 +1586,13 @@ static char *hostSeparator(const char *zIn){
**
** Input formats:
**
-** (1) sqlite3-rsync FILENAME1 USER@HOST:FILENAME2
+** (1) sqlite3_rsync FILENAME1 USER@HOST:FILENAME2
**
-** (2) sqlite3-rsync USER@HOST:FILENAME1 FILENAME2
+** (2) sqlite3_rsync USER@HOST:FILENAME1 FILENAME2
**
-** (3) sqlite3-rsync --origin FILENAME1
+** (3) sqlite3_rsync --origin FILENAME1
**
-** (4) sqlite3-rsync --replica FILENAME2
+** (4) sqlite3_rsync --replica FILENAME2
**
** The user types (1) or (2). SSH launches (3) or (4).
**
@@ -1613,7 +1616,7 @@ int main(int argc, char const * const *argv){
FILE *pOut = 0;
int childPid = 0;
const char *zSsh = "ssh";
- const char *zExe = "sqlite3-rsync";
+ const char *zExe = "sqlite3_rsync";
char *zCmd = 0;
sqlite3_int64 tmStart;
sqlite3_int64 tmEnd;
diff --git a/tool/src-verify.c b/tool/src-verify.c
index 7629046564..0c7ed6f4c4 100644
--- a/tool/src-verify.c
+++ b/tool/src-verify.c
@@ -854,12 +854,16 @@ int main(int argc, char **argv){
xErr = errorMsgNH;
continue;
}
+ usage:
fprintf(stderr, "Usage: %s DIRECTORY\n"
" or: %s --sha1 FILE ...\n"
" or: %s --sha3 FILE ...\n",
argv[0], argv[0], argv[0]);
return 1;
}
+ if( !zDir ){
+ goto usage;
+ }
if( strlen(zDir)>1000 ){
fprintf(stderr, "Directory argument too big: [%s]\n", zDir);
return 1;