aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordan <Dan Kennedy>2025-02-11 17:10:46 +0000
committerdan <Dan Kennedy>2025-02-11 17:10:46 +0000
commit138951dc2eb7256ae932d4b75266618773eb504b (patch)
tree9c6f157123d9bd225cc670605bc0324a44305937
parent2d878947004909b22c2057eb124b9d00fabe8d82 (diff)
parent62e1d44846baa68cdfcdcbdd58fcb4483cc5de47 (diff)
downloadsqlite-138951dc2eb7256ae932d4b75266618773eb504b.tar.gz
sqlite-138951dc2eb7256ae932d4b75266618773eb504b.zip
Merge latest changes from trunk into this branch.
FossilOrigin-Name: e5ec5bb9f4dc3e02db7ab0e49686f47617af75d3f7d4ab23288a1aea4a693e59
-rw-r--r--Makefile.in9
-rw-r--r--Makefile.msc23
-rw-r--r--VERSION2
-rw-r--r--auto.def1246
-rw-r--r--autoconf/INSTALL370
-rw-r--r--autoconf/Makefile.am20
-rw-r--r--autoconf/Makefile.in248
-rw-r--r--autoconf/Makefile.msc3
-rw-r--r--autoconf/README.first13
-rw-r--r--autoconf/README.txt25
-rw-r--r--autoconf/auto.def101
-rw-r--r--autoconf/configure.ac270
-rw-r--r--autoconf/tea/configure.ac2
-rw-r--r--autosetup/README.md60
-rw-r--r--autosetup/jimsh0.c41
-rw-r--r--autosetup/proj.tcl55
-rw-r--r--autosetup/sqlite-config.tcl1485
-rw-r--r--doc/compile-for-unix.md6
-rw-r--r--doc/compile-for-windows.md28
-rw-r--r--doc/tcl-extension-testing.md208
-rw-r--r--ext/fts3/fts3.c18
-rw-r--r--ext/fts3/fts3Int.h1
-rw-r--r--ext/fts3/fts3_snippet.c22
-rw-r--r--ext/fts5/fts5_index.c97
-rw-r--r--ext/fts5/fts5_main.c22
-rw-r--r--ext/fts5/fts5_storage.c5
-rw-r--r--ext/fts5/test/fts5circref.test2
-rw-r--r--ext/fts5/test/fts5corrupt3.test233
-rw-r--r--ext/fts5/test/fts5corrupt5.test467
-rw-r--r--ext/fts5/test/fts5faultI.test35
-rw-r--r--ext/fts5/test/fts5misc.test22
-rw-r--r--ext/fts5/test/fts5savepoint.test2
-rw-r--r--ext/fts5/test/fts5version.test2
-rw-r--r--ext/misc/base64.c9
-rw-r--r--ext/misc/base85.c4
-rw-r--r--ext/misc/closure.c7
-rw-r--r--ext/misc/fileio.c2
-rw-r--r--ext/misc/regexp.c3
-rw-r--r--ext/misc/sqlite3_stdio.c16
-rw-r--r--ext/misc/vfstrace.c31
-rw-r--r--ext/session/session1.test4
-rw-r--r--ext/session/session9.test20
-rw-r--r--ext/session/session_common.tcl8
-rw-r--r--ext/session/session_gen.test191
-rw-r--r--ext/session/sessionnoact.test125
-rw-r--r--ext/session/sqlite3session.c149
-rw-r--r--ext/session/test_session.c3
-rw-r--r--ext/wasm/GNUmakefile248
-rw-r--r--ext/wasm/README-dist.txt12
-rw-r--r--ext/wasm/README.md46
-rw-r--r--ext/wasm/api/README.md24
-rw-r--r--ext/wasm/api/extern-post-js.c-pp.js20
-rw-r--r--ext/wasm/api/post-js-footer.js4
-rw-r--r--ext/wasm/api/post-js-header.js19
-rw-r--r--ext/wasm/api/sqlite3-api-cleanup.js3
-rw-r--r--ext/wasm/api/sqlite3-api-glue.c-pp.js50
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js87
-rw-r--r--ext/wasm/api/sqlite3-api-worker1.c-pp.js25
-rw-r--r--ext/wasm/api/sqlite3-wasm.c7
-rw-r--r--ext/wasm/common/whwasmutil.js13
-rw-r--r--ext/wasm/config.make.in15
-rw-r--r--ext/wasm/demo-worker1-promiser.c-pp.js5
-rw-r--r--ext/wasm/demo-worker1.js5
-rw-r--r--ext/wasm/dist.make14
-rw-r--r--ext/wasm/index-dist.html4
-rw-r--r--ext/wasm/mkwasmbuilds.c183
-rw-r--r--ext/wasm/tester1.c-pp.js104
-rw-r--r--ext/wasm/wasmfs.make2
-rw-r--r--main.mk69
-rw-r--r--manifest283
-rw-r--r--manifest.uuid2
-rw-r--r--src/alter.c6
-rw-r--r--src/analyze.c3
-rw-r--r--src/attach.c6
-rw-r--r--src/build.c76
-rw-r--r--src/callback.c10
-rw-r--r--src/date.c5
-rw-r--r--src/dbpage.c37
-rw-r--r--src/expr.c18
-rw-r--r--src/func.c76
-rw-r--r--src/hash.c46
-rw-r--r--src/hash.h1
-rw-r--r--src/insert.c54
-rw-r--r--src/json.c18
-rw-r--r--src/main.c19
-rw-r--r--src/os_unix.c2
-rw-r--r--src/pager.c2
-rw-r--r--src/parse.y36
-rw-r--r--src/resolve.c90
-rw-r--r--src/select.c31
-rw-r--r--src/shell.c.in16
-rw-r--r--src/sqlite.h.in147
-rw-r--r--src/sqliteInt.h67
-rw-r--r--src/tclsqlite.c25
-rw-r--r--src/test1.c19
-rw-r--r--src/test_intarray.c3
-rw-r--r--src/test_malloc.c6
-rw-r--r--src/tokenize.c12
-rw-r--r--src/treeview.c24
-rw-r--r--src/trigger.c8
-rw-r--r--src/update.c44
-rw-r--r--src/util.c6
-rw-r--r--src/vdbe.c5
-rw-r--r--src/vdbe.h1
-rw-r--r--src/vdbeInt.h8
-rw-r--r--src/vdbeapi.c35
-rw-r--r--src/vdbeaux.c27
-rw-r--r--src/vdbeblob.c8
-rw-r--r--src/vdbemem.c43
-rw-r--r--src/vtab.c9
-rw-r--r--src/where.c333
-rw-r--r--src/whereInt.h14
-rw-r--r--src/wherecode.c3
-rw-r--r--src/whereexpr.c32
-rw-r--r--test/autoindex1.test28
-rw-r--r--test/capi3.test4
-rw-r--r--test/date.test8
-rw-r--r--test/dbpage.test144
-rw-r--r--test/dbpagefault.test26
-rw-r--r--test/fkey6.test42
-rw-r--r--test/fuzzcheck.c92
-rw-r--r--test/fuzzdata8.dbbin4239360 -> 4248576 bytes
-rw-r--r--test/in7.test29
-rw-r--r--test/like3.test80
-rw-r--r--test/pragma4.test2
-rw-r--r--test/speedtest.md53
-rwxr-xr-xtest/speedtest.tcl304
-rw-r--r--test/speedtest1.c762
-rw-r--r--test/starschema1.test2
-rw-r--r--test/testrunner_data.tcl5
-rw-r--r--test/trace3.test16
-rw-r--r--test/walsetlk3.test1
-rw-r--r--test/with6.test6
-rw-r--r--tool/buildtclext.tcl38
-rw-r--r--tool/emcc.sh.in2
-rw-r--r--tool/mkamalzip.tcl23
-rw-r--r--tool/mkautoconfamal.sh53
-rw-r--r--tool/mkshellc.tcl3
-rw-r--r--tool/mksqlite3c-noext.tcl2
-rw-r--r--tool/mksqlite3c.tcl4
-rw-r--r--tool/mksqlite3h.tcl35
-rw-r--r--tool/mksrczip.tcl14
-rw-r--r--tool/omittest.tcl4
-rw-r--r--tool/split-sqlite3c.tcl2
-rw-r--r--tool/stripccomments.c19
145 files changed, 7106 insertions, 3087 deletions
diff --git a/Makefile.in b/Makefile.in
index 5b17c0e42..59a62d061 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -118,9 +118,14 @@ LDFLAGS.dlopen = @LDFLAGS_DLOPEN@
LDFLAGS.readline = @LDFLAGS_READLINE@
CFLAGS.readline = @CFLAGS_READLINE@
LDFLAGS.icu = @LDFLAGS_ICU@
+LDFLAGS.rt = @LDFLAGS_RT@
CFLAGS.icu = @CFLAGS_ICU@
LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@
# soname: see https://sqlite.org/src/forumpost/5a3b44f510df8ded
+LDFLAGS.libsqlite3.os-specific = @LDFLAGS_MAC_CVERSION@ @LDFLAGS_OUT_IMPLIB@
+# os-specific: see
+# - https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7
+# - https://sqlite.org/forum/forumpost/0c7fc097b2
ENABLE_SHARED = @ENABLE_SHARED@
ENABLE_STATIC = @ENABLE_STATIC@
HAVE_WASI_SDK = @HAVE_WASI_SDK@
@@ -323,9 +328,6 @@ distclean-autosetup: clean
rm -f $(TOP)/tool/emcc.sh
rm -f libsqlite3*$(T.dll)
rm -f jimsh0*
-# -if [ -f ext/wasm/GNUmakefile ]; then \
-# gmake --no-print-directory --ignore-errors -C ext/wasm distclean; \
-# fi >/dev/null 2>&1; true
distclean: distclean-autosetup
#
@@ -335,4 +337,5 @@ distclean: distclean-autosetup
version-info$(T.exe): $(TOP)/tool/version-info.c Makefile sqlite3.h
$(T.link) $(ST_OPT) -o $@ $(TOP)/tool/version-info.c
+IS_CROSS_COMPILING = @IS_CROSS_COMPILING@
include $(TOP)/main.mk
diff --git a/Makefile.msc b/Makefile.msc
index 78b1d7ee2..09e860aaa 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -994,10 +994,14 @@ TCLLIBS =
!ENDIF
!IFNDEF LIBTCLSTUB
-!IF EXISTS("$(TCLLIBDIR)\tclstub$(TCLSUFFIX).lib")
+!IF EXISTS("$(TCLLIBDIR)\tclstub$(TCLVERSION)$(TCLSUFFIX).lib")
+LIBTCLSTUB = tclstub$(TCLVERSION)$(TCLSUFFIX).lib
+!ELSEIF EXISTS("$(TCLLIBDIR)\tclstub$(TCLSUFFIX).lib")
LIBTCLSTUB = tclstub$(TCLSUFFIX).lib
+!ELSEIF EXISTS("$(TCLLIBDIR)\tclstub$(TCLVERSION).lib")
+LIBTCLSTUB = tclstub$(TCLVERSION).lib
!ELSE
-LIBTCLSTUB = tclstub$(TCLVERSION)$(TCLSUFFIX).lib
+LIBTCLSTUB = tclstub.lib
!ENDIF
!ENDIF
@@ -1898,7 +1902,10 @@ tclextension-uninstall:
$(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --uninstall
tclextension-list:
- $(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --info
+ @ $(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --info
+
+tclextension-verify: sqlite3.h
+ @ $(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --version-check
# <</mark>>
@@ -2337,7 +2344,7 @@ parse.c: $(TOP)\src\parse.y lemon.exe
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y
$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION $(JIM_TCLSH)
- $(JIM_TCLSH) $(TOP)\tool\mksqlite3h.tcl "$(TOP:\=/)" > $(SQLITE3H) $(MKSQLITE3H_ARGS)
+ $(JIM_TCLSH) $(TOP)\tool\mksqlite3h.tcl "$(TOP:\=/)" -o $(SQLITE3H) $(MKSQLITE3H_ARGS)
sqlite3ext.h: .target_source
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
@@ -2401,7 +2408,7 @@ SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\zipfile.c
!ENDIF
shell.c: $(SHELL_DEP) $(TOP)\tool\mkshellc.tcl $(JIM_TCLSH)
- $(JIM_TCLSH) $(TOP)\tool\mkshellc.tcl > shell.c
+ $(JIM_TCLSH) $(TOP)\tool\mkshellc.tcl shell.c
zlib:
pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd
@@ -2802,6 +2809,8 @@ tcl-env:
@echo LIBTCL = $(LIBTCL)
@echo LIBTCLSTUB = $(LIBTCLSTUB)
@echo TCLSH_CMD = $(TCLSH_CMD)
+ @echo JIM_TCLSH = $(JIM_TCLSH)
+ @echo VISUALSTUDIOVERSION = $(VISUALSTUDIOVERSION)
LSMDIR=$(TOP)\ext\lsm1
!INCLUDE $(LSMDIR)\Makefile.msc
@@ -2812,7 +2821,8 @@ moreclean: clean
clean:
del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
- del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q sqlite3.def tclsqlite3.def 2>NUL
del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
# <<mark>>
del /Q $(SQLITE3TCLDLL) pkgIndex.tcl 2>NUL
@@ -2846,4 +2856,5 @@ clean:
del /Q fts5.* fts5parse.* 2>NUL
del /Q lsm.h lsm1.c 2>NUL
del /q src-verify.exe 2>NUL
+ del /q jimsh.exe jimsh0.exe 2>NUL
# <</mark>>
diff --git a/VERSION b/VERSION
index 7dd5eda81..ca25ff637 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.48.0
+3.50.0
diff --git a/auto.def b/auto.def
index c9aa0cb9d..6274d79b6 100644
--- a/auto.def
+++ b/auto.def
@@ -12,18 +12,17 @@
#
# JimTCL: https://jim.tcl.tk
#
-use cc cc-db cc-shared cc-lib proj pkg-config
+use sqlite-config
+
+if {[string first " " $autosetup(srcdir)] != -1} {
+ user-error "The pathname of the source tree\
+ may not contain space characters"
+}
+if {[string first " " $autosetup(builddir)] != -1} {
+ user-error "The pathname of the build directory\
+ may not contain space characters"
+}
-# $DUMP_DEFINES_TXT is the file emitted by --dump-defines, intended
-# only for build debugging and not part of the public build interface.
-set DUMP_DEFINES_TXT ./config.defines.txt
-# $DUMP_DEFINES_JSON is the autosetup counterpart of the historical
-# "DEFS" var which was generated by the autotools in the pre-processed
-# autotools builds (but not in the canonical tree). Generation of this
-# file is disabled (via an empty file name) until/unless someone
-# voices a specific interest in it. The original motivating use case
-# is handled fine by sqlite_cfg.h.
-set DUMP_DEFINES_JSON ""; #./config.defines.json
########################################################################
# Regarding flag compatibility with the historical autotool configure
@@ -34,10 +33,9 @@ set DUMP_DEFINES_JSON ""; #./config.defines.json
# flags compared to the historical autotools build. The differences
# are documented here:
#
-# 1) --debug is used by autosetup itself, so we have to rename it to
-# --with-debug. We cannot use --enable-debug because that is, for
-# autosetup, an alias for --debug=1. Alternately, we can patch
-# autosetup to use --autosetup-debug for its own purposes instead.
+# 1) --debug is used by autosetup itself, but we patch it because
+# decades of muscle memory expect --debug to apply to this code,
+# not the configure script (details are in autosetup/README.md).
#
# 2) In autosetup, all flags starting with (--enable, --disable) are
# forced to be booleans and receive special handling in how they're
@@ -199,9 +197,12 @@ set flags {
test-status => {Enable status of tests}
gcov=0 => {Enable coverage testing using gcov}
linemacros => {Enable #line macros in the amalgamation}
- dump-defines=0 => {Dump autosetup defines to $DUMP_DEFINES_TXT (for build debugging)}
dynlink-tools => {Dynamically link libsqlite3 to certain tools which normally statically embed it.}
+ dump-defines=0 => {Dump autosetup defines to $::sqliteConfig(dump-defines-txt) (for build debugging)}
+ # </developer>
+ # <packaging>
soname:=legacy =>
+ # --soname has a long story behind it: https://sqlite.org/src/forumpost/5a3b44f510df8ded
{SONAME for libsqlite3.so. "none", or not using this flag, sets no
soname. "legacy" sets it to its historical value of
libsqlite3.so.0. A value matching the glob "libsqlite3.*" sets
@@ -209,125 +210,21 @@ set flags {
suffix which gets applied to "libsqlite3.so.",
e.g. --soname=9.10 equates to "libsqlite3.so.9.10".
}
- # --soname has a long story behind it: https://sqlite.org/src/forumpost/5a3b44f510df8ded
- # </developer>
+ out-implib=0 =>
+ {Enable use of --out-implib linker flag to generate an "import library" for the DLL}
+ # </packaging>
}
-if {"" ne $DUMP_DEFINES_JSON} {
+if {"" ne $::sqliteConfig(dump-defines-json)} {
lappend flags \
defines-json-include-lowercase=0 \
- => {Include lower-case defines (primarily system paths) in $DUMP_DEFINES_JSON}
+ => {Include lower-case defines (primarily system paths) in $::sqliteConfig(dump-defines-json)}
}
options [subst -nobackslashes -nocommands $flags]
unset flags
+sqlite-post-options-init
-#
-# Carry values from hidden --flag aliases over to their canonical flag
-# forms.
-#
-proj-xfer-options-aliases {
- with-readline-inc => with-readline-cflags
- with-readline-lib => with-readline-ldflags
- with-debug => debug
-}
-
-set srcdir $::autosetup(srcdir)
-set PACKAGE_VERSION [proj-file-content -trim $srcdir/VERSION]
-define PACKAGE_NAME "sqlite"
-define PACKAGE_URL {https://sqlite.org}
-define PACKAGE_VERSION $PACKAGE_VERSION
-define PACKAGE_STRING "[get-define PACKAGE_NAME] $PACKAGE_VERSION"
-define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
-msg-result "Source dir = $srcdir"
-msg-result "Build dir = $::autosetup(builddir)"
-msg-result "Configuring SQLite version $PACKAGE_VERSION"
-
-apply {{} {
- #
- # SQLITE_AUTORECONFIG contains make target rules for re-running the
- # configure script with the same arguments it was initially invoked
- # with. This can be used to automatically reconfigure
- #
- proc squote {arg} {
- # Wrap $arg in single-quotes if it looks like it might need that
- # to avoid mis-handling as a shell argument. We assume that $arg
- # will never contain any single-quote characters.
- if {[string match {*[ &;$*"]*} $arg]} { return '$arg' }
- return $arg
- }
- define-append SQLITE_AUTORECONFIG cd [squote $::autosetup(builddir)] && [squote $::srcdir/configure]
- #{*}$::autosetup(argv) breaks with --flag='val with spaces', so...
- foreach arg $::autosetup(argv) {
- define-append SQLITE_AUTORECONFIG [squote $arg]
- }
- rename squote ""
-}}
-
-# Are we cross-compiling?
-set isCrossCompiling [proj-is-cross-compiling]
-
-define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
-define OPT_SHELL {} ; # Feature-related CFLAGS for the sqlite3 CLI app
-########################################################################
-# Adds $args, if not empty, to OPT_FEATURE_FLAGS. If the first arg is
-# -shell then it strips that arg and passes the remaining args the
-# sqlite-add-shell-opt in addition to adding them to
-# OPT_FEATURE_FLAGS.
-proc sqlite-add-feature-flag {args} {
- set shell ""
- if {"-shell" eq [lindex $args 0]} {
- set args [lassign $args shell]
- }
- if {"" ne $args} {
- if {"" ne $shell} {
- sqlite-add-shell-opt {*}$args
- }
- define-append OPT_FEATURE_FLAGS {*}$args
- }
-}
-# Appends $args, if not empty, to OPT_SHELL.
-proc sqlite-add-shell-opt {args} {
- if {"" ne $args} {
- define-append OPT_SHELL {*}$args
- }
-}
-
-# Pass msg-debug=1 to configure to enable obnoxiously loud output from
-# msg-debug.
-set msgDebugEnabled [proj-val-truthy [get-env msg-debug 0]]
-proc msg-debug {msg} {
- if {$::msgDebugEnabled} {
- puts stderr [proj-bold "** DEBUG: $msg"]
- }
-}
-
-proj-file-extensions
-if {".exe" eq [get-define TARGET_EXEEXT]} {
- define SQLITE_OS_UNIX 0
- define SQLITE_OS_WIN 1
-} else {
- define SQLITE_OS_UNIX 1
- define SQLITE_OS_WIN 0
-}
-
-#########
-# Programs needed
-cc-check-tools ld ar ; # must come before [sqlite-check-wasi-sdk]
-if {"" eq [proj-bin-define install]} {
- proj-warn "Cannot find install binary, so 'make install' will not work."
- define BIN_INSTALL false
-}
-
-########################################################################
-# We differentiate between two C compilers: the one used for binaries
-# which are to run on the build system (in autosetup it's called
-# CC_FOR_BUILD and in Makefile.in it's $(B.cc)) and the one used for
-# compiling binaries for the target system (CC a.k.a. $(T.cc)).
-# Normally they're the same, but they will differ when
-# cross-compiling.
-define CFLAGS [proj-get-env CFLAGS {-g -O2}]
-define BUILD_CFLAGS [proj-get-env BUILD_CFLAGS {-g}]
-
+sqlite-setup-default-cflags
proj-if-opt-truthy dev {
# --enable-dev needs to come early so that the downstream tests
# which check for the following flags use their updated state.
@@ -335,170 +232,23 @@ proj-if-opt-truthy dev {
proj-opt-set debug 1
proj-opt-set amalgamation 0
define CFLAGS [get-env CFLAGS {-O0 -g}]
+ # -------------^^^^^^^ intentionally using [get-env] instead of
+ # [proj-get-env] here because [sqlite-setup-default-cflags] uses
+ # [proj-get-env] and we want this to supercede that.
}
-########################################################################
-# Handle --with-wasi-sdk=DIR
-#
-# This must be run relatively early on because it may change the
-# toolchain and disable a number of config options.
-proc sqlite-check-wasi-sdk {} {
- set wasiSdkDir [opt-val with-wasi-sdk] ; # ??? [lindex [opt-val with-wasi-sdk] end]
- define HAVE_WASI_SDK 0
- if {$wasiSdkDir eq ""} {
- return 0
- } elseif {$::isCrossCompiling} {
- proj-fatal "Cannot combine --with-wasi-sdk with cross-compilation"
- }
- msg-result "Checking WASI SDK directory \[$wasiSdkDir]... "
- #puts "prefix = [prefix $wasiSdkDir/bin {clang ld}]"
- proj-affirm-files-exist -v {*}[prefix "$wasiSdkDir/bin/" {clang wasm-ld ar}]
- define HAVE_WASI_SDK 1
- define WASI_SDK_DIR $wasiSdkDir
- # Disable numerous options which we know either can't work or are
- # not useful in this build...
- msg-result "Using wasi-sdk clang. Disabling CLI shell modifying config flags:"
- # Boolean (--enable-/--disable-) flags which must be switched off:
- foreach opt {
- dynlink-tools
- editline
- gcov
- icu-collations
- load-extension
- readline
- shared
- tcl
- threadsafe
- } {
- if {[opt-bool $opt]} {
- msg-result " --disable-$opt"
- proj-opt-set $opt 0
- }
- }
- # Non-boolean flags which need to be cleared:
- foreach opt {
- with-emsdk
- with-icu-config
- with-icu-ldflags
- with-icu-cflags
- with-linenoise
- with-tcl
- } {
- if {[proj-opt-was-provided $opt]} {
- msg-result " removing --$opt"
- proj-opt-set $opt ""
- }
- }
- # Remember that we now have a discrepancy beteween
- # $::isCrossCompiling and [proj-is-cross-compiling].
- set ::isCrossCompiling 1
-
- #
- # Changing --host and --target have no effect here except to
- # possibly cause confusion. Autosetup has finished processing them
- # by this point.
- #
- # host_alias=wasm32-wasi
- # target=wasm32-wasi
- #
- # Merely changing CC, LD, and AR to the wasi-sdk's is enough to get
- # sqlite3.o building in WASM format.
- #
- define CC "${wasiSdkDir}/bin/clang"
- define LD "${wasiSdkDir}/bin/wasm-ld"
- define AR "${wasiSdkDir}/bin/ar"
- #define STRIP "${wasiSdkDir}/bin/strip"
- return 1
-}; # sqlite-check-wasi-sdk
-sqlite-check-wasi-sdk
-
-########################################################################
-# --dynlink-tools tells the build to dynamically link certain binaries
-# to libsqlite3.so instead of embedding a copy of the amalgamation.
-define LINK_TOOLS_DYNAMICALLY [proj-opt-was-provided dynlink-tools]
+sqlite-check-common-bins ;# must come before [sqlite-handle-wasi-sdk]
+sqlite-handle-wasi-sdk ;# must run relatively early, as it changes the environment
+sqlite-check-common-system-deps
#
# Enable large file support (if special flags are necessary)
+#
define HAVE_LFS 0
if {[opt-bool largefile]} {
cc-check-lfs
}
-#
-# Check for needed/wanted data types
-cc-with {-includes stdint.h} \
- {cc-check-types int8_t int16_t int32_t int64_t intptr_t \
- uint8_t uint16_t uint32_t uint64_t uintptr_t}
-
-#
-# Check for needed/wanted functions
-cc-check-functions gmtime_r isnan localtime_r localtime_s \
- malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64
-
-proj-check-function-in-lib fdatasync rt
-define LDFLAGS_FDATASYNC [get-define lib_fdatasync]
-undefine lib_fdatasync
-
-#
-# Check for needed/wanted headers
-cc-check-includes \
- sys/types.h sys/stat.h dlfcn.h unistd.h \
- stdlib.h malloc.h memory.h \
- string.h strings.h \
- inttypes.h
-
-if {[cc-check-includes zlib.h] && [proj-check-function-in-lib deflate z]} {
- # TODO? port over the more sophisticated zlib search from the fossil auto.def
- define HAVE_ZLIB 1
- define LDFLAGS_ZLIB -lz
- sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
-} else {
- define HAVE_ZLIB 0
- define LDFLAGS_ZLIB ""
-}
-
-proj-check-rpath ; # Determine proper rpath-handling flag
-
-########################################################################
-# "soname" for libsqlite3.so. See discussion at:
-# https://sqlite.org/src/forumpost/5a3b44f510df8ded
-apply {{} {
- define LDFLAGS_LIBSQLITE3_SONAME ""
- if {[proj-opt-was-provided soname]} {
- set soname [join [opt-val soname] ""]
- } else {
- # Enabling soname breaks linking for the --dynlink-tools feature,
- # and this project has no direct use for soname, so default to
- # none. Package maintainers, on the other hand, like to have an
- # soname.
- set soname none
- }
- switch -exact -- $soname {
- none - "" { return 0 }
- auto { set soname libsqlite3.so.3 }
- legacy { set soname libsqlite3.so.0 }
- default {
- if {[string match libsqlite3.* $soname]} {
- # use it as-is
- } else {
- # Assume it's a suffix
- set soname "libsqlite3.so.${soname}"
- }
- }
- }
- msg-debug "soname=$soname"
- if {[proj-check-soname $soname]} {
- define LDFLAGS_LIBSQLITE3_SONAME [get-define LDFLAGS_SONAME_PREFIX]$soname
- msg-result "Setting SONAME using: [get-define LDFLAGS_LIBSQLITE3_SONAME]"
- } elseif {[proj-opt-was-provided soname]} {
- # --soname was explicitly requested but not available, so fail fatally
- proj-fatal "This environment does not support SONAME."
- } else {
- # --soname was not explicitly requested but not available, so just warn
- msg-result "This environment does not support SONAME."
- }
-}}
-
proj-define-for-opt shared ENABLE_SHARED "Build shared library?"
if {![proj-define-for-opt static ENABLE_STATIC \
@@ -516,924 +266,18 @@ proj-define-for-opt test-status TSTRNNR_OPTS \
proj-define-for-opt linemacros AMALGAMATION_LINE_MACROS \
"Use #line macros in the amalgamation:"
-msg-checking "SQLITE_DEBUG build? "
-proj-if-opt-truthy debug {
- define SQLITE_DEBUG 1
- define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall}
- proj-opt-set memsys5
- msg-result yes
-} {
- define TARGET_DEBUG {-DNDEBUG}
- msg-result no
-}
-
-########################################################################
-# TCL...
-#
-# sqlite-check-tcl performs most of the --with-tcl and --with-tclsh
-# handling. Some related bits and pieces are performed before and
-# after that function is called.
-#
-# Important [define]'d vars:
-#
-# - HAVE_TCL indicates whether we have a tclsh suitable for building
-# the TCL SQLite extension and, by extension, the testing
-# infrastructure. This must only be 1 for environments where
-# tclConfig.sh can be found.
-#
-# - TCLSH_CMD is the path to the canonical tclsh or "". It never
-# refers to jimtcl.
-#
-# - TCL_CONFIG_SH is the path to tclConfig.sh or "".
-#
-# - TCLLIBDIR is the dir to which libtclsqlite3 gets installed.
-#
-# - BTCLSH = the path to the tcl interpreter used for in-tree code
-# generation. It may be jimtcl or the canonical tclsh but may not
-# be empty - this tree requires TCL to generated numerous
-# components.
-#
-# If --tcl or --with-tcl are provided but no TCL is found, this
-# function fails fatally. If they are not explicitly provided then
-# failure to find TCL is not fatal but a loud warning will be emitted.
-#
-proc sqlite-check-tcl {} {
- rename sqlite-check-tcl ""
- define TCLSH_CMD false ; # Significant is that it exits with non-0
- define HAVE_TCL 0 ; # Will be enabled via --tcl or a successful search
- define TCLLIBDIR "" ; # Installation dir for TCL extension lib
- define TCL_CONFIG_SH ""; # full path to tclConfig.sh
-
- # Clear out all vars which would be set by tclConfigToAutoDef.sh, so
- # that the late-config validation of @VARS@ works even if
- # --disable-tcl is used.
- foreach k {TCL_INCLUDE_SPEC TCL_LIB_SPEC TCL_STUB_LIB_SPEC TCL_EXEC_PREFIX TCL_VERSION} {
- define $k ""
- }
-
- file delete -force ".tclenv.sh"; # ensure no stale state from previous configures.
- if {![opt-bool tcl]} {
- proj-indented-notice {
- NOTE: TCL is disabled via --disable-tcl. This means that none
- of the TCL-based components will be built, including tests
- and sqlite3_analyzer.
- }
- return
- }
- # TODO: document the steps this is taking.
- global srcdir
- msg-result "Checking for a suitable tcl... "
- proj-assert [proj-opt-truthy tcl]
- set use_tcl 1
- set with_tclsh [opt-val with-tclsh]
- set with_tcl [opt-val with-tcl]
- if {"prefix" eq $with_tcl} {
- set with_tcl [get-define prefix]
- }
- msg-debug "sqlite-check-tcl: use_tcl ${use_tcl}"
- msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
- msg-debug "sqlite-check-tcl: with_tcl=$with_tcl"
- if {"" eq $with_tclsh && "" eq $with_tcl} {
- # If neither --with-tclsh nor --with-tcl are provided, try to find
- # a workable tclsh.
- set with_tclsh [proj-first-bin-of tclsh9.0 tclsh8.6 tclsh]
- msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
- }
-
- set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
- if {"" ne $with_tclsh} {
- # --with-tclsh was provided or found above. Validate it and use it
- # to trump any value passed via --with-tcl=DIR.
- if {![file isfile $with_tclsh]} {
- proj-fatal "TCL shell $with_tclsh is not a file"
- } elseif {![file-isexec $with_tclsh]} {
- proj-fatal "TCL shell $with_tclsh is not executable"
- } else {
- define TCLSH_CMD $with_tclsh
- #msg-result "Using tclsh: $with_tclsh"
- }
- if {$doConfigLookup &&
- [catch {exec $with_tclsh $srcdir/tool/find_tclconfig.tcl} result] == 0} {
- set with_tcl $result
- }
- if {"" ne $with_tcl && [file isdir $with_tcl]} {
- msg-result "$with_tclsh recommends the tclConfig.sh from $with_tcl"
- } else {
- proj-warn "$with_tclsh is unable to recommend a tclConfig.sh"
- set use_tcl 0
- }
- }
- set cfg ""
- set tclSubdirs {tcl9.0 tcl8.6 lib}
- while {$use_tcl} {
- if {"" ne $with_tcl} {
- # Ensure that we can find tclConfig.sh under ${with_tcl}/...
- if {$doConfigLookup} {
- if {[file readable "${with_tcl}/tclConfig.sh"]} {
- set cfg "${with_tcl}/tclConfig.sh"
- } else {
- foreach i $tclSubdirs {
- if {[file readable "${with_tcl}/$i/tclConfig.sh"]} {
- set cfg "${with_tcl}/$i/tclConfig.sh"
- break
- }
- }
- }
- }
- if {"" eq $cfg} {
- proj-fatal "No tclConfig.sh found under ${with_tcl}"
- }
- } else {
- # If we have not yet found a tclConfig.sh file, look in
- # $libdir which is set automatically by autosetup or by the
- # --prefix command-line option. See
- # https://sqlite.org/forum/forumpost/e04e693439a22457
- set libdir [get-define libdir]
- if {[file readable "${libdir}/tclConfig.sh"]} {
- set cfg "${libdir}/tclConfig.sh"
- } else {
- foreach i $tclSubdirs {
- if {[file readable "${libdir}/$i/tclConfig.sh"]} {
- set cfg "${libdir}/$i/tclConfig.sh"
- break
- }
- }
- }
- if {![file readable $cfg]} {
- break
- }
- }
- msg-result "Using tclConfig.sh: $cfg"
- break
- }
- define TCL_CONFIG_SH $cfg
- # Export a subset of tclConfig.sh to the current TCL-space. If $cfg
- # is an empty string, this emits empty-string entries for the
- # various options we're interested in.
- eval [exec "${srcdir}/tool/tclConfigShToAutoDef.sh" "$cfg"]
-
- if {"" eq $with_tclsh && $cfg ne ""} {
- # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
- # based on info from tclConfig.sh.
- proj-assert {"" ne [get-define TCL_EXEC_PREFIX]}
- set with_tclsh [get-define TCL_EXEC_PREFIX]/bin/tclsh[get-define TCL_VERSION]
- if {![file-isexec $with_tclsh]} {
- set with_tclsh2 [get-define TCL_EXEC_PREFIX]/bin/tclsh
- if {![file-isexec $with_tclsh2]} {
- proj-warn "Cannot find a usable tclsh (tried: $with_tclsh $with_tclsh2)"
- } else {
- set with_tclsh $with_tclsh2
- }
- }
- }
- define TCLSH_CMD $with_tclsh
- if {$use_tcl} {
- # Set up the TCLLIBDIR
- #
- # 2024-10-28: calculation of TCLLIBDIR is now done via the shell
- # in main.mk (search it for T.tcl.env.sh) so that
- # static/hand-written makefiles which import main.mk do not have
- # to define that before importing main.mk. Even so, we export
- # TCLLIBDIR from here, which will cause the canonical makefile to
- # use this one rather than to re-calculate it at make-time.
- set tcllibdir [get-env TCLLIBDIR ""]
- if {"" eq $tcllibdir} {
- # Attempt to extract TCLLIBDIR from TCL's $auto_path
- if {"" ne $with_tclsh &&
- [catch {exec echo "puts stdout \$auto_path" | "$with_tclsh"} result] == 0} {
- foreach i $result {
- if {[file isdir $i]} {
- set tcllibdir $i/sqlite3
- break
- }
- }
- } else {
- proj-warn "Cannot determine TCLLIBDIR."
- # The makefile will fail fatally in this case if a target is
- # invoked which requires TCLLIBDIR.
- }
- }
- #if {"" ne $tcllibdir} { msg-result "TCLLIBDIR = ${tcllibdir}"; }
- define TCLLIBDIR $tcllibdir
- }; # find TCLLIBDIR
-
- if {[file-isexec $with_tclsh]} {
- msg-result "Using tclsh: $with_tclsh"
- if {$cfg ne ""} {
- define HAVE_TCL 1
- } else {
- proj-warn "Found tclsh but no tclConfig.sh."
- }
- }
- show-notices
- # If TCL is not found: if it was explicitly requested then fail
- # fatally, else just emit a warning. If we can find the APIs needed
- # to generate a working JimTCL then that will suffice for build-time
- # TCL purposes (see: proc sqlite-determine-codegen-tcl).
- if {![get-define HAVE_TCL] &&
- ([proj-opt-was-provided tcl] || [proj-opt-was-provided with-tcl])} {
- proj-fatal "TCL support was requested but no tclConfig.sh could be found."
- }
- if {"" eq $cfg} {
- proj-assert {0 == [get-define HAVE_TCL]}
- proj-indented-notice {
- WARNING: Cannot find a usable tclConfig.sh file. Use
- --with-tcl=DIR to specify a directory where tclConfig.sh can be
- found. SQLite does not use TCL internally, but some optional
- components require TCL, including tests and sqlite3_analyzer.
- }
- }
-}; # sqlite-check-tcl
-sqlite-check-tcl
-
-########################################################################
-# sqlite-determine-codegen-tcl checks which TCL to use as a code
-# generator. By default, prefer jimsh simply because we have it
-# in-tree (it's part of autosetup) unless --with-tclsh=X is used, in
-# which case prefer X.
-#
-# Returns the human-readable name of the TCL it selects. Fails fatally
-# if it cannot detect a TCL appropriate for code generation.
-#
-# Defines:
-#
-# - BTCLSH = the TCL shell used for code generation. It may set this
-# to an unexpanded makefile var name.
-#
-# - CFLAGS_JIMSH = any flags needed for buildng a BTCLSH-compatible
-# jimsh. The defaults may be passed on to configure as
-# CFLAGS_JIMSH=...
-set useJimForCodeGen 0 ; # Set to 1 when using jimsh for code generation.
- # May affect later decisions.
-proc sqlite-determine-codegen-tcl {} {
- rename sqlite-determine-codegen-tcl ""
- msg-result "Checking for TCL to use for code generation... "
- define CFLAGS_JIMSH [proj-get-env CFLAGS_JIMSH {-O1}]
- set cgtcl [opt-val with-tclsh jimsh]
- if {"jimsh" ne $cgtcl} {
- # When --with-tclsh=X is used, use that for all TCL purposes,
- # including in-tree code generation, per developer request.
- define BTCLSH "\$(TCLSH_CMD)"
- return $cgtcl
- }
- set flagsToRestore {CC CFLAGS AS_CFLAGS CPPFLAGS AS_CPPFLAGS LDFLAGS LINKFLAGS LIBS CROSS}
- define-push $flagsToRestore {
- # We have to swap CC to CC_FOR_BUILD for purposes of the various
- # [cc-...] tests below. Recall that --with-wasi-sdk may have
- # swapped out CC with one which is not appropriate for this block.
- # Per consulation with autosetup's creator, doing this properly
- # requires us to [define-push] the whole $flagsToRestore list
- # (plus a few others which are not relevant in this tree).
- #
- # These will get set to their previous values at the end of this
- # block.
- foreach flag $flagsToRestore {define $flag ""}
- define CC [get-define CC_FOR_BUILD]
- # These headers are technically optional for JimTCL but necessary if
- # we want to use it for code generation:
- set sysh [cc-check-includes dirent.h sys/time.h]
- # jimsh0.c hard-codes #define's for HAVE_DIRENT_H and
- # HAVE_SYS_TIME_H on the platforms it supports, so we do not
- # need to add -D... flags for those. We check for them here only
- # so that we can avoid the situation that we later, at
- # make-time, try to compile jimsh but it then fails due to
- # missing headers (i.e. fail earlier rather than later).
- if {$sysh && [cc-check-functions realpath]} {
- define-append CFLAGS_JIMSH -DHAVE_REALPATH
- define BTCLSH "\$(JIMSH)"
- set ::useJimForCodeGen 1
- } elseif {$sysh && [cc-check-functions _fullpath]} {
- # _fullpath() is a Windows API. It's not entirely clear
- # whether we need to add {-DHAVE_SYS_TIME_H -DHAVE_DIRENT_H}
- # to CFLAGS_JIMSH in this case. On MinGW32 we definitely do
- # not want to because it already hard-codes them. On _MSC_VER
- # builds it does not.
- define-append CFLAGS_JIMSH -DHAVE__FULLPATH
- define BTCLSH "\$(JIMSH)"
- set ::useJimForCodeGen 1
- } elseif {[file-isexec [get-define TCLSH_CMD]]} {
- set cgtcl [get-define TCLSH_CMD]
- define BTCLSH "\$(TCLSH_CMD)"
- } else {
- # One last-ditch effort to find TCLSH_CMD: use info from
- # tclConfig.sh to try to find a tclsh
- if {"" eq [get-define TCLSH_CMD]} {
- set tpre [get-define TCL_EXEC_PREFIX]
- if {"" ne $tpre} {
- set tv [get-define TCL_VERSION]
- if {[file-isexec "${tpre}/bin/tclsh${tv}"]} {
- define TCLSH_CMD "${tpre}/bin/tclsh${tv}"
- } elseif {[file-isexec "${tpre}/bin/tclsh"]} {
- define TCLSH_CMD "${tpre}/bin/tclsh"
- }
- }
- }
- set cgtcl [get-define TCLSH_CMD]
- if {![file-isexec $cgtcl]} {
- proj-fatal "Cannot find a tclsh to use for code generation."
- }
- define BTCLSH "\$(TCLSH_CMD)"
- }
- }; # CC swap-out
- return $cgtcl
-}; # sqlite-determine-codegen-tcl
-msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
-# /TCL
-########################################################################
-
-########################################################################
-# Thread safety?
-msg-checking "Support threadsafe operation? "
-proj-if-opt-truthy threadsafe {
- msg-result yes
- sqlite-add-feature-flag -DSQLITE_THREADSAFE=1
- if {![proj-check-function-in-lib pthread_create pthread]
- || ![proj-check-function-in-lib pthread_mutexattr_init pthread]} {
- user-error "Missing required pthread bits"
- }
- define LDFLAGS_PTHREAD [get-define lib_pthread_create]
- undefine lib_pthread_create
- # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if
- # found because it's in -lc on some platforms.
-} {
- msg-result no
- sqlite-add-feature-flag -DSQLITE_THREADSAFE=0
- define LDFLAGS_PTHREAD ""
-}
-
-########################################################################
-# Do we want temporary databases in memory?
-#
-# The test fixture likes to set SQLITE_TEMP_STORE on its own, so do
-# not set that feature flag unless it was explicitly provided to the
-# configure script.
-if {[proj-opt-was-provided with-tempstore]} {
- apply {{} {
- set ts [opt-val with-tempstore no]
- set tsn 1
- msg-checking "Use an in-RAM database for temporary tables? "
- switch -exact -- $ts {
- never { set tsn 0 }
- no { set tsn 1 }
- yes { set tsn 2 }
- always { set tsn 3 }
- default {
- user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always"
- }
- }
- msg-result $ts
- sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn
- }}
-}
-
-########################################################################
-# sqlite-check-line-editing jumps through proverbial hoops to try to
-# find a working line-editing library, setting:
-#
-# - HAVE_READLINE to 0 or 1
-# - HAVE_LINENOISE to 0, 1, or 2
-# - HAVE_EDITLINE to 0 or 1
-#
-# Only one of ^^^ those will be set to non-0.
-#
-# - LDFLAGS_READLINE = linker flags or empty string
-#
-# - CFLAGS_READLINE = compilation flags for clients or empty string.
-#
-# Note that LDFLAGS_READLINE and CFLAGS_READLINE may refer to
-# linenoise or editline, not necessarily libreadline. In some cases
-# it will set HAVE_READLINE=1 when it's really using editline, for
-# reasons described in this function's comments.
-#
-# Returns a string describing which line-editing approach to use, or
-# "none" if no option is available.
-#
-# Order of checks:
-#
-# 1) --with-linenoise trumps all others and skips all of the
-# complexities involved with the remaining options.
-#
-# 2) --editline trumps --readline
-#
-# 3) --disable-readline trumps --readline
-#
-# 4) Default to automatic search for optional readline
-#
-# 5) Try to find readline or editline. If it's not found AND the
-# corresponding --FEATURE flag was explicitly given, fail fatally,
-# else fail silently.
-proc sqlite-check-line-editing {} {
- rename sqlite-check-line-editing ""
- msg-result "Checking for line-editing capability..."
- define HAVE_READLINE 0
- define HAVE_LINENOISE 0
- define HAVE_EDITLINE 0
- define LDFLAGS_READLINE ""
- define CFLAGS_READLINE ""
- set failIfNotFound 0 ; # Gets set to 1 for explicit --FEATURE requests
- # so that we know whether to fail fatally or not
- # if the library is not found.
- set libsForReadline {readline edit} ; # -l<LIB> names to check for readline().
- # The libedit check changes this.
- set editLibName "readline" ; # "readline" or "editline"
- set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
- set dirLn [opt-val with-linenoise]
- if {"" ne $dirLn} {
- # Use linenoise from a copy of its sources (not a library)...
- if {![file isdir $dirLn]} {
- proj-fatal "--with-linenoise value is not a directory"
- }
- set lnH $dirLn/linenoise.h
- if {![file exists $lnH] } {
- proj-fatal "Cannot find linenoise.h in $dirLn"
- }
- set lnC ""
- set lnCOpts {linenoise-ship.c linenoise.c}
- foreach f $lnCOpts {
- if {[file exists $dirLn/$f]} {
- set lnC $dirLn/$f
- break;
- }
- }
- if {"" eq $lnC} {
- proj-fatal "Cannot find any of $lnCOpts in $dirLn"
- }
- set flavor ""
- set lnVal [proj-which-linenoise $lnH]
- switch -- $lnVal {
- 1 { set flavor "antirez" }
- 2 { set flavor "msteveb" }
- default {
- proj-fatal "Cannot determine the flavor of linenoise from $lnH"
- }
- }
- define CFLAGS_READLINE "-I$dirLn $lnC"
- define HAVE_LINENOISE $lnVal
- sqlite-add-shell-opt -DHAVE_LINENOISE=$lnVal
- if {$::useJimForCodeGen && 2 == $lnVal} {
- define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE]
- user-notice "Adding linenoise support to jimsh."
- }
- return "linenoise ($flavor)"
- } elseif {[opt-bool editline]} {
- # libedit mimics libreadline and on some systems does not have its
- # own header installed (instead, that of libreadline is used).
- #
- # shell.c historically expects HAVE_EDITLINE to be set for
- # libedit, but it then expects to see <editline/readline.h>, which
- # some system's don't actually have despite having libedit. If we
- # end up finding <editline/readline.h> below, we will use
- # -DHAVE_EDITLINE=1, else we will use -DHAVE_READLINE=1. In either
- # case, we will link against libedit.
- set failIfNotFound 1
- set libsForReadline {edit}
- set editLibName editline
- } elseif {![opt-bool readline]} {
- msg-result "Readline support explicitly disabled with --disable-readline"
- return "none"
- } elseif {[proj-opt-was-provided readline]} {
- # If an explicit --[enable-]readline was used, fail if it's not
- # found, else treat the feature as optional.
- set failIfNotFound 1
- }
-
- # Transform with-readline-header=X to with-readline-cflags=-I...
- set v [opt-val with-readline-header]
- proj-opt-set with-readline-header ""
- if {"" ne $v} {
- if {"auto" eq $v} {
- proj-opt-set with-readline-cflags auto
- } else {
- set v [file dirname $v]
- if {[string match */readline $v]} {
- # Special case: if the path includes .../readline/readline.h,
- # set the -I to one dir up from that because our sources
- # #include <readline/readline.h> or <editline/readline.h>.
- set v [file dirname $v]
- }
- proj-opt-set with-readline-cflags "-I$v"
- }
- }
-
- # Look for readline.h
- set rlInc [opt-val with-readline-cflags auto]
- if {"auto" eq $rlInc} {
- set rlInc ""
- if {$::isCrossCompiling} {
- # ^^^ this check is derived from the legacy configure script.
- proj-warn "Skipping check for readline.h because we're cross-compiling."
- } else {
- set dirs "[get-define prefix] /usr /usr/local /usr/local/readline /usr/contrib /mingw"
- set subdirs "include/$editLibName"
- if {"editline" eq $editLibName} {
- lappend subdirs include/readline
- # ^^^ editline, on some systems, does not have its own header,
- # and uses libreadline's header.
- }
- lappend subdirs include
- # ^^^ The dirs and subdirs lists are, except for the inclusion
- # of $prefix and editline, from the legacy configure script
- set rlInc [proj-search-for-header-dir readline.h \
- -dirs $dirs -subdirs $subdirs]
- if {"" ne $rlInc} {
- if {[string match */readline $rlInc]} {
- set rlInc [file dirname $rlInc]; # shell #include's <readline/readline.h>
- } elseif {[string match */editline $rlInc]} {
- set editLibDef HAVE_EDITLINE
- set rlInc [file dirname $rlInc]; # shell #include's <editline/readline.h>
- }
- set rlInc "-I${rlInc}"
- }
- }
- } elseif {"" ne $rlInc && ![string match *-I* $rlInc]} {
- proj-fatal "Argument to --with-readline-cflags is intended to be CFLAGS and contain -I..."
- }
-
- # If readline.h was found/specified, look for lib(readline|edit)...
- #
- # This is not quite straightforward because both libreadline and
- # libedit typically require some other library which (according to
- # legacy autotools-generated tests) provides tgetent(3). On some
- # systems that's built into libreadline/edit, on some (most?) its in
- # lib[n]curses, and on some it's in libtermcap.
- set rlLib ""
- if {"" ne $rlInc} {
- set rlLib [opt-val with-readline-ldflags]
- if {"" eq $rlLib || "auto" eq $rlLib} {
- set rlLib ""
- set libTerm ""
- if {[proj-check-function-in-lib tgetent "$editLibName ncurses curses termcap"]} {
- # ^^^ that libs list comes from the legacy configure script ^^^
- set libTerm [get-define lib_tgetent]
- undefine lib_tgetent
- }
- if {$editLibName eq $libTerm} {
- set rlLib $libTerm
- } elseif {[proj-check-function-in-lib readline $libsForReadline $libTerm]} {
- set rlLib [get-define lib_readline]
- lappend rlLib $libTerm
- undefine lib_readline
- }
- }
- }
-
- # If we found a library, configure the build to use it...
- if {"" ne $rlLib} {
- if {"editline" eq $editLibName && "HAVE_READLINE" eq $editLibDef} {
- # Alert the user that, despite outward appearances, we won't be
- # linking to the GPL'd libreadline. Presumably that distinction is
- # significant for those using --editline.
- proj-indented-notice {
- NOTE: the local libedit but uses <readline/readline.h> so we
- will compile with -DHAVE_READLINE=1 but will link with
- libedit.
- }
- }
- set rlLib [join $rlLib]
- set rlInc [join $rlInc]
- define LDFLAGS_READLINE $rlLib
- define CFLAGS_READLINE $rlInc
- proj-assert {$editLibDef in {HAVE_READLINE HAVE_EDITLINE}}
- proj-assert {$editLibName in {readline editline}}
- sqlite-add-shell-opt -D${editLibDef}=1
- msg-result "Using $editLibName flags: $rlInc $rlLib"
- # Check whether rl_completion_matches() has a signature we can use
- # and disable that sub-feature if it doesn't.
- if {![cctest \
- -cflags "$rlInc -D${editLibDef}" -libs $rlLib -nooutput 1 -source {
- #include <stdio.h>
- #ifdef HAVE_EDITLINE
- #include <editline/readline.h>
- #else
- #include <readline/readline.h>
- #endif
- static char * rcg(const char *z, int i){(void)z; (void)i; return 0;}
- int main(void) {
- char ** x = rl_completion_matches("one", rcg);
- (void)x;
- return 0;
- }
- }]} {
- proj-warn "readline-style completion disabled due to rl_completion_matches() signature mismatch"
- sqlite-add-shell-opt -DSQLITE_OMIT_READLINE_COMPLETION
- }
- return $editLibName
- }
-
- if {$failIfNotFound} {
- proj-fatal "Explicit --$editLibName failed to find a matching library."
- }
- return "none"
-}; # sqlite-check-line-editing
-msg-result "Line-editing support for the sqlite3 shell: [sqlite-check-line-editing]"
-
-proj-if-opt-truthy load-extension {
- if {[proj-check-function-in-lib dlopen dl]} {
- define LDFLAGS_DLOPEN [get-define lib_dlopen]
- undefine lib_dlopen
- } else {
- user-error "dlopen() not found. Use --disable-load-extension to bypass this check."
- }
-} {
- define LDFLAGS_DLOPEN ""
- sqlite-add-feature-flag {-DSQLITE_OMIT_LOAD_EXTENSION=1}
- msg-result "Disabling loadable extensions."
-}
-
-proj-if-opt-truthy math {
- if {![proj-check-function-in-lib ceil m]} {
- user-error "Cannot find libm functions. Use --disable-math to bypass this."
- }
- define LDFLAGS_MATH [get-define lib_ceil]
- undefine lib_ceil
- sqlite-add-feature-flag {-DSQLITE_ENABLE_MATH_FUNCTIONS}
- msg-result "Enabling math SQL functions [get-define LDFLAGS_MATH]"
-} {
- define LDFLAGS_MATH ""
- msg-result "Disabling math SQL functions"
-}
-
-########################################################################
-# ICU - International Components for Unicode
-#
-# Handles these flags:
-#
-# --with-icu-ldflags=LDFLAGS
-# --with-icu-cflags=CFLAGS
-# --with-icu-config[=auto | pkg-config | /path/to/icu-config]
-# --enable-icu-collations
-#
-# --with-icu-config values:
-#
-# - auto: use the first one of (pkg-config, icu-config) found on the
-# system.
-# - pkg-config: use only pkg-config to determine flags
-# - /path/to/icu-config: use that to determine flags
-#
-# If --with-icu-config is used as neither pkg-config nor icu-config
-# are found, fail fatally.
-#
-# If both --with-icu-ldflags and --with-icu-config are provided, they
-# are cumulative. If neither are provided, icu-collations is not
-# honored and a warning is emitted if it is provided.
-#
-# Design note: though we could automatically enable ICU if the
-# icu-config binary or (pkg-config icu-io) are found, we specifically
-# do not. ICU is always an opt-in feature.
-proc sqlite-check-icu {} {
- rename sqlite-check-icu ""
- define LDFLAGS_ICU [join [opt-val with-icu-ldflags ""]]
- define CFLAGS_ICU [join [opt-val with-icu-cflags ""]]
- if {[proj-opt-was-provided with-icu-config]} {
- set icuConfigBin [opt-val with-icu-config]
- set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config
- if {"auto" eq $icuConfigBin || "pkg-config" eq $icuConfigBin} {
- if {[pkg-config-init 0] && [pkg-config icu-io]} {
- # Maintenance reminder: historical docs say to use both of
- # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has
- # all of them on tested OSes.
- set tryIcuConfigBin 0
- define LDFLAGS_ICU [get-define PKG_ICU_IO_LDFLAGS]
- define-append LDFLAGS_ICU [get-define PKG_ICU_IO_LIBS]
- define CFLAGS_ICU [get-define PKG_ICU_IO_CFLAGS]
- } elseif {"pkg-config" eq $icuConfigBin} {
- proj-fatal "pkg-config cannot find package icu-io"
- } else {
- proj-assert {"auto" eq $icuConfigBin}
- }
- }
- if {$tryIcuConfigBin} {
- if {"auto" eq $icuConfigBin} {
- set icuConfigBin [proj-first-bin-of \
- /usr/local/bin/icu-config \
- /usr/bin/icu-config]
- if {"" eq $icuConfigBin} {
- proj-fatal "--with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary"
- }
- }
- if {[file-isexec $icuConfigBin]} {
- set x [exec $icuConfigBin --ldflags]
- if {"" eq $x} {
- proj-fatal "$icuConfigBin --ldflags returned no data"
- }
- define-append LDFLAGS_ICU $x
- set x [exec $icuConfigBin --cppflags]
- define-append CFLAGS_ICU $x
- } else {
- proj-fatal "--with-icu-config=$bin does not refer to an executable"
- }
- }
- }
- set ldflags [define LDFLAGS_ICU [string trim [get-define LDFLAGS_ICU]]]
- set cflags [define CFLAGS_ICU [string trim [get-define CFLAGS_ICU]]]
- if {"" ne $ldflags} {
- sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU
- msg-result "Enabling ICU support with flags: $ldflags $cflags"
- if {[opt-bool icu-collations]} {
- msg-result "Enabling ICU collations."
- sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU_COLLATIONS
- # Recall that shell.c builds with sqlite3.c
- }
- } elseif {[opt-bool icu-collations]} {
- proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
- } else {
- msg-result "ICU support is disabled."
- }
-}; # sqlite-check-icu
-sqlite-check-icu
-
-########################################################################
-# Check for the Emscripten SDK for building the web-based wasm
-# components. The core lib and tools do not require this but ext/wasm
-# does.
-apply {{} {
- if {$::autosetup(srcdir) ne $::autosetup(builddir)} {
- # The EMSDK pieces require writing to the original source tree
- # even when doing an out-of-tree build. The ext/wasm pieces do not
- # support an out-of-tree build so we catch that case and treat it
- # as if EMSDK were not found.
- msg-result "Out-of tree build: not checking for EMSDK."
- define EMCC_WRAPPER ""
- return
- }
- set emccsh $::srcdir/tool/emcc.sh
- if {![get-define HAVE_WASI_SDK] && [proj-check-emsdk]} {
- define EMCC_WRAPPER $emccsh
- proj-make-from-dot-in $emccsh
- catch {exec chmod u+x $emccsh}
- } else {
- define EMCC_WRAPPER ""
- file delete -force $emccsh
- }
-}}
-
-########################################################################
-# Check for log(3) in libm and die with an error if it is not
-# found. $featureName should be the feature name which requires that
-# function (it's used only in error messages). defines LDFLAGS_MATH to
-# the required linker flags (which may be empty even if the math APIs
-# are found, depending on the OS).
-proc affirm-have-math {featureName} {
- if {"" eq [get-define LDFLAGS_MATH ""]} {
- if {![msg-quiet proj-check-function-in-lib log m]} {
- user-error "Missing math APIs for $featureName"
- }
- define LDFLAGS_MATH [get-define lib_log ""]
- undefine lib_log
- }
-}
-
-########################################################################
-# Handle various SQLITE_ENABLE_... feature flags.
-msg-result "Feature flags..."
-foreach {boolFlag featureFlag ifSetEvalThis} {
- all {} {
- # The 'all' option must be first in this list.
- proj-opt-set fts4
- proj-opt-set fts5
- proj-opt-set geopoly
- proj-opt-set rtree
- proj-opt-set session
- }
- fts4 -DSQLITE_ENABLE_FTS4 {affirm-have-math fts4}
- fts5 -DSQLITE_ENABLE_FTS5 {affirm-have-math fts5}
- geopoly -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree}
- rtree -DSQLITE_ENABLE_RTREE {}
- session {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {}
- update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {}
- memsys5 -DSQLITE_ENABLE_MEMSYS5 {}
- memsys3 {} {
- if {[opt-bool memsys5]} {
- proj-warn "not enabling memsys3 because memsys5 is enabled."
- expr 0
- } else {
- sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
- }
- }
- scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
-} {
- proj-if-opt-truthy $boolFlag {
- sqlite-add-feature-flag $featureFlag
- if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
- msg-result " + $boolFlag"
- }
- } {
- if {"all" ne $boolFlag} {
- msg-result " - $boolFlag"
- }
- }
-}
-
-########################################################################
-# Invert the above loop's logic for some SQLITE_OMIT_... cases. If
-# config option $boolFlag is false, [sqlite-add-feature-flag
-# $featureFlag], where $featureFlag is intended to be
-# -DSQLITE_OMIT_...
-foreach {boolFlag featureFlag} {
- json -DSQLITE_OMIT_JSON
-} {
- if {[proj-opt-truthy $boolFlag]} {
- msg-result " + $boolFlag"
- } else {
- sqlite-add-feature-flag $featureFlag
- msg-result " - $boolFlag"
- }
-}
-
-#########################################################################
-# Show the final feature flag sets:
-apply {{} {
- set oFF [get-define OPT_FEATURE_FLAGS]
- if {"" ne $oFF} {
- define OPT_FEATURE_FLAGS [lsort -unique $oFF]
- msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
- }
- set oFF [get-define OPT_SHELL]
- if {"" ne $oFF} {
- define OPT_SHELL [lsort -unique $oFF]
- msg-result "Shell options: [get-define OPT_SHELL]"
- }
- unset oFF
-}}
-
-########################################################################
-# "Re-export" the autoconf-conventional --XYZdir flags into something
-# which is more easily overridable from a make invocation. See the docs
-# for [proj-remap-autoconf-dir-vars] for the explanation of why.
-#
-# We do this late in the config process, immediately before we export
-# the Makefile and other generated files, so that configure tests
-# which make make use of the autotools-conventional flags
-# (e.g. [proj-check-rpath]) may do so before we "mangle" them here.
-proj-remap-autoconf-dir-vars
-
-########################################################################
-# Generate the output files.
-#
-# Potential TODO (unclear): in sqlite3.pc.in, do we need to include
-# any CFLAGS_READLINE, CFLAGS_ZLIB, etc in its "Cflags:" section?
-proj-make-from-dot-in -touch Makefile sqlite3.pc
-make-config-header sqlite_cfg.h \
- -bare {SIZEOF_* HAVE_DECL_*} \
- -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG
- TARGET_* USE_GCOV TCL_*} \
- -auto {HAVE_* PACKAGE_*} \
- -none *
-proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@
-
-########################################################################
-# Some build-dev/debug-only output
-proj-if-opt-truthy dump-defines {
- make-config-header $::DUMP_DEFINES_TXT \
- -bare {SQLITE_OS* SQLITE_DEBUG USE_*} \
- -str {BIN_* CC LD AR LDFLAG* OPT_*} \
- -auto {*}
- # achtung: ^^^^ whichever SQLITE_OS_foo flag which is set to 0 will
- # get _undefined_ here unless it's part of the -bare set.
- if {"" ne $DUMP_DEFINES_JSON} {
- msg-result "--dump-defines is creating $::DUMP_DEFINES_JSON"
- ########################################################################
- # Dump config-defines.json...
- # Demonstrate (mis?)handling of spaces in JSON-export array values:
- # define-append OPT_FOO.list {"-DFOO=bar baz" -DBAR="baz barre"}
- define OPT_FEATURE_FLAGS.list [get-define OPT_FEATURE_FLAGS]
- define OPT_SHELL.list [get-define OPT_SHELL]
- set dumpDefsOpt {
- -bare {SIZEOF_* HAVE_DECL_*}
- -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG TARGET_* USE_GCOV TCL_*}
- -array {*.list}
- -auto {OPT_* PACKAGE_* HAVE_*}
- }
- if {[opt-bool defines-json-include-lowercase]} {
- lappend dumpDefsOpt -none {lib_*} ; # remnants from proj-check-function-in-lib and friends
- lappend dumpDefsOpt -auto {[a-z]*}
- }
- lappend dumpDefsOpt -none *
- proj-dump-defs-json $DUMP_DEFINES_JSON {*}$dumpDefsOpt
- undefine OPT_FEATURE_FLAGS.list
- undefine OPT_SHELL.list
- }
-}
+define LINK_TOOLS_DYNAMICALLY [proj-opt-was-provided dynlink-tools]
-########################################################################
-# Perform some high-level validation on the generated files...
-#
-# 1) Ensure that no unresolved @VAR@ placeholders are in files which
-# use those.
-#
-# 2) TBD
-apply {{} {
- # Check #1: ensure that files which get filtered for @VAR@ do not
- # contain any unresolved @VAR@ refs. That may indicate an
- # unexported/unused var or a typo.
- foreach f "Makefile sqlite3.pc $::srcdir/tool/emcc.sh" {
- if {![file exists $f]} continue
- set lnno 1
- foreach line [proj-file-content-list $f] {
- if {[regexp {(@[A-Za-z_]+@)} $line match]} {
- error "Unresolved reference to $match at line $lnno of $f"
- }
- incr lnno
- }
- }
-}}
+proj-check-rpath
+sqlite-handle-soname
+sqlite-handle-debug
+sqlite-handle-tcl
+sqlite-handle-threadsafe
+sqlite-handle-tempstore
+sqlite-handle-line-editing
+sqlite-handle-load-extension
+sqlite-handle-math
+sqlite-handle-icu
+sqlite-handle-emsdk
+sqlite-common-late-stage-config
+sqlite-dump-defines
diff --git a/autoconf/INSTALL b/autoconf/INSTALL
deleted file mode 100644
index a1e89e18a..000000000
--- a/autoconf/INSTALL
+++ /dev/null
@@ -1,370 +0,0 @@
-Installation Instructions
-*************************
-
-Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
-Inc.
-
- Copying and distribution of this file, with or without modification,
-are permitted in any medium without royalty provided the copyright
-notice and this notice are preserved. This file is offered as-is,
-without warranty of any kind.
-
-Basic Installation
-==================
-
- Briefly, the shell commands `./configure; make; make install' should
-configure, build, and install this package. The following
-more-detailed instructions are generic; see the `README' file for
-instructions specific to this package. Some packages provide this
-`INSTALL' file but do not implement all of the features documented
-below. The lack of an optional feature in a given package is not
-necessarily a bug. More recommendations for GNU packages can be found
-in *note Makefile Conventions: (standards)Makefile Conventions.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation. It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
- It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring. Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.
-
- If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
- The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'. You need `configure.ac' if
-you want to change it or regenerate `configure' using a newer version
-of `autoconf'.
-
- The simplest way to compile this package is:
-
- 1. `cd' to the directory containing the package's source code and type
- `./configure' to configure the package for your system.
-
- Running `configure' might take a while. While running, it prints
- some messages telling which features it is checking for.
-
- 2. Type `make' to compile the package.
-
- 3. Optionally, type `make check' to run any self-tests that come with
- the package, generally using the just-built uninstalled binaries.
-
- 4. Type `make install' to install the programs and any data files and
- documentation. When installing into a prefix owned by root, it is
- recommended that the package be configured and built as a regular
- user, and only the `make install' phase executed with root
- privileges.
-
- 5. Optionally, type `make installcheck' to repeat any self-tests, but
- this time using the binaries in their final installed location.
- This target does not install anything. Running this target as a
- regular user, particularly if the prior `make install' required
- root privileges, verifies that the installation completed
- correctly.
-
- 6. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
-
- 7. Often, you can also type `make uninstall' to remove the installed
- files again. In practice, not all packages have tested that
- uninstallation works correctly, even though it is required by the
- GNU Coding Standards.
-
- 8. Some packages, particularly those that use Automake, provide `make
- distcheck', which can by used by developers to test that all other
- targets like `make install' and `make uninstall' work correctly.
- This target is generally not run by end users.
-
-Compilers and Options
-=====================
-
- Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. Run `./configure --help'
-for details on some of the pertinent environment variables.
-
- You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment. Here
-is an example:
-
- ./configure CC=c99 CFLAGS=-g LIBS=-lposix
-
- *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
- You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you can use GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'. This
-is known as a "VPATH" build.
-
- With a non-GNU `make', it is safer to compile the package for one
-architecture at a time in the source code directory. After you have
-installed the package for one architecture, use `make distclean' before
-reconfiguring for another architecture.
-
- On MacOS X 10.5 and later systems, you can create libraries and
-executables that work on multiple system types--known as "fat" or
-"universal" binaries--by specifying multiple `-arch' options to the
-compiler but only a single `-arch' option to the preprocessor. Like
-this:
-
- ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
- CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
- CPP="gcc -E" CXXCPP="g++ -E"
-
- This is not guaranteed to produce working output in all cases, you
-may have to build one architecture at a time and combine the results
-using the `lipo' tool if you have problems.
-
-Installation Names
-==================
-
- By default, `make install' installs the package's commands under
-`/usr/local/bin', include files under `/usr/local/include', etc. You
-can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX', where PREFIX must be an
-absolute file name.
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-pass the option `--exec-prefix=PREFIX' to `configure', the package uses
-PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files still use the regular prefix.
-
- In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
-kinds of files. Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them. In general, the
-default for these options is expressed in terms of `${prefix}', so that
-specifying just `--prefix' will affect all of the other directory
-specifications that were not explicitly provided.
-
- The most portable way to affect installation locations is to pass the
-correct locations to `configure'; however, many packages provide one or
-both of the following shortcuts of passing variable assignments to the
-`make install' command line to change installation locations without
-having to reconfigure or recompile.
-
- The first method involves providing an override variable for each
-affected directory. For example, `make install
-prefix=/alternate/directory' will choose an alternate location for all
-directory configuration variables that were expressed in terms of
-`${prefix}'. Any directories that were specified during `configure',
-but not in terms of `${prefix}', must each be overridden at install
-time for the entire installation to be relocated. The approach of
-makefile variable overrides for each directory variable is required by
-the GNU Coding Standards, and ideally causes no recompilation.
-However, some platforms have known limitations with the semantics of
-shared libraries that end up requiring recompilation when using this
-method, particularly noticeable in packages that use GNU Libtool.
-
- The second method involves providing the `DESTDIR' variable. For
-example, `make install DESTDIR=/alternate/directory' will prepend
-`/alternate/directory' before all installation names. The approach of
-`DESTDIR' overrides is not required by the GNU Coding Standards, and
-does not work on platforms that have drive letters. On the other hand,
-it does better at avoiding recompilation issues, and works well even
-when some directory options were not specified in terms of `${prefix}'
-at `configure' time.
-
-Optional Features
-=================
-
- If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
- Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System). The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
- For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
- Some packages offer the ability to configure how verbose the
-execution of `make' will be. For these packages, running `./configure
---enable-silent-rules' sets the default to minimal output, which can be
-overridden with `make V=1'; while running `./configure
---disable-silent-rules' sets the default to verbose, which can be
-overridden with `make V=0'.
-
-Particular systems
-==================
-
- On HP-UX, the default C compiler is not ANSI C compatible. If GNU
-CC is not installed, it is recommended to use the following options in
-order to use an ANSI C compiler:
-
- ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
-
-and if that doesn't work, install pre-built binaries of GCC for HP-UX.
-
- HP-UX `make' updates targets which have the same time stamps as
-their prerequisites, which makes it generally unusable when shipped
-generated files such as `configure' are involved. Use GNU `make'
-instead.
-
- On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
-parse its `<wchar.h>' header file. The option `-nodtk' can be used as
-a workaround. If GNU CC is not installed, it is therefore recommended
-to try
-
- ./configure CC="cc"
-
-and if that doesn't work, try
-
- ./configure CC="cc -nodtk"
-
- On Solaris, don't put `/usr/ucb' early in your `PATH'. This
-directory contains several dysfunctional programs; working variants of
-these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
-in your `PATH', put it _after_ `/usr/bin'.
-
- On Haiku, software installed for all users goes in `/boot/common',
-not `/usr/local'. It is recommended to use the following options:
-
- ./configure --prefix=/boot/common
-
-Specifying the System Type
-==========================
-
- There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on. Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
- CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
- OS
- KERNEL-OS
-
- See the file `config.sub' for the possible values of each field. If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
- If you are _building_ compiler tools for cross-compiling, you should
-use the option `--target=TYPE' to select the type of system they will
-produce code for.
-
- If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
- If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists. Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
- Variables not defined in a site shell script can be set in the
-environment passed to `configure'. However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost. In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'. For example:
-
- ./configure CC=/usr/local2/bin/gcc
-
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-Unfortunately, this technique does not work for `CONFIG_SHELL' due to
-an Autoconf bug. Until the bug is fixed you can use this workaround:
-
- CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
-
-`configure' Invocation
-======================
-
- `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
- Print a summary of all of the options to `configure', and exit.
-
-`--help=short'
-`--help=recursive'
- Print a summary of the options unique to this package's
- `configure', and exit. The `short' variant lists options used
- only in the top level, while the `recursive' variant lists options
- also present in any nested packages.
-
-`--version'
-`-V'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`--cache-file=FILE'
- Enable the cache: use and save the results of the tests in FILE,
- traditionally `config.cache'. FILE defaults to `/dev/null' to
- disable caching.
-
-`--config-cache'
-`-C'
- Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
- Do not print messages saying which checks are being made. To
- suppress all normal output, redirect it to `/dev/null' (any error
- messages will still be shown).
-
-`--srcdir=DIR'
- Look for the package's source code in directory DIR. Usually
- `configure' can determine that directory automatically.
-
-`--prefix=DIR'
- Use DIR as the installation prefix. *note Installation Names::
- for more details, including other options available for fine-tuning
- the installation locations.
-
-`--no-create'
-`-n'
- Run the configure checks, but stop before creating any output
- files.
-
-`configure' also accepts some other, not widely useful, options. Run
-`configure --help' for more details.
-
diff --git a/autoconf/Makefile.am b/autoconf/Makefile.am
deleted file mode 100644
index 1eaa560ff..000000000
--- a/autoconf/Makefile.am
+++ /dev/null
@@ -1,20 +0,0 @@
-
-AM_CFLAGS = @BUILD_CFLAGS@
-lib_LTLIBRARIES = libsqlite3.la
-libsqlite3_la_SOURCES = sqlite3.c
-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
-
-bin_PROGRAMS = sqlite3
-sqlite3_SOURCES = shell.c sqlite3.h
-EXTRA_sqlite3_SOURCES = sqlite3.c
-sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
-sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
-sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_DQS=0 -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)
-
-include_HEADERS = sqlite3.h sqlite3ext.h
-
-EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback
-pkgconfigdir = ${libdir}/pkgconfig
-pkgconfig_DATA = sqlite3.pc
-
-man_MANS = sqlite3.1
diff --git a/autoconf/Makefile.in b/autoconf/Makefile.in
new file mode 100644
index 000000000..8e09b9c61
--- /dev/null
+++ b/autoconf/Makefile.in
@@ -0,0 +1,248 @@
+########################################################################
+# This is a main makefile for the "autoconf" bundle of SQLite. This is
+# a trimmed-down version of the canonical makefile, devoid of most
+# documentation. For the full docs, see /main.mk in the canonical
+# source tree.
+#
+# Maintenance reminders:
+#
+# - To keep this working with an out-of-tree build, be sure to prefix
+# input file names with $(TOP)/ where appropriate (which is most
+# places).
+#
+# - The original/canonical recipes can be found in /main.mk in the
+# canonical source tree.
+all:
+
+TOP = @abs_top_srcdir@
+
+PACKAGE_VERSION = @PACKAGE_VERSION@
+
+#
+# Filename extensions for binaries and libraries
+#
+B.exe = @BUILD_EXEEXT@
+T.exe = @TARGET_EXEEXT@
+B.dll = @BUILD_DLLEXT@
+T.dll = @TARGET_DLLEXT@
+B.lib = @BUILD_LIBEXT@
+T.lib = @TARGET_LIBEXT@
+
+#
+# Autotools-compatibility dirs
+#
+prefix = @prefix@
+datadir = @datadir@
+mandir = @mandir@
+includedir = @includedir@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+
+#
+# Required binaries
+#
+INSTALL = @BIN_INSTALL@
+AR = @AR@
+AR.flags = cr
+CC = @CC@
+
+
+ENABLE_LIB_SHARED = @ENABLE_LIB_SHARED@
+ENABLE_LIB_STATIC = @ENABLE_LIB_STATIC@
+
+CFLAGS = @CFLAGS@ @CPPFLAGS@
+#
+# $(LDFLAGS.configure) represents any LDFLAGS=... the client passes to
+# configure. See main.mk.
+#
+LDFLAGS.configure = @LDFLAGS@
+
+CFLAGS.core = @SH_CFLAGS@
+LDFLAGS.shlib = @SH_LDFLAGS@
+LDFLAGS.zlib = @LDFLAGS_ZLIB@
+LDFLAGS.math = @LDFLAGS_MATH@
+LDFLAGS.rpath = @LDFLAGS_RPATH@
+LDFLAGS.pthread = @LDFLAGS_PTHREAD@
+LDFLAGS.dlopen = @LDFLAGS_DLOPEN@
+LDFLAGS.readline = @LDFLAGS_READLINE@
+CFLAGS.readline = @CFLAGS_READLINE@
+LDFLAGS.rt = @LDFLAGS_RT@
+LDFLAGS.icu = @LDFLAGS_ICU@
+CFLAGS.icu = @CFLAGS_ICU@
+
+# When cross-compiling, we need to avoid the -s flag because it only
+# works on the build host's platform.
+INSTALL.strip.1 = $(INSTALL)
+INSTALL.strip.0 = $(INSTALL) -s
+INSTALL.strip = $(INSTALL.strip.@IS_CROSS_COMPILING@)
+INSTALL.noexec = $(INSTALL) -m 0644
+
+install-dir.bin = $(DESTDIR)$(bindir)
+install-dir.lib = $(DESTDIR)$(libdir)
+install-dir.include = $(DESTDIR)$(includedir)
+install-dir.pkgconfig = $(DESTDIR)$(libdir)/pkgconfig
+install-dir.man1 = $(DESTDIR)$(mandir)/man1
+install-dir.all = $(install-dir.bin) $(install-dir.include) \
+ $(install-dir.lib) $(install-dir.man1) \
+ $(install-dir.pkgconfig)
+$(install-dir.all):
+ if [ ! -d "$@" ]; then $(INSTALL) -d "$@"; fi
+# ^^^^ on some platforms, install -d fails if the target already exists.
+
+
+#
+# Vars with the AS_ prefix are specifically related to AutoSetup.
+#
+# AS_AUTO_DEF is the main configure script.
+#
+AS_AUTO_DEF = $(TOP)/auto.def
+
+#
+# Shell commands to re-run $(TOP)/configure with the same args it was
+# invoked with to produce this makefile.
+#
+AS_AUTORECONFIG = @SQLITE_AUTORECONFIG@
+Makefile: $(TOP)/Makefile.in $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+sqlite3.pc: $(TOP)/sqlite3.pc.in $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+sqlite_cfg.h: $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+#
+# CFLAGS for sqlite3$(T.exe)
+#
+SHELL_OPT ?= @OPT_SHELL@
+
+#
+# Library-level feature flags
+#
+OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
+
+LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@
+# soname: see https://sqlite.org/src/forumpost/5a3b44f510df8ded
+LDFLAGS.libsqlite3.os-specific = @LDFLAGS_MAC_CVERSION@ @LDFLAGS_OUT_IMPLIB@
+# os-specific: see
+# - https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7
+# - https://sqlite.org/forum/forumpost/0c7fc097b2
+
+LDFLAGS.libsqlite3 = \
+ $(LDFLAGS.rpath) $(LDFLAGS.pthread) \
+ $(LDFLAGS.math) $(LDFLAGS.dlopen) \
+ $(LDFLAGS.zlib) $(LDFLAGS.icu) \
+ $(LDFLAGS.rt) $(LDFLAGS.configure)
+CFLAGS.libsqlite3 = -I. $(CFLAGS.core) $(CFLAGS.icu) $(OPT_FEATURE_FLAGS)
+
+sqlite3.o: $(TOP)/sqlite3.h $(TOP)/sqlite3.c
+ $(CC) -c $(TOP)/sqlite3.c -o $@ $(CFLAGS) $(CFLAGS.libsqlite3)
+
+libsqlite3.LIB = libsqlite3$(T.lib)
+libsqlite3.SO = libsqlite3$(T.dll)
+
+$(libsqlite3.SO): sqlite3.o
+ $(CC) -o $@ sqlite3.o $(LDFLAGS.shlib) \
+ $(LDFLAGS) $(LDFLAGS.libsqlite3) \
+ $(LDFLAGS.libsqlite3.os-specific) $(LDFLAGS.libsqlite3.soname)
+all: $(libsqlite3.SO)
+
+$(libsqlite3.LIB): sqlite3.o
+ $(AR) $(AR.flags) $@ sqlite3.o
+all: $(libsqlite3.LIB)
+
+install-so-1: $(install-dir.lib) $(libsqlite3.SO)
+ $(INSTALL) $(libsqlite3.SO) "$(install-dir.lib)"
+ @echo "Setting up $(libsqlite3.SO) version symlinks..."; \
+ cd "$(install-dir.lib)" || exit $$?; \
+ if [ x.dylib = x$(T.dll) ]; then \
+ rm -f libsqlite3.0$(T.dll) libsqlite3.$(PACKAGE_VERSION)$(T.dll) || exit $$?; \
+ dllname=libsqlite3.$(PACKAGE_VERSION)$(T.dll); \
+ mv $(libsqlite3.SO) $$dllname || exit $$?; \
+ ln -s $$dllname $(libsqlite3.SO) || exit $$?; \
+ ln -s $$dllname libsqlite3.0$(T.dll) || exit $$?; \
+ ls -la $$dllname $(libsqlite3.SO) libsqlite3.0$(T.dll); \
+ else \
+ rm -f $(libsqlite3.SO).0 $(libsqlite3.SO).$(PACKAGE_VERSION) || exit $$?; \
+ mv $(libsqlite3.SO) $(libsqlite3.SO).$(PACKAGE_VERSION) || exit $$?; \
+ ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO) || exit $$?; \
+ ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0 || exit $$?; \
+ ls -la $(libsqlite3.SO) $(libsqlite3.SO).[03]*; \
+ if [ -e $(libsqlite3.SO).0.8.6 ]; then \
+ echo "ACHTUNG: legacy libtool-compatible install found. Re-linking it..."; \
+ rm -f libsqlite3.la $(libsqlite3.SO).0.8.6 || exit $$?; \
+ ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0.8.6 || exit $$?; \
+ ls -la $(libsqlite3.SO).0.8.6; \
+ elif [ x1 = "x$(INSTALL_SO_086_LINK)" ]; then \
+ echo "ACHTUNG: installing legacy libtool-style links because INSTALL_SO_086_LINK=1"; \
+ rm -f libsqlite3.la $(libsqlite3.SO).0.8.6 || exit $$?; \
+ ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0.8.6 || exit $$?; \
+ ls -la $(libsqlite3.SO).0.8.6; \
+ fi; \
+ fi
+
+install-so-0 install-so-:
+install-so: install-so-$(ENABLE_LIB_SHARED)
+install: install-so
+
+install-lib-1: $(install-dir.lib) $(libsqlite3.LIB)
+ $(INSTALL.noexec) $(libsqlite3.LIB) "$(install-dir.lib)"
+install-lib-0 install-lib-:
+install-lib: install-lib-$(ENABLE_LIB_STATIC)
+install: install-lib
+
+
+sqlite3$(T.exe): $(TOP)/shell.c $(TOP)/sqlite3.c
+ $(CC) -o $@ \
+ $(TOP)/shell.c $(TOP)/sqlite3.c \
+ -I. $(OPT_FEATURE_FLAGS) $(SHELL_OPT) \
+ $(CFLAGS) $(CFLAGS.readline) $(CFLAGS.icu) \
+ $(LDFLAGS) $(LDFLAGS.libsqlite3) $(LDFLAGS.readline)
+all: sqlite3$(T.exe)
+
+install-shell: sqlite3$(T.exe) $(install-dir.bin)
+ $(INSTALL.strip) sqlite3$(T.exe) "$(install-dir.bin)"
+install: install-shell
+
+install-headers: $(TOP)/sqlite3.h $(install-dir.include)
+ $(INSTALL.noexec) $(TOP)/sqlite3.h $(TOP)/sqlite3ext.h "$(install-dir.include)"
+install: install-headers
+
+install-pc: sqlite3.pc $(install-dir.pkgconfig)
+ $(INSTALL.noexec) sqlite3.pc "$(install-dir.pkgconfig)"
+install: install-pc
+
+install-man1: $(TOP)/sqlite3.1 $(install-dir.man1)
+ $(INSTALL.noexec) $(TOP)/sqlite3.1 "$(install-dir.man1)"
+install: install-man1
+
+clean:
+ rm -f *.o sqlite3$(T.exe)
+ rm -f $(libsqlite3.LIB) $(libsqlite3.SO) $(libsqlite3.SO).a
+
+distclean: clean
+ rm -f jimsh0$(T.exe) config.* sqlite3.pc
+
+DIST_FILES := \
+ README.txt VERSION \
+ auto.def autosetup configure tea \
+ sqlite3.h sqlite3.c shell.c sqlite3ext.h \
+ Makefile.in Makefile.msc Makefile.fallback \
+ sqlite3.rc sqlite3rc.h Replace.cs \
+ sqlite3.pc.in sqlite3.1
+
+# Maintenance note: dist_name must be sqlite-$(PACKAGE_VERSION) so
+# that tool/mkautoconfamal.sh knows how to find it.
+dist_name = sqlite-$(PACKAGE_VERSION)
+dist_tarball = $(dist_name).tar.gz
+dist:
+ rm -fr $(dist_name)
+ mkdir -p $(dist_name)
+ cp -rp $(DIST_FILES) $(dist_name)/.
+ tar czf $(dist_tarball) $(dist_name)
+ rm -fr $(dist_name)
+ ls -l $(dist_tarball)
diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc
index 1f0e42db4..47e0a83af 100644
--- a/autoconf/Makefile.msc
+++ b/autoconf/Makefile.msc
@@ -1087,5 +1087,6 @@ $(LIBRESOBJS): $(TOP)\sqlite3.rc rcver.vc $(SQLITE3H)
clean:
del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
- del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q sqlite3.def tclsqlite3.def 2>NUL
del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
diff --git a/autoconf/README.first b/autoconf/README.first
index 5c2ea0a70..75c4a76d6 100644
--- a/autoconf/README.first
+++ b/autoconf/README.first
@@ -1,11 +1,12 @@
-This directory contains components use to build an autoconf-ready package
-of the SQLite amalgamation: sqlite-autoconf-30XXXXXX.tar.gz
+This directory contains components used to build an autoconf-like
+package of the SQLite amalgamation: sqlite-autoconf-30XXXXXX.tar.gz
-To build the autoconf amalgamation, run from the top-level:
+To build the autoconf amalgamation, run from the top of the canonical
+source tree:
./configure
make amalgamation-tarball
-The amalgamation-tarball target (also available in "main.mk") runs the
-script tool/mkautoconfamal.sh which does the work. Refer to that script
-for details.
+The amalgamation-tarball target (available in "main.mk") runs the
+script tool/mkautoconfamal.sh which does the work. Refer to that
+script for details.
diff --git a/autoconf/README.txt b/autoconf/README.txt
index b3d351074..646c0a121 100644
--- a/autoconf/README.txt
+++ b/autoconf/README.txt
@@ -4,7 +4,7 @@ This package contains:
* the sqlite3.h and sqlite3ext.h header files that define the C-language
interface to the sqlite3.c library file
* the shell.c file used to build the sqlite3 command-line shell program
- * autoconf/automake installation infrastucture for building on POSIX
+ * autoconf-like installation infrastucture for building on POSIX
compliant systems
* a Makefile.msc, sqlite3.rc, and Replace.cs for building with Microsoft
Visual C++ on Windows
@@ -19,8 +19,10 @@ using only generic tools and without having to install TCL. The purpose
of this package is to provide that capability.
This package contains a pre-build SQLite amalgamation file "sqlite3.c"
-(and its associated header file "sqlite3.h"). Because the amalgamation
-has been pre-built, no TCL is required.
+(and its associated header file "sqlite3.h"). Because the
+amalgamation has been pre-built, no TCL is required for the code
+generate (the configure script itself is written in TCL but it can use
+the embedded copy of JimTCL).
REASONS TO USE THE CANONICAL BUILD SYSTEM RATHER THAN THIS PACKAGE
==================================================================
@@ -47,14 +49,12 @@ SUMMARY OF HOW TO BUILD USING THIS PACKAGE
BUILDING ON POSIX
=================
-The generic installation instructions for autoconf/automake are found
-in the INSTALL file.
+The configure script follows common conventions, making it easy
+to use for anyone who has configured a software tree before.
+It supports a number of build-time flags, the full list of which
+can be seen by running:
-The following SQLite specific boolean options are supported:
-
- --enable-readline use readline in shell tool [default=yes]
- --enable-threadsafe build a thread-safe library [default=yes]
- --enable-dynamic-extensions support loadable extensions [default=yes]
+ ./configure --help
The default value for the CFLAGS variable (options passed to the C
compiler) includes debugging symbols in the build, resulting in larger
@@ -65,10 +65,11 @@ line like this:
to produce a smaller installation footprint.
-Other SQLite compilation parameters can also be set using CFLAGS. For
+Many SQLite compilation parameters can be defined by passing flags
+to the configure script. Others may be passed on in the CFLAGS. For
example:
- $ CFLAGS="-Os -DSQLITE_THREADSAFE=0" ./configure
+ $ CFLAGS="-Os -DSQLITE_OMIT_DEPRECATED" ./configure
BUILDING WITH MICROSOFT VISUAL C++
diff --git a/autoconf/auto.def b/autoconf/auto.def
new file mode 100644
index 000000000..42af1b459
--- /dev/null
+++ b/autoconf/auto.def
@@ -0,0 +1,101 @@
+#/do/not/tclsh
+# ^^^ help out editors which guess this file's content type.
+#
+# This is the main autosetup-compatible configure script for the
+# "autoconf" bundle of the SQLite project.
+#
+# This script must be kept compatible with JimTCL, a copy of which is
+# included in this source tree as ./autosetup/jimsh0.c.
+#
+use sqlite-config
+
+options {
+ # <build-modes>
+ static=1 => {Disable build of static library}
+ shared=1 => {Disable build of shared library}
+ # </build-modes>
+ # <lib-feature>
+ threadsafe=1 => {Disable mutexing}
+ with-tempstore:=no => {Use an in-RAM database for temporary tables: never,no,yes,always}
+ load-extension=1 => {Disable loading of external extensions}
+ math=1 => {Disable math functions}
+ json=1 => {Disable JSON functions}
+ memsys5 => {Enable MEMSYS5}
+ memsys3 => {Enable MEMSYS3}
+ fts3 => {Enable the FTS3 extension}
+ fts4 => {Enable the FTS4 extension}
+ fts5 => {Enable the FTS5 extension}
+ update-limit => {Enable the UPDATE/DELETE LIMIT clause}
+ geopoly => {Enable the GEOPOLY extension}
+ rtree => {Enable the RTREE extension}
+ session => {Enable the SESSION extension}
+ all => {Enable FTS4, FTS5, Geopoly, RTree, Sessions}
+ # </lib-feature>
+ # <line-editing>
+ readline=1 => {Disable readline support}
+ # --with-readline-lib is a backwards-compatible alias for
+ # --with-readline-ldflags
+ with-readline-lib:
+ with-readline-ldflags:=auto
+ => {Readline LDFLAGS, e.g. -lreadline -lncurses}
+ # --with-readline-inc is a backwards-compatible alias for
+ # --with-readline-cflags.
+ with-readline-inc:
+ with-readline-cflags:=auto
+ => {Readline CFLAGS, e.g. -I/path/to/includes}
+ with-readline-header:PATH
+ => {Full path to readline.h, from which --with-readline-cflags will be derived}
+ with-linenoise:DIR => {Source directory for linenoise.c and linenoise.h}
+ editline=0 => {Enable BSD editline support}
+ # </line-editing>
+ # <icu>
+ with-icu-ldflags:LDFLAGS
+ => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the ICU libraries}
+ with-icu-cflags:CFLAGS
+ => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU. e.g. -I/usr/local/include}
+ with-icu-config:=auto => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config, /path/to/icu-config}
+ icu-collations=0 => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=... or --with-icu-config}
+ # </icu>
+ # <developer>
+ # Note that using the --debug/--enable-debug flag here requires patching
+ # autosetup/autosetup to rename the --debug to --autosetup-debug.
+ with-debug=0
+ debug=0 =>
+ {Enable debug build flags. This option will impact performance by
+ as much as 4x, as it includes large numbers of assert()s in
+ performance-critical loops. Never use --debug for production
+ builds.}
+ # </developer>
+ # <packaging>
+ soname:=legacy =>
+ # --soname has a long story behind it: https://sqlite.org/src/forumpost/5a3b44f510df8ded
+ {SONAME for libsqlite3.so. "none", or not using this flag, sets no
+ soname. "legacy" sets it to its historical value of
+ libsqlite3.so.0. A value matching the glob "libsqlite3.*" sets
+ it to that literal value. Any other value is assumed to be a
+ suffix which gets applied to "libsqlite3.so.",
+ e.g. --soname=9.10 equates to "libsqlite3.so.9.10".
+ }
+ out-implib=0 =>
+ {Enable use of --out-implib linker flag to generate an "import library" for the DLL}
+ # </packaging>
+}
+
+sqlite-post-options-init
+sqlite-check-common-bins
+sqlite-check-common-system-deps
+proj-check-rpath
+sqlite-handle-soname
+sqlite-setup-default-cflags
+sqlite-handle-debug
+sqlite-handle-threadsafe
+sqlite-handle-tempstore
+sqlite-handle-line-editing
+sqlite-handle-load-extension
+sqlite-handle-math
+sqlite-handle-icu
+
+define ENABLE_LIB_SHARED [opt-bool shared]
+define ENABLE_LIB_STATIC [opt-bool static]
+
+sqlite-common-late-stage-config
diff --git a/autoconf/configure.ac b/autoconf/configure.ac
deleted file mode 100644
index 0c7a32db1..000000000
--- a/autoconf/configure.ac
+++ /dev/null
@@ -1,270 +0,0 @@
-
-#-----------------------------------------------------------------------
-# Supports the following non-standard switches.
-#
-# --enable-threadsafe
-# --enable-readline
-# --enable-editline
-# --enable-static-shell
-# --enable-dynamic-extensions
-#
-
-AC_PREREQ(2.61)
-AC_INIT(sqlite, --SQLITE-VERSION--, http://www.sqlite.org)
-AC_CONFIG_SRCDIR([sqlite3.c])
-AC_CONFIG_AUX_DIR([.])
-
-# Use automake.
-AM_INIT_AUTOMAKE([foreign])
-
-AC_SYS_LARGEFILE
-
-# Check for required programs.
-AC_PROG_CC
-AC_PROG_LIBTOOL
-AC_PROG_MKDIR_P
-
-# Check for library functions that SQLite can optionally use.
-AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
-AC_FUNC_STRERROR_R
-
-AC_CONFIG_FILES([Makefile sqlite3.pc])
-BUILD_CFLAGS=
-AC_SUBST(BUILD_CFLAGS)
-
-#-------------------------------------------------------------------------
-# Two options to enable readline compatible libraries:
-#
-# --enable-editline
-# --enable-readline
-#
-# Both are enabled by default. If, after command line processing both are
-# still enabled, the script searches for editline first and automatically
-# disables readline if it is found. So, to use readline explicitly, the
-# user must pass "--disable-editline". To disable command line editing
-# support altogether, "--disable-editline --disable-readline".
-#
-# When searching for either library, check for headers before libraries
-# as some distros supply packages that contain libraries but not header
-# files, which come as a separate development package.
-#
-AC_ARG_ENABLE(editline, [AS_HELP_STRING([--enable-editline],[use BSD libedit])])
-AC_ARG_ENABLE(readline, [AS_HELP_STRING([--enable-readline],[use readline])])
-
-AS_IF([ test x"$enable_editline" != xno ],[
- AC_CHECK_HEADERS([editline/readline.h],[
- sLIBS=$LIBS
- LIBS=""
- AC_SEARCH_LIBS([readline],[edit],[
- AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline)
- READLINE_LIBS="$LIBS -ltinfo"
- enable_readline=no
- ],[],[-ltinfo])
- AS_UNSET(ac_cv_search_readline)
- LIBS=$sLIBS
- ])
-])
-
-AS_IF([ test x"$enable_readline" != xno ],[
- AC_CHECK_HEADERS([readline/readline.h],[
- sLIBS=$LIBS
- LIBS=""
- AC_SEARCH_LIBS(tgetent, termcap curses ncurses ncursesw, [], [])
- AC_SEARCH_LIBS(readline,[readline edit], [
- AC_DEFINE([HAVE_READLINE],1,Define to use readline or wrapper)
- READLINE_LIBS=$LIBS
- ])
- LIBS=$sLIBS
- ])
-])
-
-AC_SUBST(READLINE_LIBS)
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-threadsafe
-#
-AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING(
- [--enable-threadsafe], [build a thread-safe library [default=yes]])],
- [], [enable_threadsafe=yes])
-if test x"$enable_threadsafe" == "xno"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
-else
- BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
- AC_SEARCH_LIBS(pthread_create, pthread)
- AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-dynamic-extensions
-#
-AC_ARG_ENABLE(dynamic-extensions, [AS_HELP_STRING(
- [--enable-dynamic-extensions], [support loadable extensions [default=yes]])],
- [], [enable_dynamic_extensions=yes])
-if test x"$enable_dynamic_extensions" != "xno"; then
- AC_SEARCH_LIBS(dlopen, dl)
-else
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_OMIT_LOAD_EXTENSION=1"
-fi
-AC_MSG_CHECKING([for whether to support dynamic extensions])
-AC_MSG_RESULT($enable_dynamic_extensions)
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-math
-#
-AC_ARG_ENABLE(math, [AS_HELP_STRING(
- [--enable-math], [SQL math functions [default=yes]])],
- [], [enable_math=yes])
-AC_MSG_CHECKING([SQL math functions])
-if test x"$enable_math" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS"
- AC_MSG_RESULT([enabled])
- AC_SEARCH_LIBS(ceil, m)
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts4
-#
-AC_ARG_ENABLE(fts4, [AS_HELP_STRING(
- [--enable-fts4], [include fts4 support [default=yes]])],
- [], [enable_fts4=yes])
-AC_MSG_CHECKING([FTS4 extension])
-if test x"$enable_fts4" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts3
-#
-AC_ARG_ENABLE(fts3, [AS_HELP_STRING(
- [--enable-fts3], [include fts3 support [default=no]])],
- [], [])
-AC_MSG_CHECKING([FTS3 extension])
-if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts5
-#
-AC_ARG_ENABLE(fts5, [AS_HELP_STRING(
- [--enable-fts5], [include fts5 support [default=yes]])],
- [], [enable_fts5=yes])
-AC_MSG_CHECKING([FTS5 extension])
-if test x"$enable_fts5" = "xyes"; then
- AC_MSG_RESULT([enabled])
- AC_SEARCH_LIBS(log, m)
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5"
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-rtree
-#
-AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
- [--enable-rtree], [include rtree support [default=yes]])],
- [], [enable_rtree=yes])
-AC_MSG_CHECKING([RTREE extension])
-if test x"$enable_rtree" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-session
-#
-AC_ARG_ENABLE(session, [AS_HELP_STRING(
- [--enable-session], [enable the session extension [default=no]])],
- [], [])
-AC_MSG_CHECKING([Session extension])
-if test x"$enable_session" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-debug
-#
-AC_ARG_ENABLE(debug, [AS_HELP_STRING(
- [--enable-debug], [build with debugging features enabled [default=no]])],
- [], [])
-AC_MSG_CHECKING([Build type])
-if test x"$enable_debug" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
- CFLAGS="-g -O0"
- AC_MSG_RESULT([debug])
-else
- AC_MSG_RESULT([release])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-static-shell
-#
-AC_ARG_ENABLE(static-shell, [AS_HELP_STRING(
- [--enable-static-shell],
- [statically link libsqlite3 into shell tool [default=yes]])],
- [], [enable_static_shell=yes])
-if test x"$enable_static_shell" = "xyes"; then
- EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT
-else
- EXTRA_SHELL_OBJ=libsqlite3.la
-fi
-AC_SUBST(EXTRA_SHELL_OBJ)
-#-----------------------------------------------------------------------
-
-AC_CHECK_FUNCS(posix_fallocate)
-AC_CHECK_HEADERS(zlib.h,[
- AC_SEARCH_LIBS(deflate,z,[BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_HAVE_ZLIB"])
-])
-
-AC_SEARCH_LIBS(system,,,[SHELL_CFLAGS="-DSQLITE_NOHAVE_SYSTEM"])
-AC_SUBST(SHELL_CFLAGS)
-
-#-----------------------------------------------------------------------
-# UPDATE: Maybe it's better if users just set CFLAGS before invoking
-# configure. This option doesn't really add much...
-#
-# --enable-tempstore
-#
-# AC_ARG_ENABLE(tempstore, [AS_HELP_STRING(
-# [--enable-tempstore],
-# [in-memory temporary tables (never, no, yes, always) [default=no]])],
-# [], [enable_tempstore=no])
-# AC_MSG_CHECKING([for whether or not to store temp tables in-memory])
-# case "$enable_tempstore" in
-# never ) TEMP_STORE=0 ;;
-# no ) TEMP_STORE=1 ;;
-# always ) TEMP_STORE=3 ;;
-# yes ) TEMP_STORE=3 ;;
-# * )
-# TEMP_STORE=1
-# enable_tempstore=yes
-# ;;
-# esac
-# AC_MSG_RESULT($enable_tempstore)
-# AC_SUBST(TEMP_STORE)
-#-----------------------------------------------------------------------
-
-AC_OUTPUT
diff --git a/autoconf/tea/configure.ac b/autoconf/tea/configure.ac
index 8abf8ad02..d3952707a 100644
--- a/autoconf/tea/configure.ac
+++ b/autoconf/tea/configure.ac
@@ -19,7 +19,7 @@ dnl to configure the system for the local environment.
# so that we create the export library with the dll.
#-----------------------------------------------------------------------
-AC_INIT([sqlite],[3.48.0])
+AC_INIT([sqlite],[3.50.0])
#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
diff --git a/autosetup/README.md b/autosetup/README.md
index fd426d56d..2d6cf723c 100644
--- a/autosetup/README.md
+++ b/autosetup/README.md
@@ -33,12 +33,26 @@ $ ./configure --reference | less
That will include any docs from any TCL files in the `./autosetup` dir
which contain certain (simple) markup defined by autosetup.
-This project's own autosetup-related APIs are in [proj.tcl][] or
-[auto.def][]. The former contains helper APIs which are, more or
-less, portable across projects (that file is re-used as-is in other
-projects) and all have a `proj-` name prefix. The latter is the main
-configure script driver and contains related functions which are
-specific to this tree.
+This project's own configuration-related TCL code is spread across the
+following files:
+
+- [proj.tcl][]: project-agnostic utility code for autosetup-driven
+ projects. This file is designed to be shared between this project,
+ other projects managed under the SQLite/Hwaci umbrella
+ (e.g. Fossil), and personal projects of SQLite's developers. It is
+ essentially an amalgamation of a decade's worth of autosetup-related
+ utility code.
+- [auto.def][]: the primary driver for the `./configure` process.
+ When we talk about "the configure script," we're referring to
+ this file.
+- [sqlite-config.tcl][]: utility code which is too project-specific
+ for `proj.tcl`. We split this out of `auto.def` so that it can be
+ used by both `auto.def` and...
+- [autoconf/auto.def][]: the main driver script for the "autoconf"
+ bundle's configure script. It is essentially a slightly trimmed-down
+ version of the main `auto.def` file. The `autoconf` dir was ported
+ from the Autotools to Autosetup in the 3.49.0 dev cycle but retains
+ the "autoconf" name to minimize downstream disruption.
<a name="apitips"></a>
@@ -47,9 +61,11 @@ Autosetup API Tips
This section briefly covers only APIs which are frequently useful in
day-to-day maintenance and might not be immediately recognized as such
-obvious from a casual perusal of [auto.def][]. The complete docs of
-those with `proj-` prefix can be found in [proj.tcl][]. The others are
-scattered around [the TCL files in ./autosetup](/dir/autosetup).
+obvious from a casual perusal of the relevant TCL files. The complete
+docs of those with `proj-` prefix can be found in [proj.tcl][] and
+those with an `sqlite-` prefix are in [sqlite-config.tcl][]. The
+others are scattered around [the TCL files in
+./autosetup](/dir/autosetup).
In (mostly) alphabetical order:
@@ -180,6 +196,30 @@ APIs must not use `[file normalize]`, but autosetup provides a
TCL-only implementation of `[file-normalize]` (note the dash) for
portable use in the configure script.
+Known TCL Incompatibilities
+------------------------------------------------------------------------
+
+A summary of known incompatibilities in JimTCL
+
+- **CRNL line endings**: prior to 2025-02-05 `fconfigure -translation ...`
+ was a no-op in JimTCL, and it emits CRNL line endings by default on
+ Windows. Since then, it supports `-translation binary`, which is
+ close enough to `-translation lf` for our purposes. When working
+ with files using the `open` command, it is important to use mode
+ `"rb"` or `"wb"`, as appropriate, so that the output does not get
+ CRNL-mangled on Windows.
+
+- **`file copy`** does not support multiple source files. See
+ [](/info/61f18c96183867fe) for a workaround.
+
+- **Regular expressions**:
+
+ - Patterns treat `\nnn` octal values as back-references (which it
+ does not support). Those can be reformulated as demonstrated in
+ [](/info/aeac23359bb681c0).
+
+ - `regsub` does not support the `\y` flag. A workaround is demonstrated
+ in [](/info/c2e5dd791cce3ec4).
<a name="conventions"></a>
Design Conventions
@@ -331,8 +371,10 @@ If autosetup is upgraded and this patch is _not_ applied the invoking
[Autosetup]: https://msteveb.github.io/autosetup/
[auto.def]: /file/auto.def
+[autoconf/auto.def]: /file/autoconf/auto.def
[autosetup-git]: https://github.com/msteveb/autosetup
[proj.tcl]: /file/autosetup/proj.tcl
+[sqlite-config.tcl]: /file/autosetup/sqlite-config.tcl
[Makefile.in]: /file/Makefile.in
[main.mk]: /file/main.mk
[JimTCL]: https://jim.tcl.tk
diff --git a/autosetup/jimsh0.c b/autosetup/jimsh0.c
index 84db85a20..0526b9a44 100644
--- a/autosetup/jimsh0.c
+++ b/autosetup/jimsh0.c
@@ -1198,6 +1198,11 @@ int Jim_OpenForRead(const char *filename);
#define Jim_FileStat _fstat64
#define Jim_Lseek _lseeki64
#define O_TEXT _O_TEXT
+ #define O_BINARY _O_BINARY
+ #define Jim_SetMode _setmode
+ #ifndef STDIN_FILENO
+ #define STDIN_FILENO 0
+ #endif
#else
#if defined(HAVE_STAT64)
@@ -1864,7 +1869,7 @@ int Jim_tclcompatInit(Jim_Interp *interp)
" $f buffering $v\n"
" }\n"
" -tr* {\n"
-"\n"
+" $f translation $v\n"
" }\n"
" default {\n"
" return -code error \"fconfigure: unknown option $n\"\n"
@@ -2936,6 +2941,28 @@ static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_OK;
}
+static int aio_cmd_translation(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ enum {OPT_BINARY, OPT_TEXT};
+ static const char * const options[] = {
+ "binary",
+ "text",
+ NULL
+ };
+ int opt;
+
+ if (Jim_GetEnum(interp, argv[0], options, &opt, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+#if defined(Jim_SetMode)
+ else {
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_SetMode(af->fd, opt == OPT_BINARY ? O_BINARY : O_TEXT);
+ }
+#endif
+ return JIM_OK;
+}
+
static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
@@ -3146,6 +3173,13 @@ static const jim_subcmd_type aio_command_table[] = {
2,
},
+ { "translation",
+ "binary|text",
+ aio_cmd_translation,
+ 1,
+ 1,
+
+ },
{ "readsize",
"?size?",
aio_cmd_readsize,
@@ -24425,6 +24459,10 @@ int main(int argc, char *const argv[])
}
if (retcode != JIM_EXIT) {
JimSetArgv(interp, 0, NULL);
+ if (!isatty(STDIN_FILENO)) {
+
+ goto eval_stdin;
+ }
retcode = Jim_InteractivePrompt(interp);
}
}
@@ -24447,6 +24485,7 @@ int main(int argc, char *const argv[])
Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
JimSetArgv(interp, argc - 2, argv + 2);
if (strcmp(argv[1], "-") == 0) {
+eval_stdin:
retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
} else {
retcode = Jim_EvalFile(interp, argv[1]);
diff --git a/autosetup/proj.tcl b/autosetup/proj.tcl
index a469c898d..fdfbf3a5e 100644
--- a/autosetup/proj.tcl
+++ b/autosetup/proj.tcl
@@ -114,11 +114,13 @@ proc proj-bold {str} {
#
# If the -notice flag it used then it emits using [user-notice], which
# means its rendering will (A) go to stderr and (B) be delayed until
-# the next time autosetup goes to output a message. If -notice
-# is not used, it will send the message to stdout without delay.
+# the next time autosetup goes to output a message.
#
# If the -error flag is provided then it renders the message
# immediately to stderr and then exits.
+#
+# If neither -notice nor -error are used, the message will be sent to
+# stdout without delay.
proc proj-indented-notice {args} {
set fErr ""
set outFunc "puts"
@@ -126,6 +128,7 @@ proc proj-indented-notice {args} {
switch -exact -- [lindex $args 0] {
-error {
set args [lassign $args fErr]
+ set outFunc "user-notice"
}
-notice {
set args [lassign $args -]
@@ -181,10 +184,10 @@ proc proj-lshift_ {listVar {count 1}} {
########################################################################
# Expects to receive string input, which it splits on newlines, strips
-# out any lines which begin with an number of whitespace followed by a
-# '#', and returns a value containing the [append]ed results of each
+# out any lines which begin with any number of whitespace followed by
+# a '#', and returns a value containing the [append]ed results of each
# remaining line with a \n between each.
-proc proj-strip-hash-comments_ {val} {
+proc proj-strip-hash-comments {val} {
set x {}
foreach line [split $val \n] {
if {![string match "#*" [string trimleft $line]]} {
@@ -200,7 +203,7 @@ proc proj-strip-hash-comments_ {val} {
# A proxy for cc-check-function-in-lib which does not make any global
# changes to the LIBS define. Returns the result of
# cc-check-function-in-lib (i.e. true or false). The resulting linker
-# flags are stored in ${lib_${function}}.
+# flags are stored in the [define] named lib_${function}.
proc proj-check-function-in-lib {function libs {otherlibs {}}} {
set found 0
define-push {LIBS} {
@@ -276,9 +279,9 @@ proc proj-find-executable-path {args} {
# a binary, sets a define (see below) to the result, and returns the
# result (an empty string if not found).
#
-# The define'd name is: if defName is empty then "BIN_X" is used,
-# where X is the upper-case form of $binName with any '-' characters
-# replaced with '_'.
+# The define'd name is: If $defName is not empty, it is used as-is. If
+# $defName is empty then "BIN_X" is used, where X is the upper-case
+# form of $binName with any '-' characters replaced with '_'.
proc proj-bin-define {binName {defName {}}} {
set check [proj-find-executable-path -v $binName]
if {"" eq $defName} {
@@ -760,7 +763,7 @@ proc proj-exe-extension {} {
# Trivia: for .dylib files, the linker needs the -dynamiclib flag
# instead of -shared.
proc proj-dll-extension {} {
- proc inner {key} {
+ set inner {{key} {
switch -glob -- [get-define $key] {
*apple* {
return ".dylib"
@@ -772,9 +775,9 @@ proc proj-dll-extension {} {
return ".so"
}
}
- }
- define BUILD_DLLEXT [inner build]
- define TARGET_DLLEXT [inner host]
+ }}
+ define BUILD_DLLEXT [apply $inner build]
+ define TARGET_DLLEXT [apply $inner host]
}
########################################################################
@@ -784,18 +787,20 @@ proc proj-dll-extension {} {
# BUILD_LIBEXT and TARGET_LIBEXT to the conventional static library
# extension for the being-built-on resp. the target platform.
proc proj-lib-extension {} {
- proc inner {key} {
+ set inner {{key} {
switch -glob -- [get-define $key] {
*-*-ming* - *-*-cygwin - *-*-msys {
- return ".lib"
+ return ".a"
+ # ^^^ this was ".lib" until 2025-02-07. See
+ # https://sqlite.org/forum/forumpost/02db2d4240
}
default {
return ".a"
}
}
- }
- define BUILD_LIBEXT [inner build]
- define TARGET_LIBEXT [inner host]
+ }}
+ define BUILD_LIBEXT [apply $inner build]
+ define TARGET_LIBEXT [apply $inner host]
}
########################################################################
@@ -850,16 +855,16 @@ proc proj-affirm-files-exist {args} {
# If the given directory is found, it expects to find emsdk_env.sh in
# that directory, as well as the emcc compiler somewhere under there.
#
-# If the --with-emsdk flag is explicitly provided and the SDK is not
-# found then a fatal error is generated, otherwise failure to find the
-# SDK is not fatal.
+# If the --with-emsdk[=DIR] flag is explicitly provided and the SDK is
+# not found then a fatal error is generated, otherwise failure to find
+# the SDK is not fatal.
#
# Defines the following:
#
-# - EMSDK_HOME = top dir of the emsdk or "".
-# - EMSDK_ENV_SH = path to EMSDK_HOME/emsdk_env.sh or ""
-# - BIN_EMCC = $EMSDK_HOME/upstream/emscripten/emcc or ""
# - HAVE_EMSDK = 0 or 1 (this function's return value)
+# - EMSDK_HOME = "" or top dir of the emsdk
+# - EMSDK_ENV_SH = "" or $EMSDK_HOME/emsdk_env.sh
+# - BIN_EMCC = "" or $EMSDK_HOME/upstream/emscripten/emcc
#
# Returns 1 if EMSDK_ENV_SH is found, else 0. If EMSDK_HOME is not empty
# but BIN_EMCC is then emcc was not found in the EMSDK_HOME, in which
@@ -1119,7 +1124,7 @@ proc proj-dump-defs-json {file args} {
# that [opt-value canonical] will return X if --alias=X is passed to
# configure.
proc proj-xfer-options-aliases {mapping} {
- foreach {hidden - canonical} [proj-strip-hash-comments_ $mapping] {
+ foreach {hidden - canonical} [proj-strip-hash-comments $mapping] {
if {[proj-opt-was-provided $hidden]} {
if {[proj-opt-was-provided $canonical]} {
proj-fatal "both --$canonical and its alias --$hidden were used. Use only one or the other."
diff --git a/autosetup/sqlite-config.tcl b/autosetup/sqlite-config.tcl
new file mode 100644
index 000000000..1aaa8af37
--- /dev/null
+++ b/autosetup/sqlite-config.tcl
@@ -0,0 +1,1485 @@
+# This file holds functions for autosetup which are specific to the
+# sqlite build tree. They are in this file, instead of auto.def, so
+# that they can be reused in the TEA sub-tree. This file requires
+# functions from proj.tcl.
+
+use cc cc-db cc-shared cc-lib pkg-config proj
+
+#
+# Object for communicating config-time state across various
+# auto.def-related pieces.
+#
+array set sqliteConfig [proj-strip-hash-comments {
+ #
+ # Gets set to 1 when using jimsh for code generation. May affect
+ # later decisions.
+ use-jim-for-codegen 0
+ #
+ # Pass msg-debug=1 to configure to enable obnoxiously loud output
+ # from [msg-debug].
+ msg-debug-enabled 0
+ #
+ # Output file for --dump-defines. Intended only for build debugging
+ # and not part of the public build interface.
+ dump-defines-txt ./config.defines.txt
+ #
+ # Output file for --dump-defines-json. This is the autosetup
+ # counterpart of the historical "DEFS" var which was generated by
+ # the autotools in the pre-processed autotools builds (but not in
+ # the canonical tree). Generation of this file is disabled (via an
+ # empty file name) until/unless someone voices a specific interest
+ # in it. The original motivating use case is handled fine by
+ # sqlite_cfg.h.
+ dump-defines-json ""
+}]
+
+#
+# Set to 1 when cross-compiling This value may be changed by certain
+# build options, so it's important that config code which checks for
+# cross-compilation uses this var instead of
+# [proj-is-cross-compiling].
+#
+set sqliteConfig(is-cross-compiling) [proj-is-cross-compiling]
+
+########################################################################
+# Runs some common initialization which must happen immediately after
+# autosetup's [options] function is called. This is also a convenient
+# place to put some generic pieces common to both the canonical
+# top-level build and the "autoconf" build, but it's not intended to
+# be a catch-all dumping ground for such.
+proc sqlite-post-options-init {} {
+ #
+ # Carry values from hidden --flag aliases over to their canonical
+ # flag forms. This list must include only options which are common
+ # to both the top-level auto.def and autoconf/auto.def.
+ #
+ proj-xfer-options-aliases {
+ with-readline-inc => with-readline-cflags
+ with-readline-lib => with-readline-ldflags
+ with-debug => debug
+ }
+ sqlite-autoreconfig
+ proj-file-extensions
+ if {".exe" eq [get-define TARGET_EXEEXT]} {
+ define SQLITE_OS_UNIX 0
+ define SQLITE_OS_WIN 1
+ } else {
+ define SQLITE_OS_UNIX 1
+ define SQLITE_OS_WIN 0
+ }
+ set ::sqliteConfig(msg-debug-enabled) [proj-val-truthy [get-env msg-debug 0]]
+ sqlite-setup-package-info
+}
+
+########################################################################
+# Called by [sqlite-post-options-init] to set up PACKAGE_NAME and
+# related defines.
+proc sqlite-setup-package-info {} {
+ set srcdir $::autosetup(srcdir)
+ set PACKAGE_VERSION [proj-file-content -trim $srcdir/VERSION]
+ define PACKAGE_NAME "sqlite"
+ define PACKAGE_URL {https://sqlite.org}
+ define PACKAGE_VERSION $PACKAGE_VERSION
+ define PACKAGE_STRING "[get-define PACKAGE_NAME] $PACKAGE_VERSION"
+ define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
+ msg-result "Source dir = $srcdir"
+ msg-result "Build dir = $::autosetup(builddir)"
+ msg-result "Configuring SQLite version $PACKAGE_VERSION"
+}
+
+########################################################################
+# Internal config-time debugging output routine. It generates no
+# output unless msg-debug=1 is passed to the configure script.
+proc msg-debug {msg} {
+ if {$::sqliteConfig(msg-debug-enabled)} {
+ puts stderr [proj-bold "** DEBUG: $msg"]
+ }
+}
+
+########################################################################
+# Sets up the SQLITE_AUTORECONFIG define.
+proc sqlite-autoreconfig {} {
+ #
+ # SQLITE_AUTORECONFIG contains make target rules for re-running the
+ # configure script with the same arguments it was initially invoked
+ # with. This can be used to automatically reconfigure
+ #
+ proc squote {arg} {
+ # Wrap $arg in single-quotes if it looks like it might need that
+ # to avoid mis-handling as a shell argument. We assume that $arg
+ # will never contain any single-quote characters.
+ if {[string match {*[ &;$*"]*} $arg]} { return '$arg' }
+ return $arg
+ }
+ define-append SQLITE_AUTORECONFIG cd [squote $::autosetup(builddir)] && [squote $::autosetup(srcdir)/configure]
+ #{*}$::autosetup(argv) breaks with --flag='val with spaces', so...
+ foreach arg $::autosetup(argv) {
+ define-append SQLITE_AUTORECONFIG [squote $arg]
+ }
+ rename squote ""
+}
+
+define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
+define OPT_SHELL {} ; # Feature-related CFLAGS for the sqlite3 CLI app
+########################################################################
+# Adds $args, if not empty, to OPT_FEATURE_FLAGS. If the first arg is
+# -shell then it strips that arg and passes the remaining args the
+# sqlite-add-shell-opt in addition to adding them to
+# OPT_FEATURE_FLAGS.
+proc sqlite-add-feature-flag {args} {
+ set shell ""
+ if {"-shell" eq [lindex $args 0]} {
+ set args [lassign $args shell]
+ }
+ if {"" ne $args} {
+ if {"" ne $shell} {
+ sqlite-add-shell-opt {*}$args
+ }
+ define-append OPT_FEATURE_FLAGS {*}$args
+ }
+}
+# Appends $args, if not empty, to OPT_SHELL.
+proc sqlite-add-shell-opt {args} {
+ if {"" ne $args} {
+ define-append OPT_SHELL {*}$args
+ }
+}
+
+########################################################################
+# Check for log(3) in libm and die with an error if it is not
+# found. $featureName should be the feature name which requires that
+# function (it's used only in error messages). defines LDFLAGS_MATH to
+# the required linker flags (which may be empty even if the math APIs
+# are found, depending on the OS).
+proc sqlite-affirm-have-math {featureName} {
+ if {"" eq [get-define LDFLAGS_MATH ""]} {
+ if {![msg-quiet proj-check-function-in-lib log m]} {
+ user-error "Missing math APIs for $featureName"
+ }
+ define LDFLAGS_MATH [get-define lib_log ""]
+ undefine lib_log
+ }
+}
+
+########################################################################
+# Run checks for required binaries, like ld and ar. In the canonical
+# build this must come before [sqlite-handle-wasi-sdk].
+proc sqlite-check-common-bins {} {
+ cc-check-tools ld ar ; # must come before [sqlite-handle-wasi-sdk]
+ if {"" eq [proj-bin-define install]} {
+ proj-warn "Cannot find install binary, so 'make install' will not work."
+ define BIN_INSTALL false
+ }
+}
+
+########################################################################
+# Run checks for system-level includes and libs which are common to
+# both the canonical build and the "autoconf" bundle.
+proc sqlite-check-common-system-deps {} {
+ #
+ # Check for needed/wanted data types
+ cc-with {-includes stdint.h} \
+ {cc-check-types int8_t int16_t int32_t int64_t intptr_t \
+ uint8_t uint16_t uint32_t uint64_t uintptr_t}
+
+ #
+ # Check for needed/wanted functions
+ cc-check-functions gmtime_r isnan localtime_r localtime_s \
+ malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64
+
+ set ldrt ""
+ # Collapse funcs from librt into LDFLAGS_RT.
+ # Some systems (ex: SunOS) require -lrt in order to use nanosleep
+ foreach func {fdatasync nanosleep} {
+ if {[proj-check-function-in-lib $func rt]} {
+ lappend ldrt [get-define lib_${func}]
+ }
+ }
+ define LDFLAGS_RT [join [lsort -unique $ldrt] ""]
+
+ #
+ # Check for needed/wanted headers
+ cc-check-includes \
+ sys/types.h sys/stat.h dlfcn.h unistd.h \
+ stdlib.h malloc.h memory.h \
+ string.h strings.h \
+ inttypes.h
+
+ if {[cc-check-includes zlib.h] && [proj-check-function-in-lib deflate z]} {
+ # TODO? port over the more sophisticated zlib search from the fossil auto.def
+ define HAVE_ZLIB 1
+ define LDFLAGS_ZLIB -lz
+ sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
+ } else {
+ define HAVE_ZLIB 0
+ define LDFLAGS_ZLIB ""
+ }
+}
+
+proc sqlite-setup-default-cflags {} {
+ ########################################################################
+ # We differentiate between two C compilers: the one used for binaries
+ # which are to run on the build system (in autosetup it's called
+ # CC_FOR_BUILD and in Makefile.in it's $(B.cc)) and the one used for
+ # compiling binaries for the target system (CC a.k.a. $(T.cc)).
+ # Normally they're the same, but they will differ when
+ # cross-compiling.
+ #
+ # When cross-compiling we default to not using the -g flag, based on a
+ # /chat discussion prompted by
+ # https://sqlite.org/forum/forumpost/9a67df63eda9925c
+ set defaultCFlags {-O2}
+ if {!$::sqliteConfig(is-cross-compiling)} {
+ lappend defaultCFlags -g
+ }
+ define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
+ # BUILD_CFLAGS is the CFLAGS for CC_FOR_BUILD.
+ define BUILD_CFLAGS [proj-get-env BUILD_CFLAGS {-g}]
+
+ # Copy all CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and
+ # -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived
+ # from the legacy build and was missing the 3.48.0 release (the
+ # initial Autosetup port).
+ # https://sqlite.org/forum/forumpost/9801e54665afd728
+ #
+ # Handling of CPPFLAGS, as well as removing ENABLE/OMIT from
+ # CFLAGS/CPPFLAGS, was missing in the 3.49.0 release as well.
+ #
+ # If any configure flags for features are in conflict with
+ # CFLAGS/CPPFLAGS-specified feature flags, all bets are off. There
+ # are no guarantees about which one will take precedence.
+ foreach flagDef {CFLAGS CPPFLAGS} {
+ set tmp ""
+ foreach cf [get-define $flagDef ""] {
+ switch -glob -- $cf {
+ -DSQLITE_OMIT* -
+ -DSQLITE_ENABLE* {
+ sqlite-add-feature-flag $cf
+ }
+ default {
+ lappend tmp $cf
+ }
+ }
+ }
+ define $flagDef $tmp
+ }
+
+ # Strip all SQLITE_ENABLE/OMIT flags from BUILD_CFLAGS,
+ # for compatibility with the legacy build.
+ set tmp ""
+ foreach cf [get-define BUILD_CFLAGS ""] {
+ switch -glob -- $cf {
+ -DSQLITE_OMIT* -
+ -DSQLITE_ENABLE* {}
+ default {
+ lappend tmp $cf
+ }
+ }
+ }
+ define BUILD_CFLAGS $tmp
+}
+
+########################################################################
+# Handle various SQLITE_ENABLE_... feature flags.
+proc sqlite-handle-common-feature-flags {} {
+ msg-result "Feature flags..."
+ foreach {boolFlag featureFlag ifSetEvalThis} {
+ all {} {
+ # The 'all' option must be first in this list.
+ proj-opt-set fts4
+ proj-opt-set fts5
+ proj-opt-set geopoly
+ proj-opt-set rtree
+ proj-opt-set session
+ }
+ fts4 -DSQLITE_ENABLE_FTS4 {sqlite-affirm-have-math fts4}
+ fts5 -DSQLITE_ENABLE_FTS5 {sqlite-affirm-have-math fts5}
+ geopoly -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree}
+ rtree -DSQLITE_ENABLE_RTREE {}
+ session {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {}
+ update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {}
+ memsys5 -DSQLITE_ENABLE_MEMSYS5 {}
+ memsys3 {} {
+ if {[opt-bool memsys5]} {
+ proj-warn "not enabling memsys3 because memsys5 is enabled."
+ expr 0
+ } else {
+ sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
+ }
+ }
+ scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
+ } {
+ if {$boolFlag ni $::autosetup(options)} {
+ # Skip flags which are in the canonical build but not
+ # the autoconf bundle.
+ continue
+ }
+ proj-if-opt-truthy $boolFlag {
+ sqlite-add-feature-flag $featureFlag
+ if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
+ msg-result " + $boolFlag"
+ }
+ } {
+ if {"all" ne $boolFlag} {
+ msg-result " - $boolFlag"
+ }
+ }
+ }
+ ########################################################################
+ # Invert the above loop's logic for some SQLITE_OMIT_... cases. If
+ # config option $boolFlag is false, [sqlite-add-feature-flag
+ # $featureFlag], where $featureFlag is intended to be
+ # -DSQLITE_OMIT_...
+ foreach {boolFlag featureFlag} {
+ json -DSQLITE_OMIT_JSON
+ } {
+ if {[proj-opt-truthy $boolFlag]} {
+ msg-result " + $boolFlag"
+ } else {
+ sqlite-add-feature-flag $featureFlag
+ msg-result " - $boolFlag"
+ }
+ }
+
+}
+
+#########################################################################
+# Remove duplicates from the final feature flag sets and show them to
+# the user.
+proc sqlite-finalize-feature-flags {} {
+ set oFF [get-define OPT_FEATURE_FLAGS]
+ if {"" ne $oFF} {
+ define OPT_FEATURE_FLAGS [lsort -unique $oFF]
+ msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
+ }
+ set oFF [get-define OPT_SHELL]
+ if {"" ne $oFF} {
+ define OPT_SHELL [lsort -unique $oFF]
+ msg-result "Shell options: [get-define OPT_SHELL]"
+ }
+}
+
+########################################################################
+# Checks for the --debug flag, defining SQLITE_DEBUG to 1 if it is
+# true. TARGET_DEBUG gets defined either way, with content depending
+# on whether --debug is true or false.
+proc sqlite-handle-debug {} {
+ msg-checking "SQLITE_DEBUG build? "
+ proj-if-opt-truthy debug {
+ define SQLITE_DEBUG 1
+ define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall}
+ proj-opt-set memsys5
+ msg-result yes
+ } {
+ define TARGET_DEBUG {-DNDEBUG}
+ msg-result no
+ }
+}
+
+########################################################################
+# "soname" for libsqlite3.so. See discussion at:
+# https://sqlite.org/src/forumpost/5a3b44f510df8ded
+proc sqlite-handle-soname {} {
+ define LDFLAGS_LIBSQLITE3_SONAME ""
+ if {[proj-opt-was-provided soname]} {
+ set soname [join [opt-val soname] ""]
+ } else {
+ # Enabling soname breaks linking for the --dynlink-tools feature,
+ # and this project has no direct use for soname, so default to
+ # none. Package maintainers, on the other hand, like to have an
+ # soname.
+ set soname none
+ }
+ switch -exact -- $soname {
+ none - "" { return 0 }
+ legacy { set soname libsqlite3.so.0 }
+ default {
+ if {[string match libsqlite3.* $soname]} {
+ # use it as-is
+ } else {
+ # Assume it's a suffix
+ set soname "libsqlite3.so.${soname}"
+ }
+ }
+ }
+ msg-debug "soname=$soname"
+ if {[proj-check-soname $soname]} {
+ define LDFLAGS_LIBSQLITE3_SONAME [get-define LDFLAGS_SONAME_PREFIX]$soname
+ msg-result "Setting SONAME using: [get-define LDFLAGS_LIBSQLITE3_SONAME]"
+ } elseif {[proj-opt-was-provided soname]} {
+ # --soname was explicitly requested but not available, so fail fatally
+ proj-fatal "This environment does not support SONAME."
+ } else {
+ # --soname was not explicitly requested but not available, so just warn
+ msg-result "This environment does not support SONAME."
+ }
+}
+
+########################################################################
+# If --enable-thresafe is set, this adds -DSQLITE_THREADSAFE=1 to
+# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to the linker flags
+# needed for linking pthread. If --enable-threadsafe is not set, adds
+# -DSQLITE_THREADSAFE=0 to OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD
+# to an empty string.
+proc sqlite-handle-threadsafe {} {
+ msg-checking "Support threadsafe operation? "
+ proj-if-opt-truthy threadsafe {
+ msg-result yes
+ sqlite-add-feature-flag -DSQLITE_THREADSAFE=1
+ if {![proj-check-function-in-lib pthread_create pthread]
+ || ![proj-check-function-in-lib pthread_mutexattr_init pthread]} {
+ user-error "Missing required pthread bits"
+ }
+ define LDFLAGS_PTHREAD [get-define lib_pthread_create]
+ undefine lib_pthread_create
+ # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if
+ # found because it's in -lc on some platforms.
+ } {
+ msg-result no
+ sqlite-add-feature-flag -DSQLITE_THREADSAFE=0
+ define LDFLAGS_PTHREAD ""
+ }
+}
+
+########################################################################
+# Handles the --with-tempstore flag.
+#
+# The test fixture likes to set SQLITE_TEMP_STORE on its own, so do
+# not set that feature flag unless it was explicitly provided to the
+# configure script.
+proc sqlite-handle-tempstore {} {
+ if {[proj-opt-was-provided with-tempstore]} {
+ set ts [opt-val with-tempstore no]
+ set tsn 1
+ msg-checking "Use an in-RAM database for temporary tables? "
+ switch -exact -- $ts {
+ never { set tsn 0 }
+ no { set tsn 1 }
+ yes { set tsn 2 }
+ always { set tsn 3 }
+ default {
+ user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always"
+ }
+ }
+ msg-result $ts
+ sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn
+ }
+}
+
+########################################################################
+# Check for the Emscripten SDK for building the web-based wasm
+# components. The core lib and tools do not require this but ext/wasm
+# does. Most of the work is done via [proj-check-emsdk], then this
+# function adds the following defines:
+#
+# - EMCC_WRAPPER = "" or top-srcdir/tool/emcc.sh
+# - BIN_WASM_OPT = "" or path to wasm-opt
+# - BIN_WASM_STRIP = "" or path to wasm-strip
+#
+# Noting that:
+#
+# 1) Not finding the SDK is not fatal at this level, nor is failure to
+# find one of the related binaries.
+#
+# 2) wasm-strip is part of the wabt package:
+#
+# https://github.com/WebAssembly/wabt
+#
+# and this project requires it for production-mode builds but not dev
+# builds.
+#
+proc sqlite-handle-emsdk {} {
+ define EMCC_WRAPPER ""
+ define BIN_WASM_STRIP ""
+ define BIN_WASM_OPT ""
+ set srcdir $::autosetup(srcdir)
+ if {$srcdir ne $::autosetup(builddir)} {
+ # The EMSDK pieces require writing to the original source tree
+ # even when doing an out-of-tree build. The ext/wasm pieces do not
+ # support an out-of-tree build so we treat that case as if EMSDK
+ # were not found.
+ msg-result "Out-of tree build: not checking for EMSDK."
+ return
+ }
+ set emccSh $srcdir/tool/emcc.sh
+ set extWasmConfig $srcdir/ext/wasm/config.make
+ if {![get-define HAVE_WASI_SDK] && [proj-check-emsdk]} {
+ define EMCC_WRAPPER $emccSh
+ set emsdkHome [get-define EMSDK_HOME ""]
+ proj-assert {"" ne $emsdkHome}
+ #define EMCC_WRAPPER ""; # just for testing
+ proj-bin-define wasm-strip
+ proj-bin-define bash; # ext/wasm/GNUmakefile requires bash
+ if {[file-isexec $emsdkHome/upstream/bin/wasm-opt]} {
+ define BIN_WASM_OPT $emsdkHome/upstream/bin/wasm-opt
+ } else {
+ # Maybe there's a copy in the path?
+ proj-bin-define wasm-opt BIN_WASM_OPT
+ }
+ proj-make-from-dot-in $emccSh $extWasmConfig
+ catch {exec chmod u+x $emccSh}
+ } else {
+ define EMCC_WRAPPER ""
+ file delete -force -- $emccSh $extWasmConfig
+ }
+}
+
+########################################################################
+# sqlite-check-line-editing jumps through proverbial hoops to try to
+# find a working line-editing library, setting:
+#
+# - HAVE_READLINE to 0 or 1
+# - HAVE_LINENOISE to 0, 1, or 2
+# - HAVE_EDITLINE to 0 or 1
+#
+# Only one of ^^^ those will be set to non-0.
+#
+# - LDFLAGS_READLINE = linker flags or empty string
+#
+# - CFLAGS_READLINE = compilation flags for clients or empty string.
+#
+# Note that LDFLAGS_READLINE and CFLAGS_READLINE may refer to
+# linenoise or editline, not necessarily libreadline. In some cases
+# it will set HAVE_READLINE=1 when it's really using editline, for
+# reasons described in this function's comments.
+#
+# Returns a string describing which line-editing approach to use, or
+# "none" if no option is available.
+#
+# Order of checks:
+#
+# 1) --with-linenoise trumps all others and skips all of the
+# complexities involved with the remaining options.
+#
+# 2) --editline trumps --readline
+#
+# 3) --disable-readline trumps --readline
+#
+# 4) Default to automatic search for optional readline
+#
+# 5) Try to find readline or editline. If it's not found AND the
+# corresponding --FEATURE flag was explicitly given, fail fatally,
+# else fail silently.
+proc sqlite-check-line-editing {} {
+ msg-result "Checking for line-editing capability..."
+ define HAVE_READLINE 0
+ define HAVE_LINENOISE 0
+ define HAVE_EDITLINE 0
+ define LDFLAGS_READLINE ""
+ define CFLAGS_READLINE ""
+ set failIfNotFound 0 ; # Gets set to 1 for explicit --FEATURE requests
+ # so that we know whether to fail fatally or not
+ # if the library is not found.
+ set libsForReadline {readline edit} ; # -l<LIB> names to check for readline().
+ # The libedit check changes this.
+ set editLibName "readline" ; # "readline" or "editline"
+ set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
+ set dirLn [opt-val with-linenoise]
+ if {"" ne $dirLn} {
+ # Use linenoise from a copy of its sources (not a library)...
+ if {![file isdir $dirLn]} {
+ proj-fatal "--with-linenoise value is not a directory"
+ }
+ set lnH $dirLn/linenoise.h
+ if {![file exists $lnH] } {
+ proj-fatal "Cannot find linenoise.h in $dirLn"
+ }
+ set lnC ""
+ set lnCOpts {linenoise-ship.c linenoise.c}
+ foreach f $lnCOpts {
+ if {[file exists $dirLn/$f]} {
+ set lnC $dirLn/$f
+ break;
+ }
+ }
+ if {"" eq $lnC} {
+ proj-fatal "Cannot find any of $lnCOpts in $dirLn"
+ }
+ set flavor ""
+ set lnVal [proj-which-linenoise $lnH]
+ switch -- $lnVal {
+ 1 { set flavor "antirez" }
+ 2 { set flavor "msteveb" }
+ default {
+ proj-fatal "Cannot determine the flavor of linenoise from $lnH"
+ }
+ }
+ define CFLAGS_READLINE "-I$dirLn $lnC"
+ define HAVE_LINENOISE $lnVal
+ sqlite-add-shell-opt -DHAVE_LINENOISE=$lnVal
+ if {$::sqliteConfig(use-jim-for-codegen) && 2 == $lnVal} {
+ define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE]
+ user-notice "Adding linenoise support to jimsh."
+ }
+ return "linenoise ($flavor)"
+ } elseif {[opt-bool editline]} {
+ # libedit mimics libreadline and on some systems does not have its
+ # own header installed (instead, that of libreadline is used).
+ #
+ # shell.c historically expects HAVE_EDITLINE to be set for
+ # libedit, but it then expects to see <editline/readline.h>, which
+ # some system's don't actually have despite having libedit. If we
+ # end up finding <editline/readline.h> below, we will use
+ # -DHAVE_EDITLINE=1, else we will use -DHAVE_READLINE=1. In either
+ # case, we will link against libedit.
+ set failIfNotFound 1
+ set libsForReadline {edit}
+ set editLibName editline
+ } elseif {![opt-bool readline]} {
+ msg-result "Readline support explicitly disabled with --disable-readline"
+ return "none"
+ } elseif {[proj-opt-was-provided readline]} {
+ # If an explicit --[enable-]readline was used, fail if it's not
+ # found, else treat the feature as optional.
+ set failIfNotFound 1
+ }
+
+ # Transform with-readline-header=X to with-readline-cflags=-I...
+ set v [opt-val with-readline-header]
+ proj-opt-set with-readline-header ""
+ if {"" ne $v} {
+ if {"auto" eq $v} {
+ proj-opt-set with-readline-cflags auto
+ } else {
+ set v [file dirname $v]
+ if {[string match */readline $v]} {
+ # Special case: if the path includes .../readline/readline.h,
+ # set the -I to one dir up from that because our sources
+ # #include <readline/readline.h> or <editline/readline.h>.
+ set v [file dirname $v]
+ }
+ proj-opt-set with-readline-cflags "-I$v"
+ }
+ }
+
+ # Look for readline.h
+ set rlInc [opt-val with-readline-cflags auto]
+ if {"auto" eq $rlInc} {
+ set rlInc ""
+ if {$::sqliteConfig(is-cross-compiling)} {
+ # ^^^ this check is derived from the legacy configure script.
+ proj-warn "Skipping check for readline.h because we're cross-compiling."
+ } else {
+ set dirs "[get-define prefix] /usr /usr/local /usr/local/readline /usr/contrib /mingw"
+ set subdirs "include/$editLibName"
+ if {"editline" eq $editLibName} {
+ lappend subdirs include/readline
+ # ^^^ editline, on some systems, does not have its own header,
+ # and uses libreadline's header.
+ }
+ lappend subdirs include
+ # ^^^ The dirs and subdirs lists are, except for the inclusion
+ # of $prefix and editline, from the legacy configure script
+ set rlInc [proj-search-for-header-dir readline.h \
+ -dirs $dirs -subdirs $subdirs]
+ if {"" ne $rlInc} {
+ if {[string match */readline $rlInc]} {
+ set rlInc [file dirname $rlInc]; # shell #include's <readline/readline.h>
+ } elseif {[string match */editline $rlInc]} {
+ set editLibDef HAVE_EDITLINE
+ set rlInc [file dirname $rlInc]; # shell #include's <editline/readline.h>
+ }
+ set rlInc "-I${rlInc}"
+ }
+ }
+ } elseif {"" ne $rlInc && ![string match *-I* $rlInc]} {
+ proj-fatal "Argument to --with-readline-cflags is intended to be CFLAGS and contain -I..."
+ }
+
+ # If readline.h was found/specified, look for lib(readline|edit)...
+ #
+ # This is not quite straightforward because both libreadline and
+ # libedit typically require some other library which (according to
+ # legacy autotools-generated tests) provides tgetent(3). On some
+ # systems that's built into libreadline/edit, on some (most?) its in
+ # lib[n]curses, and on some it's in libtermcap.
+ set rlLib ""
+ if {"" ne $rlInc} {
+ set rlLib [opt-val with-readline-ldflags]
+ if {"" eq $rlLib || "auto" eq $rlLib} {
+ set rlLib ""
+ set libTerm ""
+ if {[proj-check-function-in-lib tgetent "$editLibName ncurses curses termcap"]} {
+ # ^^^ that libs list comes from the legacy configure script ^^^
+ set libTerm [get-define lib_tgetent]
+ undefine lib_tgetent
+ }
+ if {$editLibName eq $libTerm} {
+ set rlLib $libTerm
+ } elseif {[proj-check-function-in-lib readline $libsForReadline $libTerm]} {
+ set rlLib [get-define lib_readline]
+ lappend rlLib $libTerm
+ undefine lib_readline
+ }
+ }
+ }
+
+ # If we found a library, configure the build to use it...
+ if {"" ne $rlLib} {
+ if {"editline" eq $editLibName && "HAVE_READLINE" eq $editLibDef} {
+ # Alert the user that, despite outward appearances, we won't be
+ # linking to the GPL'd libreadline. Presumably that distinction is
+ # significant for those using --editline.
+ proj-indented-notice {
+ NOTE: the local libedit but uses <readline/readline.h> so we
+ will compile with -DHAVE_READLINE=1 but will link with
+ libedit.
+ }
+ }
+ set rlLib [join $rlLib]
+ set rlInc [join $rlInc]
+ define LDFLAGS_READLINE $rlLib
+ define CFLAGS_READLINE $rlInc
+ proj-assert {$editLibDef in {HAVE_READLINE HAVE_EDITLINE}}
+ proj-assert {$editLibName in {readline editline}}
+ sqlite-add-shell-opt -D${editLibDef}=1
+ msg-result "Using $editLibName flags: $rlInc $rlLib"
+ # Check whether rl_completion_matches() has a signature we can use
+ # and disable that sub-feature if it doesn't.
+ if {![cctest \
+ -cflags "$rlInc -D${editLibDef}" -libs $rlLib -nooutput 1 -source {
+ #include <stdio.h>
+ #ifdef HAVE_EDITLINE
+ #include <editline/readline.h>
+ #else
+ #include <readline/readline.h>
+ #endif
+ static char * rcg(const char *z, int i){(void)z; (void)i; return 0;}
+ int main(void) {
+ char ** x = rl_completion_matches("one", rcg);
+ (void)x;
+ return 0;
+ }
+ }]} {
+ proj-warn "readline-style completion disabled due to rl_completion_matches() signature mismatch"
+ sqlite-add-shell-opt -DSQLITE_OMIT_READLINE_COMPLETION
+ }
+ return $editLibName
+ }
+
+ if {$failIfNotFound} {
+ proj-fatal "Explicit --$editLibName failed to find a matching library."
+ }
+ return "none"
+}; # sqlite-check-line-editing
+
+########################################################################
+# Runs sqlite-check-line-editing and adds a message around it In the
+# canonical build this must not be called before
+# sqlite-determine-codegen-tcl.
+proc sqlite-handle-line-editing {} {
+ msg-result "Line-editing support for the sqlite3 shell: [sqlite-check-line-editing]"
+}
+
+
+########################################################################
+# ICU - International Components for Unicode
+#
+# Handles these flags:
+#
+# --with-icu-ldflags=LDFLAGS
+# --with-icu-cflags=CFLAGS
+# --with-icu-config[=auto | pkg-config | /path/to/icu-config]
+# --enable-icu-collations
+#
+# --with-icu-config values:
+#
+# - auto: use the first one of (pkg-config, icu-config) found on the
+# system.
+# - pkg-config: use only pkg-config to determine flags
+# - /path/to/icu-config: use that to determine flags
+#
+# If --with-icu-config is used as neither pkg-config nor icu-config
+# are found, fail fatally.
+#
+# If both --with-icu-ldflags and --with-icu-config are provided, they
+# are cumulative. If neither are provided, icu-collations is not
+# honored and a warning is emitted if it is provided.
+#
+# Design note: though we could automatically enable ICU if the
+# icu-config binary or (pkg-config icu-io) are found, we specifically
+# do not. ICU is always an opt-in feature.
+proc sqlite-handle-icu {} {
+ define LDFLAGS_ICU [join [opt-val with-icu-ldflags ""]]
+ define CFLAGS_ICU [join [opt-val with-icu-cflags ""]]
+ if {[proj-opt-was-provided with-icu-config]} {
+ set icuConfigBin [opt-val with-icu-config]
+ set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config
+ if {"auto" eq $icuConfigBin || "pkg-config" eq $icuConfigBin} {
+ if {[pkg-config-init 0] && [pkg-config icu-io]} {
+ # Maintenance reminder: historical docs say to use both of
+ # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has
+ # all of them on tested OSes.
+ set tryIcuConfigBin 0
+ define LDFLAGS_ICU [get-define PKG_ICU_IO_LDFLAGS]
+ define-append LDFLAGS_ICU [get-define PKG_ICU_IO_LIBS]
+ define CFLAGS_ICU [get-define PKG_ICU_IO_CFLAGS]
+ } elseif {"pkg-config" eq $icuConfigBin} {
+ proj-fatal "pkg-config cannot find package icu-io"
+ } else {
+ proj-assert {"auto" eq $icuConfigBin}
+ }
+ }
+ if {$tryIcuConfigBin} {
+ if {"auto" eq $icuConfigBin} {
+ set icuConfigBin [proj-first-bin-of \
+ /usr/local/bin/icu-config \
+ /usr/bin/icu-config]
+ if {"" eq $icuConfigBin} {
+ proj-fatal "--with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary"
+ }
+ }
+ if {[file-isexec $icuConfigBin]} {
+ set x [exec $icuConfigBin --ldflags]
+ if {"" eq $x} {
+ proj-fatal "$icuConfigBin --ldflags returned no data"
+ }
+ define-append LDFLAGS_ICU $x
+ set x [exec $icuConfigBin --cppflags]
+ define-append CFLAGS_ICU $x
+ } else {
+ proj-fatal "--with-icu-config=$bin does not refer to an executable"
+ }
+ }
+ }
+ set ldflags [define LDFLAGS_ICU [string trim [get-define LDFLAGS_ICU]]]
+ set cflags [define CFLAGS_ICU [string trim [get-define CFLAGS_ICU]]]
+ if {"" ne $ldflags} {
+ sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU
+ msg-result "Enabling ICU support with flags: $ldflags $cflags"
+ if {[opt-bool icu-collations]} {
+ msg-result "Enabling ICU collations."
+ sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU_COLLATIONS
+ # Recall that shell.c builds with sqlite3.c
+ }
+ } elseif {[opt-bool icu-collations]} {
+ proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
+ } else {
+ msg-result "ICU support is disabled."
+ }
+}; # sqlite-handle-icu
+
+
+########################################################################
+# Handles the --enable-load-extension flag. Returns 1 if the support
+# is enabled, else 0. If support for that feature is not found, a
+# fatal error is triggered if --enable-load-extension is explicitly
+# provided, else a loud warning is instead emited. If
+# --disable-load-extension is used, no check is performed.
+#
+# Makes the following environment changes:
+#
+# - defines LDFLAGS_DLOPEN to any linker flags needed for this
+# feature. It may legally be empty on some systems where dlopen()
+# is in libc.
+#
+# - If the feature is not available, adds
+# -DSQLITE_OMIT_LOAD_EXTENSION=1 to the feature flags list.
+proc sqlite-handle-load-extension {} {
+ define LDFLAGS_DLOPEN ""
+ set found 0
+ proj-if-opt-truthy load-extension {
+ set found [proj-check-function-in-lib dlopen dl]
+ if {$found} {
+ define LDFLAGS_DLOPEN [get-define lib_dlopen]
+ undefine lib_dlopen
+ } else {
+ if {[proj-opt-was-provided load-extension]} {
+ # Explicit --enable-load-extension: fail if not found
+ proj-indented-notice -error {
+ --enable-load-extension was provided but dlopen()
+ not found. Use --disable-load-extension to bypass this
+ check.
+ }
+ } else {
+ # It was implicitly enabled: warn if not found
+ proj-indented-notice {
+ WARNING: dlopen() not found, so loadable module support will
+ be disabled. Use --disable-load-extension to bypass this
+ check.
+ }
+ }
+ }
+ }
+ if {$found} {
+ msg-result "Loadable extension support enabled."
+ } else {
+ msg-result "Disabling loadable extension support. Use --enable-load-extensions to enable them."
+ sqlite-add-feature-flag {-DSQLITE_OMIT_LOAD_EXTENSION=1}
+ }
+ return $found
+}
+
+########################################################################
+# Handles the --enable-math flag.
+proc sqlite-handle-math {} {
+ proj-if-opt-truthy math {
+ if {![proj-check-function-in-lib ceil m]} {
+ user-error "Cannot find libm functions. Use --disable-math to bypass this."
+ }
+ define LDFLAGS_MATH [get-define lib_ceil]
+ undefine lib_ceil
+ sqlite-add-feature-flag {-DSQLITE_ENABLE_MATH_FUNCTIONS}
+ msg-result "Enabling math SQL functions [get-define LDFLAGS_MATH]"
+ } {
+ define LDFLAGS_MATH ""
+ msg-result "Disabling math SQL functions"
+ }
+}
+
+########################################################################
+# If this OS looks like a Mac, checks for the Mac-specific
+# -current_version and -compatibility_version linker flags. Defines
+# LDFLAGS_MAC_CVERSION to an empty string and returns 0 if they're not
+# supported, else defines that to the linker flags and returns 1.
+#
+# We don't check this on non-Macs because this whole thing is a
+# libtool compatibility kludge to account for a version stamp which
+# libtool applied only on Mac platforms.
+#
+# Based on https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7.
+proc sqlite-check-mac-cversion {} {
+ define LDFLAGS_MAC_CVERSION ""
+ set rc 0
+ if {[proj-looks-like-mac]} {
+ cc-with {} {
+ # These version numbers are historical libtool-defined values, not
+ # library-defined ones
+ if {[cc-check-flags "-Wl,-current_version,9.6.0"]
+ && [cc-check-flags "-Wl,-compatibility_version,9.0.0"]} {
+ define LDFLAGS_MAC_CVERSION "-Wl,-compatibility_version,9.0.0 -Wl,-current_version,9.6.0"
+ set rc 1
+ } elseif {[cc-check-flags "-compatibility_version 9.0.0"]
+ && [cc-check-flags "-current_version 9.6.0"]} {
+ define LDFLAGS_MAC_CVERSION "-compatibility_version 9.0.0 -current_version 9.6.0"
+ set rc 1
+ }
+ }
+ }
+ return $rc
+}
+
+########################################################################
+# Define LDFLAGS_OUT_IMPLIB to either an empty string or to a
+# -Wl,... flag for the platform-specific --out-implib flag, which is
+# used for building an "import library .dll.a" file on some platforms
+# (e.g. mingw). Returns 1 if supported, else 0.
+#
+# If the configure flag --out-implib is not used then this is a no-op.
+# The feature is specifically opt-in because on some platforms the
+# feature test will pass but using that flag will fail at link-time
+# (e.g. OpenBSD).
+#
+# Added in response to: https://sqlite.org/forum/forumpost/0c7fc097b2
+proc sqlite-check-out-implib {} {
+ define LDFLAGS_OUT_IMPLIB ""
+ set rc 0
+ if {[proj-opt-was-provided out-implib]} {
+ cc-with {} {
+ set dll "libsqlite3[get-define TARGET_DLLEXT]"
+ set flags "-Wl,--out-implib,${dll}.a"
+ if {[cc-check-flags $flags]} {
+ define LDFLAGS_OUT_IMPLIB $flags
+ set rc 1
+ }
+ }
+ }
+ return $rc
+}
+
+########################################################################
+# Performs late-stage config steps common to both the canonical and
+# autoconf bundle builds.
+proc sqlite-common-late-stage-config {} {
+ sqlite-check-mac-cversion
+ sqlite-check-out-implib
+ sqlite-process-dot-in-files
+ sqlite-post-config-validation
+}
+
+########################################################################
+# Perform some late-stage work and generate the configure-process
+# output file(s).
+proc sqlite-process-dot-in-files {} {
+ ########################################################################
+ # When cross-compiling, we have to avoid using the -s flag to
+ # /usr/bin/install:
+ # https://sqlite.org/forum/forumpost/9a67df63eda9925c
+ define IS_CROSS_COMPILING $::sqliteConfig(is-cross-compiling)
+
+ # Finish up handling of the various feature flags here because it's
+ # convenient for both the canonical build and autoconf bundles that
+ # it be done here.
+ sqlite-handle-common-feature-flags
+ sqlite-finalize-feature-flags
+
+ ########################################################################
+ # "Re-export" the autoconf-conventional --XYZdir flags into something
+ # which is more easily overridable from a make invocation. See the docs
+ # for [proj-remap-autoconf-dir-vars] for the explanation of why.
+ #
+ # We do this late in the config process, immediately before we export
+ # the Makefile and other generated files, so that configure tests
+ # which make make use of the autotools-conventional flags
+ # (e.g. [proj-check-rpath]) may do so before we "mangle" them here.
+ proj-remap-autoconf-dir-vars
+
+ proj-make-from-dot-in -touch Makefile sqlite3.pc
+ make-config-header sqlite_cfg.h \
+ -bare {SIZEOF_* HAVE_DECL_*} \
+ -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG
+ TARGET_* USE_GCOV TCL_*} \
+ -auto {HAVE_* PACKAGE_*} \
+ -none *
+ proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@
+}
+
+########################################################################
+# Perform some high-level validation on the generated files...
+#
+# 1) Ensure that no unresolved @VAR@ placeholders are in files which
+# use those.
+#
+# 2) TBD
+proc sqlite-post-config-validation {} {
+ # Check #1: ensure that files which get filtered for @VAR@ do not
+ # contain any unresolved @VAR@ refs. That may indicate an
+ # unexported/unused var or a typo.
+ set srcdir $::autosetup(srcdir)
+ foreach f [list Makefile sqlite3.pc \
+ $srcdir/tool/emcc.sh \
+ $srcdir/ext/wasm/config.make] {
+ if {![file exists $f]} continue
+ set lnno 1
+ foreach line [proj-file-content-list $f] {
+ if {[regexp {(@[A-Za-z0-9_]+@)} $line match]} {
+ error "Unresolved reference to $match at line $lnno of $f"
+ }
+ incr lnno
+ }
+ }
+}
+
+########################################################################
+# Handle --with-wasi-sdk[=DIR]
+#
+# This must be run relatively early on because it may change the
+# toolchain and disable a number of config options. However, in the
+# canonical build this must come after [sqlite-check-common-bins].
+proc sqlite-handle-wasi-sdk {} {
+ set wasiSdkDir [opt-val with-wasi-sdk] ; # ??? [lindex [opt-val with-wasi-sdk] end]
+ define HAVE_WASI_SDK 0
+ if {$wasiSdkDir eq ""} {
+ return 0
+ } elseif {$::sqliteConfig(is-cross-compiling)} {
+ proj-fatal "Cannot combine --with-wasi-sdk with cross-compilation"
+ }
+ msg-result "Checking WASI SDK directory \[$wasiSdkDir]... "
+ proj-affirm-files-exist -v {*}[prefix "$wasiSdkDir/bin/" {clang wasm-ld ar}]
+ define HAVE_WASI_SDK 1
+ define WASI_SDK_DIR $wasiSdkDir
+ # Disable numerous options which we know either can't work or are
+ # not useful in this build...
+ msg-result "Using wasi-sdk clang. Disabling CLI shell and modifying config flags:"
+ # Boolean (--enable-/--disable-) flags which must be switched off:
+ foreach opt {
+ dynlink-tools
+ editline
+ gcov
+ icu-collations
+ load-extension
+ readline
+ shared
+ tcl
+ threadsafe
+ } {
+ if {[opt-bool $opt]} {
+ msg-result " --disable-$opt"
+ proj-opt-set $opt 0
+ }
+ }
+ # Non-boolean flags which need to be cleared:
+ foreach opt {
+ with-emsdk
+ with-icu-config
+ with-icu-ldflags
+ with-icu-cflags
+ with-linenoise
+ with-tcl
+ } {
+ if {[proj-opt-was-provided $opt]} {
+ msg-result " removing --$opt"
+ proj-opt-set $opt ""
+ }
+ }
+ # Remember that we now have a discrepancy beteween
+ # $::sqliteConfig(is-cross-compiling) and [proj-is-cross-compiling].
+ set ::sqliteConfig(is-cross-compiling) 1
+
+ #
+ # Changing --host and --target have no effect here except to
+ # possibly cause confusion. Autosetup has finished processing them
+ # by this point.
+ #
+ # host_alias=wasm32-wasi
+ # target=wasm32-wasi
+ #
+ # Merely changing CC, LD, and AR to the wasi-sdk's is enough to get
+ # sqlite3.o building in WASM format.
+ #
+ define CC "${wasiSdkDir}/bin/clang"
+ define LD "${wasiSdkDir}/bin/wasm-ld"
+ define AR "${wasiSdkDir}/bin/ar"
+ #define STRIP "${wasiSdkDir}/bin/strip"
+ return 1
+}; # sqlite-handle-wasi-sdk
+
+########################################################################
+# TCL...
+#
+# sqlite-check-tcl performs most of the --with-tcl and --with-tclsh
+# handling. Some related bits and pieces are performed before and
+# after that function is called.
+#
+# Important [define]'d vars:
+#
+# - HAVE_TCL indicates whether we have a tclsh suitable for building
+# the TCL SQLite extension and, by extension, the testing
+# infrastructure. This must only be 1 for environments where
+# tclConfig.sh can be found.
+#
+# - TCLSH_CMD is the path to the canonical tclsh or "". It never
+# refers to jimtcl.
+#
+# - TCL_CONFIG_SH is the path to tclConfig.sh or "".
+#
+# - TCLLIBDIR is the dir to which libtclsqlite3 gets installed.
+#
+# - BTCLSH = the path to the tcl interpreter used for in-tree code
+# generation. It may be jimtcl or the canonical tclsh but may not
+# be empty - this tree requires TCL to generated numerous
+# components.
+#
+# If --tcl or --with-tcl are provided but no TCL is found, this
+# function fails fatally. If they are not explicitly provided then
+# failure to find TCL is not fatal but a loud warning will be emitted.
+#
+proc sqlite-check-tcl {} {
+ define TCLSH_CMD false ; # Significant is that it exits with non-0
+ define HAVE_TCL 0 ; # Will be enabled via --tcl or a successful search
+ define TCLLIBDIR "" ; # Installation dir for TCL extension lib
+ define TCL_CONFIG_SH ""; # full path to tclConfig.sh
+
+ # Clear out all vars which would be set by tclConfigToAutoDef.sh, so
+ # that the late-config validation of @VARS@ works even if
+ # --disable-tcl is used.
+ foreach k {TCL_INCLUDE_SPEC TCL_LIB_SPEC TCL_STUB_LIB_SPEC TCL_EXEC_PREFIX TCL_VERSION} {
+ define $k ""
+ }
+
+ file delete -force ".tclenv.sh"; # ensure no stale state from previous configures.
+ if {![opt-bool tcl]} {
+ proj-indented-notice {
+ NOTE: TCL is disabled via --disable-tcl. This means that none
+ of the TCL-based components will be built, including tests
+ and sqlite3_analyzer.
+ }
+ return
+ }
+ # TODO: document the steps this is taking.
+ set srcdir $::autosetup(srcdir)
+ msg-result "Checking for a suitable tcl... "
+ proj-assert [proj-opt-truthy tcl]
+ set use_tcl 1
+ set with_tclsh [opt-val with-tclsh]
+ set with_tcl [opt-val with-tcl]
+ if {"prefix" eq $with_tcl} {
+ set with_tcl [get-define prefix]
+ }
+ msg-debug "sqlite-check-tcl: use_tcl ${use_tcl}"
+ msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
+ msg-debug "sqlite-check-tcl: with_tcl=$with_tcl"
+ if {"" eq $with_tclsh && "" eq $with_tcl} {
+ # If neither --with-tclsh nor --with-tcl are provided, try to find
+ # a workable tclsh.
+ set with_tclsh [proj-first-bin-of tclsh9.0 tclsh8.6 tclsh]
+ msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
+ }
+
+ set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
+ if {"" ne $with_tclsh} {
+ # --with-tclsh was provided or found above. Validate it and use it
+ # to trump any value passed via --with-tcl=DIR.
+ if {![file-isexec $with_tclsh]} {
+ proj-fatal "TCL shell $with_tclsh is not executable"
+ } else {
+ define TCLSH_CMD $with_tclsh
+ #msg-result "Using tclsh: $with_tclsh"
+ }
+ if {$doConfigLookup &&
+ [catch {exec $with_tclsh $srcdir/tool/find_tclconfig.tcl} result] == 0} {
+ set with_tcl $result
+ }
+ if {"" ne $with_tcl && [file isdir $with_tcl]} {
+ msg-result "$with_tclsh recommends the tclConfig.sh from $with_tcl"
+ } else {
+ proj-warn "$with_tclsh is unable to recommend a tclConfig.sh"
+ set use_tcl 0
+ }
+ }
+ set cfg ""
+ set tclSubdirs {tcl9.0 tcl8.6 lib}
+ while {$use_tcl} {
+ if {"" ne $with_tcl} {
+ # Ensure that we can find tclConfig.sh under ${with_tcl}/...
+ if {$doConfigLookup} {
+ if {[file readable "${with_tcl}/tclConfig.sh"]} {
+ set cfg "${with_tcl}/tclConfig.sh"
+ } else {
+ foreach i $tclSubdirs {
+ if {[file readable "${with_tcl}/$i/tclConfig.sh"]} {
+ set cfg "${with_tcl}/$i/tclConfig.sh"
+ break
+ }
+ }
+ }
+ }
+ if {"" eq $cfg} {
+ proj-fatal "No tclConfig.sh found under ${with_tcl}"
+ }
+ } else {
+ # If we have not yet found a tclConfig.sh file, look in
+ # $libdir which is set automatically by autosetup or by the
+ # --prefix command-line option. See
+ # https://sqlite.org/forum/forumpost/e04e693439a22457
+ set libdir [get-define libdir]
+ if {[file readable "${libdir}/tclConfig.sh"]} {
+ set cfg "${libdir}/tclConfig.sh"
+ } else {
+ foreach i $tclSubdirs {
+ if {[file readable "${libdir}/$i/tclConfig.sh"]} {
+ set cfg "${libdir}/$i/tclConfig.sh"
+ break
+ }
+ }
+ }
+ if {![file readable $cfg]} {
+ break
+ }
+ }
+ msg-result "Using tclConfig.sh: $cfg"
+ break
+ }
+ define TCL_CONFIG_SH $cfg
+ # Export a subset of tclConfig.sh to the current TCL-space. If $cfg
+ # is an empty string, this emits empty-string entries for the
+ # various options we're interested in.
+ eval [exec sh "$srcdir/tool/tclConfigShToAutoDef.sh" "$cfg"]
+ # ---------^^ a Windows/msys workaround, without which it cannot
+ # exec a .sh file: https://sqlite.org/forum/forumpost/befb352a42a7cd6d
+
+ if {"" eq $with_tclsh && $cfg ne ""} {
+ # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
+ # based on info from tclConfig.sh.
+ proj-assert {"" ne [get-define TCL_EXEC_PREFIX]}
+ set with_tclsh [get-define TCL_EXEC_PREFIX]/bin/tclsh[get-define TCL_VERSION]
+ if {![file-isexec $with_tclsh]} {
+ set with_tclsh2 [get-define TCL_EXEC_PREFIX]/bin/tclsh
+ if {![file-isexec $with_tclsh2]} {
+ proj-warn "Cannot find a usable tclsh (tried: $with_tclsh $with_tclsh2)"
+ } else {
+ set with_tclsh $with_tclsh2
+ }
+ }
+ }
+ define TCLSH_CMD $with_tclsh
+ if {$use_tcl} {
+ # Set up the TCLLIBDIR
+ #
+ # 2024-10-28: calculation of TCLLIBDIR is now done via the shell
+ # in main.mk (search it for T.tcl.env.sh) so that
+ # static/hand-written makefiles which import main.mk do not have
+ # to define that before importing main.mk. Even so, we export
+ # TCLLIBDIR from here, which will cause the canonical makefile to
+ # use this one rather than to re-calculate it at make-time.
+ set tcllibdir [get-env TCLLIBDIR ""]
+ if {"" eq $tcllibdir} {
+ # Attempt to extract TCLLIBDIR from TCL's $auto_path
+ if {"" ne $with_tclsh &&
+ [catch {exec echo "puts stdout \$auto_path" | "$with_tclsh"} result] == 0} {
+ foreach i $result {
+ if {[file isdir $i]} {
+ set tcllibdir $i/sqlite3
+ break
+ }
+ }
+ } else {
+ proj-warn "Cannot determine TCLLIBDIR."
+ # The makefile will fail fatally in this case if a target is
+ # invoked which requires TCLLIBDIR.
+ }
+ }
+ #if {"" ne $tcllibdir} { msg-result "TCLLIBDIR = ${tcllibdir}"; }
+ define TCLLIBDIR $tcllibdir
+ }; # find TCLLIBDIR
+
+ if {[file-isexec $with_tclsh]} {
+ msg-result "Using tclsh: $with_tclsh"
+ if {$cfg ne ""} {
+ define HAVE_TCL 1
+ } else {
+ proj-warn "Found tclsh but no tclConfig.sh."
+ }
+ }
+ show-notices
+ # If TCL is not found: if it was explicitly requested then fail
+ # fatally, else just emit a warning. If we can find the APIs needed
+ # to generate a working JimTCL then that will suffice for build-time
+ # TCL purposes (see: proc sqlite-determine-codegen-tcl).
+ if {![get-define HAVE_TCL] &&
+ ([proj-opt-was-provided tcl] || [proj-opt-was-provided with-tcl])} {
+ proj-fatal "TCL support was requested but no tclConfig.sh could be found."
+ }
+ if {"" eq $cfg} {
+ proj-assert {0 == [get-define HAVE_TCL]}
+ proj-indented-notice {
+ WARNING: Cannot find a usable tclConfig.sh file. Use
+ --with-tcl=DIR to specify a directory where tclConfig.sh can be
+ found. SQLite does not use TCL internally, but some optional
+ components require TCL, including tests and sqlite3_analyzer.
+ }
+ }
+}; # sqlite-check-tcl
+
+########################################################################
+# sqlite-determine-codegen-tcl checks which TCL to use as a code
+# generator. By default, prefer jimsh simply because we have it
+# in-tree (it's part of autosetup) unless --with-tclsh=X is used, in
+# which case prefer X.
+#
+# Returns the human-readable name of the TCL it selects. Fails fatally
+# if it cannot detect a TCL appropriate for code generation.
+#
+# Defines:
+#
+# - BTCLSH = the TCL shell used for code generation. It may set this
+# to an unexpanded makefile var name.
+#
+# - CFLAGS_JIMSH = any flags needed for buildng a BTCLSH-compatible
+# jimsh. The defaults may be passed on to configure as
+# CFLAGS_JIMSH=...
+proc sqlite-determine-codegen-tcl {} {
+ msg-result "Checking for TCL to use for code generation... "
+ define CFLAGS_JIMSH [proj-get-env CFLAGS_JIMSH {-O1}]
+ set cgtcl [opt-val with-tclsh jimsh]
+ if {"jimsh" ne $cgtcl} {
+ # When --with-tclsh=X is used, use that for all TCL purposes,
+ # including in-tree code generation, per developer request.
+ define BTCLSH "\$(TCLSH_CMD)"
+ return $cgtcl
+ }
+ set flagsToRestore {CC CFLAGS AS_CFLAGS CPPFLAGS AS_CPPFLAGS LDFLAGS LINKFLAGS LIBS CROSS}
+ define-push $flagsToRestore {
+ # We have to swap CC to CC_FOR_BUILD for purposes of the various
+ # [cc-...] tests below. Recall that --with-wasi-sdk may have
+ # swapped out CC with one which is not appropriate for this block.
+ # Per consulation with autosetup's creator, doing this properly
+ # requires us to [define-push] the whole $flagsToRestore list
+ # (plus a few others which are not relevant in this tree).
+ #
+ # These will get set to their previous values at the end of this
+ # block.
+ foreach flag $flagsToRestore {define $flag ""}
+ define CC [get-define CC_FOR_BUILD]
+ # These headers are technically optional for JimTCL but necessary if
+ # we want to use it for code generation:
+ set sysh [cc-check-includes dirent.h sys/time.h]
+ # jimsh0.c hard-codes #define's for HAVE_DIRENT_H and
+ # HAVE_SYS_TIME_H on the platforms it supports, so we do not
+ # need to add -D... flags for those. We check for them here only
+ # so that we can avoid the situation that we later, at
+ # make-time, try to compile jimsh but it then fails due to
+ # missing headers (i.e. fail earlier rather than later).
+ if {$sysh && [cc-check-functions realpath]} {
+ define-append CFLAGS_JIMSH -DHAVE_REALPATH
+ define BTCLSH "\$(JIMSH)"
+ set ::sqliteConfig(use-jim-for-codegen) 1
+ } elseif {$sysh && [cc-check-functions _fullpath]} {
+ # _fullpath() is a Windows API. It's not entirely clear
+ # whether we need to add {-DHAVE_SYS_TIME_H -DHAVE_DIRENT_H}
+ # to CFLAGS_JIMSH in this case. On MinGW32 we definitely do
+ # not want to because it already hard-codes them. On _MSC_VER
+ # builds it does not.
+ define-append CFLAGS_JIMSH -DHAVE__FULLPATH
+ define BTCLSH "\$(JIMSH)"
+ set ::sqliteConfig(use-jim-for-codegen) 1
+ } elseif {[file-isexec [get-define TCLSH_CMD]]} {
+ set cgtcl [get-define TCLSH_CMD]
+ define BTCLSH "\$(TCLSH_CMD)"
+ } else {
+ # One last-ditch effort to find TCLSH_CMD: use info from
+ # tclConfig.sh to try to find a tclsh
+ if {"" eq [get-define TCLSH_CMD]} {
+ set tpre [get-define TCL_EXEC_PREFIX]
+ if {"" ne $tpre} {
+ set tv [get-define TCL_VERSION]
+ if {[file-isexec "${tpre}/bin/tclsh${tv}"]} {
+ define TCLSH_CMD "${tpre}/bin/tclsh${tv}"
+ } elseif {[file-isexec "${tpre}/bin/tclsh"]} {
+ define TCLSH_CMD "${tpre}/bin/tclsh"
+ }
+ }
+ }
+ set cgtcl [get-define TCLSH_CMD]
+ if {![file-isexec $cgtcl]} {
+ proj-fatal "Cannot find a tclsh to use for code generation."
+ }
+ define BTCLSH "\$(TCLSH_CMD)"
+ }
+ }; # CC swap-out
+ return $cgtcl
+}; # sqlite-determine-codegen-tcl
+
+########################################################################
+# Runs sqlite-check-tcl and sqlite-determine-codegen-tcl.
+proc sqlite-handle-tcl {} {
+ sqlite-check-tcl
+ msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
+}
+
+########################################################################
+# If the --dump-defines configure flag is provided then emit a list of
+# all [define] values to config.defines.txt, else do nothing.
+proc sqlite-dump-defines {} {
+ proj-if-opt-truthy dump-defines {
+ make-config-header $::sqliteConfig(dump-defines-txt) \
+ -bare {SQLITE_OS* SQLITE_DEBUG USE_*} \
+ -str {BIN_* CC LD AR LDFLAG* OPT_*} \
+ -auto {*}
+ # achtung: ^^^^ whichever SQLITE_OS_foo flag which is set to 0 will
+ # get _undefined_ here unless it's part of the -bare set.
+ if {"" ne $::sqliteConfig(dump-defines-json)} {
+ msg-result "--dump-defines is creating $::sqliteConfig(dump-defines-json)"
+ ########################################################################
+ # Dump config-defines.json...
+ # Demonstrate (mis?)handling of spaces in JSON-export array values:
+ # define-append OPT_FOO.list {"-DFOO=bar baz" -DBAR="baz barre"}
+ define OPT_FEATURE_FLAGS.list [get-define OPT_FEATURE_FLAGS]
+ define OPT_SHELL.list [get-define OPT_SHELL]
+ set dumpDefsOpt {
+ -bare {SIZEOF_* HAVE_DECL_*}
+ -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG TARGET_* USE_GCOV TCL_*}
+ -array {*.list}
+ -auto {OPT_* PACKAGE_* HAVE_*}
+ }
+ if {[opt-bool defines-json-include-lowercase]} {
+ lappend dumpDefsOpt -none {lib_*} ; # remnants from proj-check-function-in-lib and friends
+ lappend dumpDefsOpt -auto {[a-z]*}
+ }
+ lappend dumpDefsOpt -none *
+ proj-dump-defs-json $::sqliteConfig(dump-defines-json) {*}$dumpDefsOpt
+ undefine OPT_FEATURE_FLAGS.list
+ undefine OPT_SHELL.list
+ }
+ }
+}
diff --git a/doc/compile-for-unix.md b/doc/compile-for-unix.md
index 7e3784d69..ce76b97ba 100644
--- a/doc/compile-for-unix.md
+++ b/doc/compile-for-unix.md
@@ -4,6 +4,8 @@ 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.
+See the companion document ([](./compile-for-windows.md>)) for
+guidance on building for Windows.
1. Install a C-compiler. GCC or Clang both work fine. If you are
reading this document, you've probably already done that.
@@ -12,6 +14,8 @@ are general and should work on most any modern unix platform.
we'll do a private install in the $HOME/local directory,
but you can make adjustments to install TCL wherever you like.
This document assumes you are working with TCL version 9.0.
+ See also the [](./tcl-extension-testing.md) document that contains
+ more details on compiling Tcl for use with SQLite.
<ol type="a">
<li>Get the TCL source archive, perhaps from
<https://www.tcl.tk/software/tcltk/download.html>
@@ -45,7 +49,7 @@ are general and should work on most any modern unix platform.
<li> `make sqldiff`
<li> `make sqlite3_rsync`
</ul>
- <p>None of the targets above require TCL. TCL is only needed
+ <p>None of the targets above require TCL. TCL is needed
for the following targets:
<ul>
<li> `make tclextension-install`
diff --git a/doc/compile-for-windows.md b/doc/compile-for-windows.md
index b3a48549a..2e6228633 100644
--- a/doc/compile-for-windows.md
+++ b/doc/compile-for-windows.md
@@ -1,12 +1,23 @@
# 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 2024-10-09:
+Below are step-by-step instructions on how to build SQLite from
+canonical source on a new Windows 11 PC, as of 2024-10-09.
+See [](./compile-for-unix.md) for a similar guide for unix-like
+systems, including MacOS.
1. Install Microsoft Visual Studio. The free "community edition"
will work fine. Do a standard install for C++ development.
SQLite only needs the
"cl" compiler and the "nmake" build tool.
+ <ul><li><b>Note:</b>
+ VS2015 or later is required for the procedures below to
+ all work. You *might* be able to get the build to work with
+ earlier versions of MSVC, but in that case the TCL installation
+ of step 3 will be required, since the "jimsh0.c" program of
+ Autosetup that is used as a substitute for "tclsh.exe" won't
+ compile with versions of Visual Studio prior to VS2015. In any
+ event, building SQLite from canonical source code on Windows
+ is not supported for earlier versions of Visual Studio.</ul>
2. Under the "Start" menu, find "All Apps" then go to "Visual Studio 20XX"
and find "x64 Native Tools Command Prompt for VS 20XX". Pin that
@@ -24,16 +35,21 @@ canonical source on a new Windows 11 PC, as of 2024-10-09:
"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.
+ See [](./tcl-extension-testing.md#windows) for guidance on how
+ to compile TCL version 8.6 for use with SQLite.
<ol type="a">
<li>Get the TCL source archive, perhaps from
<https://www.tcl.tk/software/tcltk/download.html>
or <https://sqlite.org/tmp/tcl9.0.0.tar.gz>.
<li>Untar or unzip the source archive. CD into the "win/" subfolder
of the source tree.
- <li>Run: `nmake /f makefile.vc release`
- <li>Run: `nmake /f makefile.vc INSTALLDIR=c:\Tcl install`
+ <li>Run: `nmake /f makefile.vc INSTALLDIR=c:\Tcl release`
+ <li>Run: `nmake /f makefile.vc INSTALLDIR=c:\Tcl install` <br>
+ Notes:
+ <ol type="i">
+ <li> The previous two `nmake` commands must be run separately.
+ <li> Also, the INSTALLDIR=... argument is required on both.
+ </ol>
<li><i>Optional:</i> CD to `c:\Tcl\bin` and make a copy of
`tclsh90.exe` over into just `tclsh.exe`.
<li><i>Optional:</i>
diff --git a/doc/tcl-extension-testing.md b/doc/tcl-extension-testing.md
new file mode 100644
index 000000000..df5f6537b
--- /dev/null
+++ b/doc/tcl-extension-testing.md
@@ -0,0 +1,208 @@
+# Test Procedures For The SQLite TCL Extension
+
+## 1.0 Background
+
+The SQLite TCL extension logic (in the
+"[tclsqlite.c](/file/src/tclsqlite.c)" source
+file) is statically linked into "textfixture" executable
+which is the program used to do most of the testing
+associated with "make test", "make devtest", and/or
+"make releasetest". So the functionality of the SQLite
+TCL extension is thoroughly vetted during normal testing. The
+procedures below are designed to test the loadable extension
+aspect of the SQLite TCL extension, and in particular to verify
+that the "make tclextension-install" build target works and that
+an ordinary tclsh can subsequently run "package require sqlite3".
+
+This procedure can also be used as a template for how to set up
+a local TCL+SQLite development environment. In other words, it
+can be be used as a guide on how to compile per-user copies of
+Tcl that are used to develop, test, and debug SQLite. In that
+case, perhaps make minor changes to the procedure such as:
+
+ * Make TCLBUILD directory is permanent.
+ * Enable debugging symbols on the Tcl library build.
+ * Reduce the optimization level to -O0 for easier debugging.
+ * Also compile "wish" to go with each "tclsh".
+
+
+<a id="unix"></a>
+## 2.0 Testing On Unix-like Systems (Including Mac)
+
+See also the [](./compile-for-unix.md) document which provides another
+perspective on how to compile SQLite on unix-like systems.
+
+### 2.1 Setup
+
+<ol type="1">
+<li value="1">
+ [Fossil](https://fossil-scm.org/) installed.
+<li> Check out source code and set environment variables:
+ <ol type="a">
+ <li> **TCLSOURCE** &rarr;
+ The top-level directory of a Fossil check-out of the TCL source tree.
+ <li> **SQLITESOURCE** &rarr;
+ A Fossil check-out of the SQLite source tree.
+ <li> **TCLBUILD** &rarr;
+ A directory that does not exist at the start of the test and which
+ will be deleted at the end of the test, and that will contain the
+ test builds of the TCL libraries and the SQLite TCL Extensions.
+ </ol>
+</ol>
+
+### 2.2 Testing TCL 8.6 on unix
+
+<ol type="1">
+<li value="3"> `mkdir -p $TCLBUILD/tcl86`
+<li> `cd $TCLSOURCE/unix`
+<li> `fossil up core-8-6-16` <br>
+ &uarr; Or some other version of Tcl8.6.
+<li> `fossil clean -x`
+<li> `./configure --prefix=$TCLBUILD/tcl86 --disable-shared` <br>
+ &uarr; The --disable-shared is to avoid the need to set LD_LIBRARY_PATH
+ when using this Tcl build.
+<li> `make install`
+<li> `cd $SQLITESOURCE`
+<li> `fossil clean -x`
+<li> `./configure --with-tclsh=$TCLBUILD/tcl86/bin/tclsh8.6 --all`
+<li> `make tclextension-install` <br>
+ &uarr; Verify extension installed at $TCLBUILD/tcl86/lib/tcl8.6/sqlite3.*
+<li> `make tclextension-list` <br>
+ &uarr; Verify TCL extension correctly installed.
+<li> `make tclextension-verify` <br>
+ &uarr; Verify that the correct version is installed.
+<li> `$TCLBUILD/tcl86/bin/tclsh8.6 test/testrunner.tcl release --explain` <br>
+ &uarr; Verify thousands of lines of output with no errors. Or
+ consider running "devtest" without --explain instead of "release".
+</ol>
+
+### 2.3 Testing TCL 9.0 on unix
+
+<ol>
+<li value="16"> `mkdir -p $TCLBUILD/tcl90`
+<li> `fossil up core-9-0-0` <br>
+ &uarr; Or some other version of Tcl9
+<li> `fossil clean -x`
+<li> `./configure --prefix=$TCLBUILD/tcl90 --disable-shared` <br>
+ &uarr; The --disable-shared is to avoid the need to set LD_LIBRARY_PATH
+ when using this Tcl build.
+<li> `make install`
+<li> `cp -r ../library $TCLBUILD/tcl90/lib/tcl9.0` <br>
+ &uarr; The Tcl library is not installed by "make install" for Tcl9.0 unless
+ you also include the --disable-zipfs to ./configure. But if you do that
+ then the generated tclsh9.0 is no longer stand-alone. On the other hand,
+ if you don't install the Tcl library, other programs like testfixture
+ won't be able to find the Tcl library and hence won't work. This
+ extra installation step resolves the dilemma.
+ This step is not required when building Tcl8.6, which lacks support for
+ zipfs and hence always installs its Tcl library.
+<li> `cd $SQLITESOURCE`
+<li> `fossil clean -x`
+<li> `./configure --with-tclsh=$TCLBUILD/tcl90/bin/tclsh9.0 --all`
+<li> `make tclextension-install` <br>
+ &uarr; Verify extension installed at $TCLBUILD/tcl90/lib/sqlite3.*
+<li> `make tclextension-list` <br>
+ &uarr; Verify TCL extension correctly installed.
+<li> `make tclextension-verify`
+<li> `$TCLBUILD/tcl90/bin/tclsh9.0 test/testrunner.tcl release --explain` <br>
+ &uarr; Verify thousands of lines of output with no errors. Or
+ consider running "devtest" without --explain instead of "release".
+</ol>
+
+### 2.4 Cleanup
+
+<ol type="1">
+<li value="29"> `rm -rf $TCLBUILD`
+</ol>
+
+<a id="windows"></a>
+## 3.0 Testing On Windows
+
+See also the [](./compile-for-windows.md) document which provides another
+perspective on how to compile SQLite on Windows.
+
+### 3.1 Setup for Windows
+
+<ol type="1">
+<li value="1">
+ [Fossil](https://fossil-scm.org/) installed.
+<li>
+ Unix-like command-line tools installed. Example:
+ [unxutils](https://unxutils.sourceforge.net/)
+<li> [Visual Studio](https://visualstudio.microsoft.com/vs/community/)
+ installed. VS2015 or later required.
+<li> Check out source code and set environment variables.
+ <ol type="a">
+ <li> **TCLSOURCE** &rarr;
+ The top-level directory of a Fossil check-out of the TCL source tree.
+ <li> **SQLITESOURCE** &rarr;
+ A Fossil check-out of the SQLite source tree.
+ <li> **TCLBUILD** &rarr;
+ A directory that does not exist at the start of the test and which
+ will be deleted at the end of the test, and that will contain the
+ test builds of the TCL libraries and the SQLite TCL Extensions.
+ <li> **ORIGINALPATH** &rarr;
+ The original value of %PATH%. In other words, set as follows:
+ `set ORIGINALPATH %PATH%`
+ </ol>
+</ol>
+
+### 3.2 Testing TCL 8.6 on Windows
+
+<ol type="1">
+<li value="5"> `mkdir %TCLBUILD%\tcl86`
+<li> `cd %TCLSOURCE%\win`
+<li> `fossil up core-8-6-16` <br>
+ &uarr; Or some other version of Tcl8.6.
+<li> `fossil clean -x`
+<li> `set INSTALLDIR=%TCLBUILD%\tcl86`
+<li> `nmake /f makefile.vc release` <br>
+ &udarr; You *must* invoke the "release" and "install" targets
+ using separate "nmake" commands or tclsh86t.exe won't be
+ installed.
+<li> `nmake /f makefile.vc install`
+<li> `cd %SQLITESOURCE%`
+<li> `fossil clean -x`
+<li> `set TCLDIR=%TCLBUILD%\tcl86`
+<li> `set PATH=%TCLBUILD%\tcl86\bin;%ORIGINALPATH%`
+<li> `set TCLSH_CMD=%TCLBUILD%\tcl86\bin\tclsh86t.exe`
+<li> `nmake /f Makefile.msc tclextension-install` <br>
+ &uarr; Verify extension installed at %TCLBUILD%\\tcl86\\lib\\tcl8.6\\sqlite3.*
+<li> `nmake /f Makefile.msc tclextension-verify`
+<li>`tclsh86t test/testrunner.tcl release --explain` <br>
+ &uarr; Verify thousands of lines of output with no errors. Or
+ consider running "devtest" without --explain instead of "release".
+</ol>
+
+### 3.3 Testing TCL 9.0 on Windows
+
+<ol>
+<li value="20"> `mkdir %TCLBUILD%\tcl90`
+<li> `cd %TCLSOURCE%\win`
+<li> `fossil up core-9-0-0` <br>
+ &uarr; Or some other version of Tcl9
+<li> `fossil clean -x`
+<li> `set INSTALLDIR=%TCLBUILD%\tcl90`
+<li> `nmake /f makefile.vc release` <br>
+ &udarr; You *must* invoke the "release" and "install" targets
+ using separate "nmake" commands or tclsh90.exe won't be
+ installed.
+<li> `nmake /f makefile.vc install`
+<li> `cd %SQLITESOURCE%`
+<li> `fossil clean -x`
+<li> `set TCLDIR=%TCLBUILD%\tcl90`
+<li> `set PATH=%TCLBUILD%\tcl90\bin;%ORIGINALPATH%`
+<li> `set TCLSH_CMD=%TCLBUILD%\tcl90\bin\tclsh90.exe`
+<li> `nmake /f Makefile.msc tclextension-install` <br>
+ &uarr; Verify extension installed at %TCLBUILD%\\tcl90\\lib\\sqlite3.*
+<li> `nmake /f Makefile.msc tclextension-verify`
+<li> `tclsh90 test/testrunner.tcl release --explain` <br>
+ &uarr; Verify thousands of lines of output with no errors. Or
+ consider running "devtest" without --explain instead of "release".
+</ol>
+
+### 3.4 Cleanup
+
+<ol type="1">
+<li value="35"> `rm -rf %TCLBUILD%`
+</ol>
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index e58f256a4..2b2c3b8d2 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -5788,6 +5788,24 @@ static void fts3EvalRestart(
}
/*
+** Expression node pExpr is an MSR phrase. This function restarts pExpr
+** so that it is a regular phrase query, not an MSR. SQLITE_OK is returned
+** if successful, or an SQLite error code otherwise.
+*/
+int sqlite3Fts3MsrCancel(Fts3Cursor *pCsr, Fts3Expr *pExpr){
+ int rc = SQLITE_OK;
+ if( pExpr->bEof==0 ){
+ i64 iDocid = pExpr->iDocid;
+ fts3EvalRestart(pCsr, pExpr, &rc);
+ while( rc==SQLITE_OK && pExpr->iDocid!=iDocid ){
+ fts3EvalNextRow(pCsr, pExpr, &rc);
+ if( pExpr->bEof ) rc = FTS_CORRUPT_VTAB;
+ }
+ }
+ return rc;
+}
+
+/*
** After allocating the Fts3Expr.aMI[] array for each phrase in the
** expression rooted at pExpr, the cursor iterates through all rows matched
** by pExpr, calling this function for each row. This function increments
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
index 3b236faf4..77e6737af 100644
--- a/ext/fts3/fts3Int.h
+++ b/ext/fts3/fts3Int.h
@@ -640,6 +640,7 @@ int sqlite3Fts3MsrIncrNext(
int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
+int sqlite3Fts3MsrCancel(Fts3Cursor*, Fts3Expr*);
/* fts3_tokenize_vtab.c */
int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*));
diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c
index 80f62eb3b..8a6ab8ea6 100644
--- a/ext/fts3/fts3_snippet.c
+++ b/ext/fts3/fts3_snippet.c
@@ -1587,6 +1587,22 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
}
/*
+** If expression pExpr is a phrase expression that uses an MSR query,
+** restart it as a regular, non-incremental query. Return SQLITE_OK
+** if successful, or an SQLite error code otherwise.
+*/
+static int fts3ExprRestartIfCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ TermOffsetCtx *p = (TermOffsetCtx*)ctx;
+ int rc = SQLITE_OK;
+ UNUSED_PARAMETER(iPhrase);
+ if( pExpr->pPhrase && pExpr->pPhrase->bIncr ){
+ rc = sqlite3Fts3MsrCancel(p->pCsr, pExpr);
+ pExpr->pPhrase->bIncr = 0;
+ }
+ return rc;
+}
+
+/*
** Implementation of offsets() function.
*/
void sqlite3Fts3Offsets(
@@ -1622,6 +1638,12 @@ void sqlite3Fts3Offsets(
sCtx.iDocid = pCsr->iPrevId;
sCtx.pCsr = pCsr;
+ /* If a query restart will be required, do it here, rather than later of
+ ** after pointers to poslist buffers that may be invalidated by a restart
+ ** have been saved. */
+ rc = sqlite3Fts3ExprIterate(pCsr->pExpr, fts3ExprRestartIfCb, (void*)&sCtx);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+
/* Loop through the table columns, appending offset information to
** string-buffer res for each column.
*/
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index 8730b6950..f56aa82e8 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -778,11 +778,13 @@ static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
/*
** Close the read-only blob handle, if it is open.
*/
-void sqlite3Fts5IndexCloseReader(Fts5Index *p){
+static void fts5IndexCloseReader(Fts5Index *p){
if( p->pReader ){
+ int rc;
sqlite3_blob *pReader = p->pReader;
p->pReader = 0;
- sqlite3_blob_close(pReader);
+ rc = sqlite3_blob_close(pReader);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
}
}
@@ -807,7 +809,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
assert( p->pReader==0 );
p->pReader = pBlob;
if( rc!=SQLITE_OK ){
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
}
if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
}
@@ -891,9 +893,13 @@ static int fts5IndexPrepareStmt(
){
if( p->rc==SQLITE_OK ){
if( zSql ){
- p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
+ int rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB,
ppStmt, 0);
+ /* If this prepare() call fails with SQLITE_ERROR, then one of the
+ ** %_idx or %_data tables has been removed or modified. Call this
+ ** corruption. */
+ p->rc = (rc==SQLITE_ERROR ? SQLITE_CORRUPT : rc);
}else{
p->rc = SQLITE_NOMEM;
}
@@ -5005,6 +5011,14 @@ static int fts5IndexReturn(Fts5Index *p){
return rc;
}
+/*
+** Close the read-only blob handle, if it is open.
+*/
+void sqlite3Fts5IndexCloseReader(Fts5Index *p){
+ fts5IndexCloseReader(p);
+ fts5IndexReturn(p);
+}
+
typedef struct Fts5FlushCtx Fts5FlushCtx;
struct Fts5FlushCtx {
Fts5Index *pIdx;
@@ -5462,8 +5476,11 @@ static void fts5DoSecureDelete(
** This is called as part of flushing a delete to disk in 'secure-delete'
** mode. It edits the segments within the database described by argument
** pStruct to remove the entries for term zTerm, rowid iRowid.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** has occurred. Any error code is also stored in the Fts5Index handle.
*/
-static void fts5FlushSecureDelete(
+static int fts5FlushSecureDelete(
Fts5Index *p,
Fts5Structure *pStruct,
const char *zTerm,
@@ -5473,6 +5490,24 @@ static void fts5FlushSecureDelete(
const int f = FTS5INDEX_QUERY_SKIPHASH;
Fts5Iter *pIter = 0; /* Used to find term instance */
+ /* If the version number has not been set to SECUREDELETE, do so now. */
+ if( p->pConfig->iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE ){
+ Fts5Config *pConfig = p->pConfig;
+ sqlite3_stmt *pStmt = 0;
+ fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
+ "REPLACE INTO %Q.'%q_config' VALUES ('version', %d)",
+ pConfig->zDb, pConfig->zName, FTS5_CURRENT_VERSION_SECUREDELETE
+ ));
+ if( p->rc==SQLITE_OK ){
+ int rc;
+ sqlite3_step(pStmt);
+ rc = sqlite3_finalize(pStmt);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
+ pConfig->iCookie++;
+ pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
+ }
+ }
+
fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
if( fts5MultiIterEof(p, pIter)==0 ){
i64 iThis = fts5MultiIterRowid(pIter);
@@ -5490,6 +5525,7 @@ static void fts5FlushSecureDelete(
}
fts5MultiIterFree(pIter);
+ return p->rc;
}
@@ -5573,8 +5609,9 @@ static void fts5FlushOneHash(Fts5Index *p){
** using fts5FlushSecureDelete(). */
if( bSecureDelete ){
if( eDetail==FTS5_DETAIL_NONE ){
- if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
- fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ if( iOff<nDoclist && pDoclist[iOff]==0x00
+ && !fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid)
+ ){
iOff++;
if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
iOff++;
@@ -5583,8 +5620,9 @@ static void fts5FlushOneHash(Fts5Index *p){
continue;
}
}
- }else if( (pDoclist[iOff] & 0x01) ){
- fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ }else if( (pDoclist[iOff] & 0x01)
+ && !fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid)
+ ){
if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
iOff++;
continue;
@@ -6651,6 +6689,7 @@ static void fts5SetupPrefixIter(
}
pData = fts5IdxMalloc(p, sizeof(*pData)+s.doclist.n+FTS5_DATA_ZERO_PADDING);
+ assert( pData!=0 || p->rc!=SQLITE_OK );
if( pData ){
pData->p = (u8*)&pData[1];
pData->nn = pData->szLeaf = s.doclist.n;
@@ -6658,6 +6697,7 @@ static void fts5SetupPrefixIter(
fts5MultiIterNew2(p, pData, bDesc, ppIter);
}
+ assert( (*ppIter)!=0 || p->rc!=SQLITE_OK );
if( p->rc==SQLITE_OK && s.pTokendata ){
fts5TokendataIterSortMap(p, s2.pT);
(*ppIter)->pTokenDataIter = s2.pT;
@@ -6706,7 +6746,7 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
int sqlite3Fts5IndexSync(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
return fts5IndexReturn(p);
}
@@ -6717,11 +6757,10 @@ int sqlite3Fts5IndexSync(Fts5Index *p){
** records must be invalidated.
*/
int sqlite3Fts5IndexRollback(Fts5Index *p){
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
fts5IndexDiscardData(p);
fts5StructureInvalidate(p);
- /* assert( p->rc==SQLITE_OK ); */
- return SQLITE_OK;
+ return fts5IndexReturn(p);
}
/*
@@ -6922,6 +6961,16 @@ static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
pSeg->pLeaf = 0;
}
+static void fts5IterClose(Fts5IndexIter *pIndexIter){
+ if( pIndexIter ){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5Index *pIndex = pIter->pIndex;
+ fts5TokendataIterDelete(pIter->pTokenDataIter);
+ fts5MultiIterFree(pIter);
+ fts5IndexCloseReader(pIndex);
+ }
+}
+
/*
** This function appends iterator pAppend to Fts5TokenDataIter pIn and
** returns the result.
@@ -6949,7 +6998,7 @@ static Fts5TokenDataIter *fts5AppendTokendataIter(
}
}
if( p->rc ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pAppend);
+ fts5IterClose((Fts5IndexIter*)pAppend);
}else{
pRet->apIter[pRet->nIter++] = pAppend;
}
@@ -7162,7 +7211,7 @@ static Fts5Iter *fts5SetupTokendataIter(
fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
}
if( p->rc ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ fts5IterClose((Fts5IndexIter*)pNew);
break;
}
@@ -7227,7 +7276,7 @@ static Fts5Iter *fts5SetupTokendataIter(
** not point to any terms that match the query. So delete it and break
** out of the loop - all required iterators have been collected. */
if( pSmall==0 ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ fts5IterClose((Fts5IndexIter*)pNew);
break;
}
@@ -7289,6 +7338,7 @@ int sqlite3Fts5IndexQuery(
int iIdx = 0; /* Index to search */
int iPrefixIdx = 0; /* +1 prefix index */
int bTokendata = pConfig->bTokendata;
+ assert( buf.p!=0 );
if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
/* The NOTOKENDATA flag is set when each token in a tokendata=1 table
@@ -7355,9 +7405,9 @@ int sqlite3Fts5IndexQuery(
}
if( p->rc ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
+ fts5IterClose((Fts5IndexIter*)pRet);
pRet = 0;
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
}
*ppIter = (Fts5IndexIter*)pRet;
@@ -7450,6 +7500,7 @@ static int fts5SetupPrefixIterTokendata(
memset(&ctx, 0, sizeof(ctx));
fts5BufferGrow(&p->rc, &token, nToken+1);
+ assert( token.p!=0 || p->rc!=SQLITE_OK );
ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT));
if( p->rc==SQLITE_OK ){
@@ -7606,11 +7657,9 @@ int sqlite3Fts5IndexIterWriteTokendata(
*/
void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
if( pIndexIter ){
- Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- Fts5Index *pIndex = pIter->pIndex;
- fts5TokendataIterDelete(pIter->pTokenDataIter);
- fts5MultiIterFree(pIter);
- sqlite3Fts5IndexCloseReader(pIndex);
+ Fts5Index *pIndex = ((Fts5Iter*)pIndexIter)->pIndex;
+ fts5IterClose(pIndexIter);
+ fts5IndexReturn(pIndex);
}
}
@@ -8140,7 +8189,7 @@ static int fts5QueryCksum(
rc = sqlite3Fts5IterNext(pIter);
}
}
- sqlite3Fts5IterClose(pIter);
+ fts5IterClose(pIter);
*pCksum = cksum;
return rc;
diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c
index 876420f24..9f504bb3a 100644
--- a/ext/fts5/fts5_main.c
+++ b/ext/fts5/fts5_main.c
@@ -1901,7 +1901,6 @@ static int fts5UpdateMethod(
Fts5Config *pConfig = pTab->p.pConfig;
int eType0; /* value_type() of apVal[0] */
int rc = SQLITE_OK; /* Return code */
- int bUpdateOrDelete = 0;
/* A transaction must be open when this is called. */
assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
@@ -1913,7 +1912,7 @@ static int fts5UpdateMethod(
);
assert( pTab->p.pConfig->pzErrmsg==0 );
if( pConfig->pgsz==0 ){
- rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie);
if( rc!=SQLITE_OK ) return rc;
}
@@ -1938,7 +1937,6 @@ static int fts5UpdateMethod(
rc = SQLITE_ERROR;
}else{
rc = fts5SpecialDelete(pTab, apVal);
- bUpdateOrDelete = 1;
}
}else{
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
@@ -1975,7 +1973,6 @@ static int fts5UpdateMethod(
}else{
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
- bUpdateOrDelete = 1;
}
}
@@ -2003,7 +2000,6 @@ static int fts5UpdateMethod(
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
- bUpdateOrDelete = 1;
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
@@ -2057,23 +2053,8 @@ static int fts5UpdateMethod(
rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
- bUpdateOrDelete = 1;
sqlite3Fts5StorageReleaseDeleteRow(pStorage);
}
-
- }
- }
-
- if( rc==SQLITE_OK
- && bUpdateOrDelete
- && pConfig->bSecureDelete
- && pConfig->iVersion==FTS5_CURRENT_VERSION
- ){
- rc = sqlite3Fts5StorageConfigValue(
- pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
- );
- if( rc==SQLITE_OK ){
- pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
}
}
@@ -2126,6 +2107,7 @@ static int fts5RollbackMethod(sqlite3_vtab *pVtab){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
+ pTab->p.pConfig->pgsz = 0;
return rc;
}
diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c
index 31f5fc5dc..2b43016be 100644
--- a/ext/fts5/fts5_storage.c
+++ b/ext/fts5/fts5_storage.c
@@ -205,6 +205,11 @@ static int fts5StorageGetStmt(
if( rc!=SQLITE_OK && pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
}
+ if( rc==SQLITE_ERROR && eStmt>FTS5_STMT_LOOKUP2 && eStmt<FTS5_STMT_SCAN ){
+ /* One of the internal tables - not the %_content table - is missing.
+ ** This counts as a corrupted table. */
+ rc = SQLITE_CORRUPT;
+ }
}
}
diff --git a/ext/fts5/test/fts5circref.test b/ext/fts5/test/fts5circref.test
index ea992195a..8732fa17d 100644
--- a/ext/fts5/test/fts5circref.test
+++ b/ext/fts5/test/fts5circref.test
@@ -72,7 +72,7 @@ foreach {tn schema sql} {
} {
db_restore_and_reopen
do_execsql_test 1.1.$tn.1 $schema
- do_catchsql_test 1.1.$tn.2 $sql {1 {SQL logic error}}
+ do_catchsql_test 1.1.$tn.2 $sql {1 {database disk image is malformed}}
db close
}
diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test
index 3e8b0377c..437c4842c 100644
--- a/ext/fts5/test/fts5corrupt3.test
+++ b/ext/fts5/test/fts5corrupt3.test
@@ -15678,6 +15678,239 @@ do_catchsql_test 81.2 {
UPDATE t1 SET b=zeroblob(299);
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_test 82.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 32768 pagesize 4096 filename c0.txt.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........
+| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................
+| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
+| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............
+| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
+| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
+| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
+| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
+| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
+| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
+| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
+| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
+| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
+| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
+| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
+| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
+| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
+| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
+| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
+| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
+| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
+| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
+| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
+| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i....
+| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
+| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
+| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
+| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
+| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
+| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
+| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
+| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
+| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
+| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
+| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
+| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
+| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
+| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
+| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
+| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
+| page 3 offset 8192
+| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
+| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
+| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
+| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
+| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4.
+| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
+| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
+| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary..
+| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp
+| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
+| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
+| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
+| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
+| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
+| 3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
+| 3488: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
+| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
+| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 0a 02 03 .........fts4...
+| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
+| 3552: 02 03 01 03 67 63 63 01 02 03 01 02 03 01 02 03 ....gcc.........
+| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........
+| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........
+| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
+| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
+| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
+| 3648: 73 79 73 35 16 02 03 01 02 02 03 01 03 01 06 6e sys5...........n
+| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
+| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
+| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 02 ...omit.........
+| 3744: 01 05 72 74 72 65 65 19 02 03 01 02 03 01 02 03 ..rtree.........
+| 3760: 04 02 69 6d 01 06 01 02 02 03 06 01 02 02 03 06 ..im............
+| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 03 57 34 56 ..threadsafe.W4V
+| 3840: 94 64 91 46 85 84 04 76 74 61 62 07 02 04 01 02 .d.F...vtab.....
+| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
+| 3872: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 10 02 ................
+| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 3936: 01 02 01 06 01 01 10 01 06 01 01 02 01 06 01 01 ................
+| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
+| 4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f .D...G..........
+| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
+| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
+| page 4 offset 12288
+| 0: 0a 00 00 00 01 0f fa 00 00 00 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
+| page 5 offset 16384
+| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
+| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
+| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
+| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5....
+| 64: 0c da 0c b9 0c 99 0c 78 0c 57 00 00 00 00 00 00 .......x.W......
+| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
+| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
+| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
+| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
+| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 31 46 45 3d ..%..THREADS1FE=
+| 3152: 30 58 52 64 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRdRIM.!..3..OM
+| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
+| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O
+| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI
+| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3..
+| 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS
+| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3..
+| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000
+| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3.
+| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000
+| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3
+| 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500
+| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....%
+| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB
+| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE.
+| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR
+| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E
+| 3440: 4e 41 42 4b 45 20 4d 45 4d 53 59 53 35 58 42 49 NABKE MEMSYS5XBI
+| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 3472: 42 60 2d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 B`-EMSYS5XNOCASE
+| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME
+| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....%
+| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB
+| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE.
+| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO
+| 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E
+| 3600: 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 4e 41 BLE GEOPOLYXBINA
+| 3616: 52 59 1a 11 05 00 39 0f 19 45 4e 41 42 4c 45 2e RY....9..ENABLE.
+| 3632: 41 40 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 40 A@GEOPOLYXNOCAS@
+| 3648: 4f 4c 59 58 55 19 10 05 00 29 0f 17 45 4e 41 42 OLYXU....)..ENAB
+| 3664: 4c 45 20 47 45 4f 52 54 52 49 4d 17 0f 05 00 23 LE GEORTRIM....#
+| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI
+| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
+| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE...
+| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
+| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
+| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY..
+| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
+| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
+| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
+| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY.
+| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3872: 54 41 54 20 56 54 24 15 48 4e 4f 43 41 53 45 1d TAT VT$.HNOCASE.
+| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM..
+| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
+| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
+| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG
+| 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM
+| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
+| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
+| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
+| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
+| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C
+| 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4.
+| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
+| page 6 offset 20480
+| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
+| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
+| 32: 1f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
+| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 0f 30 0f 28 0f 20 .X.P.H.@.8.0.(.
+| 64: 0f 18 0f 10 0f 08 0f 00 0e f8 0e f0 0e e8 00 00 ................
+| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
+| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
+| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
+| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
+| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
+| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
+| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
+| 3920: 06 15 f3 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
+| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
+| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
+| 3968: 06 10 03 00 12 02 01 01 06 0f 03 00 12 02 01 01 ................
+| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
+| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
+| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
+| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
+| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
+| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
+| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
+| page 7 offset 24576
+| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
+| page 8 offset 28672
+| 0: 0d 00 00 00 03 0f d6 00 0f f4 0f e9 0f d6 00 00 ................
+| 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 67 72 .........+integr
+| 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb
+| 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 00 00 00 00 uild....opti....
+| end c0.txt.db
+}]} {}
+
+do_execsql_test 82.2 {
+ UPDATE t1 SET b=quote(zeroblob(current_date)) WHERE t1 MATCH 't*';
+ PRAGMA writable_schema=ON;
+
+ UPDATE sqlite_schema SET sql='SELECT * FROM t1' WHERE rowid=6;
+ INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
+}
+
+do_catchsql_test 82.3 {
+ CREATE VIRTUAL TABLE IF NOT EXISTS t USING rtree(x,c);
+} {1 {Too few columns for an rtree table}}
+
+do_catchsql_test 82.4 {
+ BEGIN;
+ REPLACE INTO t1(rowid,b,a,rowid) VALUES(x'44023b9eb002d28b0ee90c',1,2,3);
+ SAVEPOINT b;
+} {1 {database disk image is malformed}}
+
+
sqlite3_fts5_may_be_corrupt 0
finish_test
diff --git a/ext/fts5/test/fts5corrupt5.test b/ext/fts5/test/fts5corrupt5.test
index 19f053841..6a70fc7e4 100644
--- a/ext/fts5/test/fts5corrupt5.test
+++ b/ext/fts5/test/fts5corrupt5.test
@@ -1451,6 +1451,473 @@ do_catchsql_test 9.2 {
DELETE FROM t1;
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_test 10.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 32768 pagesize 4096 filename crash-b06f016068bcea.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........
+| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................
+| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
+| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............
+| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
+| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
+| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
+| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
+| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
+| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
+| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
+| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
+| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
+| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
+| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
+| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
+| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
+| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
+| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
+| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
+| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
+| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
+| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
+| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i....
+| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
+| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
+| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
+| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
+| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
+| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
+| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
+| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
+| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
+| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
+| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
+| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
+| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
+| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
+| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
+| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
+| page 3 offset 8192
+| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
+| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
+| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
+| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
+| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4.
+| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
+| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
+| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary..
+| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp
+| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
+| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
+| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
+| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
+| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
+| 3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
+| 3488: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
+| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
+| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 0a 02 03 .........fts4...
+| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
+| 3552: 02 03 01 03 67 63 63 01 02 03 01 02 03 01 02 03 ....gcc.........
+| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........
+| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........
+| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
+| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
+| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
+| 3648: 73 79 73 35 16 02 03 01 02 02 03 01 03 01 06 6e sys5...........n
+| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
+| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
+| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 02 ...omit.........
+| 3744: 01 05 72 74 72 65 65 19 02 03 01 02 03 01 02 03 ..rtree.........
+| 3760: 04 02 69 6d 01 06 01 02 02 03 06 01 02 02 03 06 ..im............
+| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 03 57 34 56 ..threadsafe.W4V
+| 3840: 94 64 91 46 85 84 04 76 74 61 62 07 02 04 01 02 .d.F...vtab.....
+| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
+| 3872: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 10 02 ................
+| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 3936: 01 02 01 06 01 01 10 01 06 01 01 02 01 06 01 01 ................
+| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
+| 4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f .D...G..........
+| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
+| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
+| page 4 offset 12288
+| 0: 0a 00 00 00 01 0f fa 00 00 00 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
+| page 5 offset 16384
+| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
+| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
+| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
+| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5....
+| 64: 0c da 0c b9 0c 99 0c 00 00 00 00 00 00 00 00 00 ................
+| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
+| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
+| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
+| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
+| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 31 46 45 3d ..%..THREADS1FE=
+| 3152: 30 58 52 64 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRdRIM.!..3..OM
+| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
+| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O
+| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI
+| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3..
+| 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS
+| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3..
+| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000
+| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3.
+| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000
+| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3
+| 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500
+| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....%
+| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB
+| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE.
+| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR
+| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E
+| 3440: 4e 41 42 4b 45 20 4d 45 4d 53 59 53 35 58 42 49 NABKE MEMSYS5XBI
+| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 3472: 42 60 2d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 B`-EMSYS5XNOCASE
+| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 46 ....)..ENABLE MF
+| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....%
+| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB
+| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE.
+| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO
+| 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E
+| 3600: 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 4e 41 BLE GEOPOLYXBINA
+| 3616: 52 59 1a 11 05 00 39 0f 19 45 4e 41 42 4c 45 2e RY....9..ENABLE.
+| 3632: 41 40 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 40 A@GEOPOLYXNOCAS@
+| 3648: 4f 4c 59 58 55 09 10 05 00 29 0f 17 45 4e 41 42 OLYXU....)..ENAB
+| 3664: 4c 45 20 47 45 4f 52 54 52 49 4d 17 0f 05 00 23 LE GEORTRIM....#
+| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI
+| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
+| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE...
+| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
+| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
+| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY..
+| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
+| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
+| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
+| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY.
+| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3872: 54 41 54 20 56 54 24 15 48 4e 4f 43 41 53 45 1d TAT VT$.HNOCASE.
+| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM..
+| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
+| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
+| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG
+| 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM
+| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
+| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
+| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
+| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
+| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C
+| 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4.
+| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
+| page 6 offset 20480
+| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
+| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
+| 32: 1f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
+| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 0f 30 0f 28 0f 20 .X.P.H.@.8.0.(.
+| 64: 0f 18 0f 10 0f 08 0f 00 0e f8 0e f0 0e e8 00 00 ................
+| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
+| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
+| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
+| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
+| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
+| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
+| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
+| 3920: 06 15 f3 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
+| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
+| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
+| 3968: 06 10 03 00 12 02 01 01 06 0f 03 00 12 02 01 01 ................
+| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
+| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
+| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
+| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
+| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
+| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
+| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
+| page 7 offset 24576
+| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
+| page 8 offset 28672
+| 0: 0d 00 00 00 03 0f d6 00 0f f4 0f 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 67 72 .........+integr
+| 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb
+| 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 00 00 00 00 uild....opti....
+| end crash-b06f016068bcea.db
+.testctrl prng_seed 1 db
+.testctrl internal_functions
+.testctrl json_selfcheck on
+}]} {}
+
+do_execsql_test 10.1 {
+ UPDATE t1 SET b=quote(zeroblob(current_date)) WHERE t1 MATCH 't*';
+}
+
+do_catchsql_test 10.2 {
+ BEGIN;
+ INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
+ REPLACE INTO t1(b,a,rowid) VALUES(1,2,3);
+} {0 {}}
+
+do_catchsql_test 10.3 {
+ COMMIT
+} {1 {database disk image is malformed}}
+
+do_catchsql_test 10.4 {
+ REPLACE INTO t1(b,a,rowid) VALUES(1,2,3);
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_test 11.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 32768 pagesize 4096 filename crash-3d05232c78871b.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........
+| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................
+| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
+| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............
+| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
+| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
+| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
+| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
+| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
+| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
+| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
+| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
+| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
+| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
+| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
+| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
+| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
+| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
+| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
+| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
+| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
+| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
+| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
+| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i....
+| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
+| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
+| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
+| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
+| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
+| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
+| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
+| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
+| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
+| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
+| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
+| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
+| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
+| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
+| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
+| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
+| page 3 offset 8192
+| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
+| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
+| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
+| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
+| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4.
+| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
+| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
+| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary..
+| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp
+| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
+| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
+| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
+| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
+| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
+| 3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
+| 3488: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
+| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
+| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 0a 02 03 .........fts4...
+| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
+| 3552: 02 03 01 03 67 63 63 01 02 03 01 02 03 01 02 03 ....gcc.........
+| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........
+| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........
+| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
+| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
+| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
+| 3648: 73 79 73 35 16 02 03 01 02 02 03 01 03 01 06 6e sys5...........n
+| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
+| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
+| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 02 ...omit.........
+| 3744: 01 05 72 74 72 65 65 19 02 03 01 02 03 01 02 03 ..rtree.........
+| 3760: 04 02 69 6d 01 06 01 02 02 03 06 01 02 02 03 06 ..im............
+| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 03 57 34 56 ..threadsafe.W4V
+| 3840: 94 64 91 46 85 84 04 76 74 61 62 07 02 04 01 02 .d.F...vtab.....
+| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
+| 3872: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 10 02 ................
+| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 3936: 01 02 01 06 01 01 10 01 06 01 01 02 01 06 01 01 ................
+| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
+| 4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f .D...G..........
+| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
+| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
+| page 4 offset 12288
+| 0: 0a 00 00 00 01 0f fa 00 00 00 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
+| page 5 offset 16384
+| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
+| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
+| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
+| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5....
+| 64: 0c da 0c b9 0c 99 0c 00 00 00 00 00 00 00 00 00 ................
+| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
+| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
+| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
+| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
+| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 31 46 45 3d ..%..THREADS1FE=
+| 3152: 30 58 52 64 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRdRIM.!..3..OM
+| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
+| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O
+| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI
+| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3..
+| 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS
+| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3..
+| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000
+| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3.
+| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000
+| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3
+| 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500
+| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....%
+| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB
+| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE.
+| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR
+| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E
+| 3440: 4e 41 42 4b 45 20 4d 45 4d 53 59 53 35 58 42 49 NABKE MEMSYS5XBI
+| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 3472: 42 60 2d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 B`-EMSYS5XNOCASE
+| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 46 ....)..ENABLE MF
+| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....%
+| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB
+| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE.
+| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO
+| 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E
+| 3600: 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 4e 41 BLE GEOPOLYXBINA
+| 3616: 52 59 1a 11 05 00 39 0f 19 45 4e 41 42 4c 45 2e RY....9..ENABLE.
+| 3632: 41 40 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 40 A@GEOPOLYXNOCAS@
+| 3648: 4f 4c 59 58 55 09 10 05 00 29 0f 17 45 4e 41 42 OLYXU....)..ENAB
+| 3664: 4c 45 20 47 45 4f 52 54 52 49 4d 17 0f 05 00 23 LE GEORTRIM....#
+| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI
+| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
+| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE...
+| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
+| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
+| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY..
+| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
+| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
+| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
+| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY.
+| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3872: 54 41 54 20 56 54 24 15 48 4e 4f 43 41 53 45 1d TAT VT$.HNOCASE.
+| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM..
+| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
+| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
+| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG
+| 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM
+| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
+| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
+| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
+| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
+| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C
+| 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4.
+| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
+| page 6 offset 20480
+| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
+| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
+| 32: 1f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
+| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 0f 30 0f 28 0f 20 .X.P.H.@.8.0.(.
+| 64: 0f 18 0f 10 0f 08 0f 00 0e f8 0e f0 0e e8 00 00 ................
+| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
+| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
+| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
+| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
+| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
+| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
+| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
+| 3920: 06 15 f3 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
+| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
+| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
+| 3968: 06 10 03 00 12 02 01 01 06 0f 03 00 12 02 01 01 ................
+| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
+| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
+| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
+| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
+| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
+| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
+| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
+| page 7 offset 24576
+| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
+| page 8 offset 28672
+| 0: 0d 00 00 00 03 0f d6 00 0f f4 0f 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 67 72 .........+integr
+| 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb
+| 4080: 75 69 6c 64 0a 01 02 1d 6f 00 00 00 00 00 00 00 uild....o.......
+| end crash-3d05232c78871b.db
+}]} {}
+
+do_execsql_test 11.1 {
+ UPDATE t1 SET b=quote(zeroblob('2025-01-09')) WHERE t1 MATCH 't*';
+ INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
+}
+
+do_catchsql_test 11.2 {
+ BEGIN;
+ REPLACE INTO t1(rowid,b,a,rowid) VALUES(x'44023b9eb002d28b0ee90c',1,2,3);
+ PRAGMA writable_schema=RESET;
+ INSERT INTO t1(t1) SELECT x FROM t2;
+ ROLLBACK;
+} {1 {database disk image is malformed}}
+
+do_catchsql_test 11.3 {
+ REPLACE INTO t1(rowid,b,a,rowid) VALUES(x'44023b9eb002d28b0ee90c',1,2,3);
+} {1 {database disk image is malformed}}
+
+
sqlite3_fts5_may_be_corrupt 0
finish_test
diff --git a/ext/fts5/test/fts5faultI.test b/ext/fts5/test/fts5faultI.test
index 72f25caee..ab84d37de 100644
--- a/ext/fts5/test/fts5faultI.test
+++ b/ext/fts5/test/fts5faultI.test
@@ -290,5 +290,40 @@ do_faultsim_test 11 -faults oom* -prep {
faultsim_test_result {0 {}}
}
+#-------------------------------------------------------------------------
+reset_db
+
+ifcapable foreignkey {
+ do_execsql_test 12.0 {
+ CREATE VIRTUAL TABLE f1 USING fts5(content);
+ CREATE TABLE p1(a INTEGER PRIMARY KEY);
+ CREATE TABLE c1(b REFERENCES p1 DEFERRABLE INITIALLY DEFERRED);
+ }
+
+ faultsim_save_and_close
+
+ do_faultsim_test 11 -faults oom* -prep {
+ faultsim_restore_and_reopen
+ execsql {
+ PRAGMA foreign_keys = 1;
+ BEGIN;
+ INSERT INTO c1 VALUES(123);
+ SAVEPOINT xyz;
+ }
+ } -body {
+ execsql {
+ INSERT INTO f1 VALUES('a b c');
+ ROLLBACK TO xyz;
+ COMMIT;
+ }
+ } -test {
+ execsql { SELECT 123 }
+ faultsim_test_result \
+ {1 {FOREIGN KEY constraint failed}} \
+ {1 {out of memory}} \
+ {1 {constraint failed}}
+ }
+}
+
finish_test
diff --git a/ext/fts5/test/fts5misc.test b/ext/fts5/test/fts5misc.test
index c2e580c56..2aca1986a 100644
--- a/ext/fts5/test/fts5misc.test
+++ b/ext/fts5/test/fts5misc.test
@@ -591,7 +591,6 @@ do_execsql_test 21.2 {
PRAGMA integrity_check
} {ok}
-breakpoint
sqlite3_db_config db DEFENSIVE 1
do_execsql_test 21.3 {
CREATE TABLE xyz_notashadow(x, y);
@@ -665,5 +664,26 @@ do_execsql_test 25.0 {
SELECT fts5_test_poslist(t1) FROM t1('b') ORDER BY rank;
} {{}}
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 26.0 {
+ PRAGMA foreign_keys = ON;
+ CREATE TABLE t1(x INTEGER PRIMARY KEY);
+ CREATE TABLE t2(y INTEGER PRIMARY KEY,
+ z INTEGER REFERENCES t1(x) DEFERRABLE INITIALLY DEFERRED
+ );
+ CREATE VIRTUAL TABLE t3 USING fts5(a, b, content='', tokendata=1);
+}
+
+do_execsql_test 26.1 {
+ BEGIN;
+ INSERT INTO t2 VALUES(1,111);
+ INSERT INTO t3 VALUES(3,3);
+ PRAGMA defer_foreign_keys=ON;
+ DELETE FROM t2 WHERE y+1;
+ COMMIT;
+}
+
finish_test
diff --git a/ext/fts5/test/fts5savepoint.test b/ext/fts5/test/fts5savepoint.test
index fdb0a25ba..bf6605228 100644
--- a/ext/fts5/test/fts5savepoint.test
+++ b/ext/fts5/test/fts5savepoint.test
@@ -48,7 +48,7 @@ do_catchsql_test 2.0 {
SAVEPOINT two;
INSERT INTO ft1 VALUES('b');
COMMIT;
-} {1 {SQL logic error}}
+} {1 {database disk image is malformed}}
reset_db
ifcapable fts3 {
diff --git a/ext/fts5/test/fts5version.test b/ext/fts5/test/fts5version.test
index a92c0dc9f..58dd9fe14 100644
--- a/ext/fts5/test/fts5version.test
+++ b/ext/fts5/test/fts5version.test
@@ -112,7 +112,7 @@ do_execsql_test 2.1 {
do_execsql_test 2.2 {
SELECT v FROM xyz_config WHERE k='version';
-} {5}
+} {4}
do_execsql_test 2.3 {
ROLLBACK TO one;
diff --git a/ext/misc/base64.c b/ext/misc/base64.c
index bc7a976ab..17b3bbfc7 100644
--- a/ext/misc/base64.c
+++ b/ext/misc/base64.c
@@ -175,15 +175,15 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
case ND:
/* Treat dark non-digits as pad, but they terminate decode too. */
ncIn = 0;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case WS:
/* Treat whitespace as pad and terminate this group.*/
nti = nac;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case PC:
bdp = 0;
--nbo;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
default: /* bdp is the digit value. */
qv = qv<<6 | bdp;
break;
@@ -192,10 +192,13 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
switch( nbo ){
case 3:
pOut[2] = (qv) & 0xff;
+ deliberate_fall_through; /* FALLTHRU */
case 2:
pOut[1] = (qv>>8) & 0xff;
+ deliberate_fall_through; /* FALLTHRU */
case 1:
pOut[0] = (qv>>16) & 0xff;
+ break;
}
pOut += nbo;
}
diff --git a/ext/misc/base85.c b/ext/misc/base85.c
index e7ef0a04c..eaf1732c4 100644
--- a/ext/misc/base85.c
+++ b/ext/misc/base85.c
@@ -232,12 +232,16 @@ static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){
switch( nbo ){
case 4:
*pOut++ = (qv >> 24)&0xff;
+ /* FALLTHRU */
case 3:
*pOut++ = (qv >> 16)&0xff;
+ /* FALLTHRU */
case 2:
*pOut++ = (qv >> 8)&0xff;
+ /* FALLTHRU */
case 1:
*pOut++ = qv&0xff;
+ /* FALLTHRU */
case 0:
break;
}
diff --git a/ext/misc/closure.c b/ext/misc/closure.c
index 79a5a21d1..267ae1c42 100644
--- a/ext/misc/closure.c
+++ b/ext/misc/closure.c
@@ -589,11 +589,16 @@ static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
}
/*
+** Wrapper around sqlite3_free
+*/
+static void closureMemFree(closure_avl *p){ sqlite3_free(p); }
+
+/*
** Free up all the memory allocated by a cursor. Set it rLimit to 0
** to indicate that it is at EOF.
*/
static void closureClearCursor(closure_cursor *pCur){
- closureAvlDestroy(pCur->pClosure, (void(*)(closure_avl*))sqlite3_free);
+ closureAvlDestroy(pCur->pClosure, closureMemFree);
sqlite3_free(pCur->zTableName);
sqlite3_free(pCur->zIdColumn);
sqlite3_free(pCur->zParentColumn);
diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c
index 483ef0187..80ac3b3e7 100644
--- a/ext/misc/fileio.c
+++ b/ext/misc/fileio.c
@@ -437,7 +437,7 @@ static int writeFile(
GetSystemTime(&currentTime);
SystemTimeToFileTime(&currentTime, &lastAccess);
- intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
+ intervals = (mtime*10000000) + 116444736000000000;
lastWrite.dwLowDateTime = (DWORD)intervals;
lastWrite.dwHighDateTime = intervals >> 32;
zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
diff --git a/ext/misc/regexp.c b/ext/misc/regexp.c
index a50008ca3..71c7ea4c2 100644
--- a/ext/misc/regexp.c
+++ b/ext/misc/regexp.c
@@ -656,7 +656,8 @@ static const char *re_subcompile_string(ReCompiled *p){
** regular expression. Applications should invoke this routine once
** for every call to re_compile() to avoid memory leaks.
*/
-static void re_free(ReCompiled *pRe){
+static void re_free(void *p){
+ ReCompiled *pRe = (ReCompiled*)p;
if( pRe ){
sqlite3_free(pRe->aOp);
sqlite3_free(pRe->aArg);
diff --git a/ext/misc/sqlite3_stdio.c b/ext/misc/sqlite3_stdio.c
index 97c3551da..c9bceb194 100644
--- a/ext/misc/sqlite3_stdio.c
+++ b/ext/misc/sqlite3_stdio.c
@@ -46,6 +46,11 @@
** 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.
+**
+** The SQLITE_USE_W32_FOR_CONSOLE_IO macro is also available. If
+** defined, it forces the use of Win32 APIs for all console I/O, both
+** input and output. This is necessary for some non-Microsoft run-times
+** that implement stdio differently from Microsoft/Visual-Studio.
*/
#if defined(SQLITE_U8TEXT_ONLY)
# define UseWtextForOutput(fd) 1
@@ -148,10 +153,10 @@ char *sqlite3_fgets(char *buf, int sz, FILE *in){
*/
wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
if( b1==0 ) return 0;
-#ifndef SQLITE_USE_STDIO_FOR_CONSOLE
+#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
DWORD nRead = 0;
if( IsConsole(in)
- && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz, &nRead, 0)
+ && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz-1, &nRead, 0)
){
b1[nRead] = 0;
}else
@@ -226,7 +231,7 @@ int sqlite3_fputs(const char *z, FILE *out){
sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
b1[sz] = 0;
-#ifndef SQLITE_STDIO_FOR_CONSOLE
+#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
DWORD nWr = 0;
if( IsConsole(out)
&& WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
@@ -236,8 +241,9 @@ int sqlite3_fputs(const char *z, FILE *out){
}else
#endif
{
- /* For non-console I/O, or if SQLITE_USE_STDIO_FOR_CONSOLE is defined
- ** then write using the standard library. */
+ /* As long as SQLITE_USE_W32_FOR_CONSOLE_IO is not defined, or for
+ ** non-console I/O even if that macro is defined, write using the
+ ** standard library. */
_setmode(_fileno(out), _O_U8TEXT);
if( UseBinaryWText(out) ){
piecemealOutput(b1, sz, out);
diff --git a/ext/misc/vfstrace.c b/ext/misc/vfstrace.c
index e8b51cdd0..c274558d1 100644
--- a/ext/misc/vfstrace.c
+++ b/ext/misc/vfstrace.c
@@ -188,6 +188,7 @@ struct vfstrace_file {
#define VTR_SLEEP 0x02000000
#define VTR_CURTIME 0x04000000
#define VTR_LASTERR 0x08000000
+#define VTR_FETCH 0x10000000 /* Also coverse xUnfetch */
/*
** Method declarations for vfstrace_file.
@@ -617,6 +618,7 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
{ "currenttime", VTR_CURTIME },
{ "currenttimeint64", VTR_CURTIME },
{ "getlasterror", VTR_LASTERR },
+ { "fetch", VTR_FETCH },
};
int onOff = 1;
while( zArg[0] ){
@@ -844,7 +846,28 @@ static int vfstraceShmUnmap(sqlite3_file *pFile, int delFlag){
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
return rc;
}
-
+static int vfstraceFetch(sqlite3_file *pFile, i64 iOff, int nAmt, void **pptr){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_FETCH);
+ vfstrace_printf(pInfo, "%s.xFetch(%s,iOff=%lld,nAmt=%d,p=%p)",
+ pInfo->zVfsName, p->zFName, iOff, nAmt, *pptr);
+ rc = p->pReal->pMethods->xFetch(p->pReal, iOff, nAmt, pptr);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+static int vfstraceUnfetch(sqlite3_file *pFile, i64 iOff, void *ptr){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_FETCH);
+ vfstrace_printf(pInfo, "%s.xUnfetch(%s,iOff=%lld,p=%p)",
+ pInfo->zVfsName, p->zFName, iOff, ptr);
+ rc = p->pReal->pMethods->xUnfetch(p->pReal, iOff, ptr);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
/*
@@ -891,6 +914,10 @@ static int vfstraceOpen(
pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
}
+ if( pNew->iVersion>=3 ){
+ pNew->xFetch = pSub->xFetch ? vfstraceFetch : 0;
+ pNew->xUnfetch = pSub->xUnfetch ? vfstraceUnfetch : 0;
+ }
pFile->pMethods = pNew;
}
vfstrace_print_errcode(pInfo, " -> %s", rc);
@@ -1006,7 +1033,7 @@ static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
sqlite3_vfs *pRoot = pInfo->pRootVfs;
vfstraceOnOff(pInfo, VTR_DLCLOSE);
- vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo->zVfsName);
+ vfstrace_printf(pInfo, "%s.xDlClose()\n", pInfo->zVfsName);
pRoot->xDlClose(pRoot, pHandle);
}
diff --git a/ext/session/session1.test b/ext/session/session1.test
index bcd7b03d5..6da905179 100644
--- a/ext/session/session1.test
+++ b/ext/session/session1.test
@@ -204,7 +204,9 @@ proc do_conflict_test {tn args} {
foreach t $O(-tables) { S attach $t }
execsql $O(-sql)
set ::xConflict [list]
- sqlite3changeset_apply db2 [S changeset] xConflict
+ catch {
+ sqlite3changeset_apply db2 [S changeset] xConflict
+ }
set conflicts [list]
foreach c $O(-conflicts) {
diff --git a/ext/session/session9.test b/ext/session/session9.test
index ebb88ffad..5c406c344 100644
--- a/ext/session/session9.test
+++ b/ext/session/session9.test
@@ -80,8 +80,10 @@ foreach {tn delrow trans conflictargs conflictret} {
8 3 1 {FOREIGN_KEY 1} ABORT
} {
- set A(OMIT) {0 {}}
- set A(ABORT) {1 SQLITE_CONSTRAINT}
+ set A(OMIT,0) {0 {}}
+ set A(OMIT,1) {0 {}}
+ set A(ABORT,0) {1 SQLITE_CONSTRAINT}
+ set A(ABORT,1) {1 SQLITE_CONSTRAINT}
do_test 1.2.$tn.1 {
populate_db
execsql { DELETE FROM p1 WHERE a=($delrow+0) }
@@ -89,20 +91,24 @@ foreach {tn delrow trans conflictargs conflictret} {
set ::xConflict [list]
list [catch {sqlite3changeset_apply db $::cc xConflict} msg] $msg
- } $A($conflictret)
+ } $A($conflictret,$trans)
do_test 1.2.$tn.2 { set ::xConflict } $conflictargs
- set A(OMIT) {1 1}
- set A(ABORT) {0 0}
+ set A(OMIT,0) {1 1}
+ set A(OMIT,1) {1 1}
+ set A(ABORT,0) {0 0}
+ set A(ABORT,1) {0 0}
+
do_test 1.2.$tn.3 {
execsql { SELECT count(*) FROM c1 UNION ALL SELECT count(*) FROM c2 }
- } $A($conflictret)
+ } $A($conflictret,$trans)
do_test 1.2.$tn.4 { expr ![sqlite3_get_autocommit db] } $trans
do_test 1.2.$tn.5 {
- if { $trans } { execsql COMMIT }
+ if { $trans && $conflictret=="ABORT" } { execsql COMMIT }
} {}
+ catchsql ROLLBACK
}
#--------------------------------------------------------------------
diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl
index 3ff84f1c5..7c1273bb1 100644
--- a/ext/session/session_common.tcl
+++ b/ext/session/session_common.tcl
@@ -201,12 +201,16 @@ proc compare_db {db1 db2} {
foreach tbl $lot1 {
set col1 [list]
set col2 [list]
+ set quoted [list]
$db1 eval "PRAGMA table_info = $tbl" { lappend col1 $name }
- $db2 eval "PRAGMA table_info = $tbl" { lappend col2 $name }
+ $db2 eval "PRAGMA table_info = $tbl" {
+ lappend col2 $name
+ lappend quoted "\"[string map {\" \"\"} $name]\""
+ }
if {$col1 != $col2} { error "table $tbl schema mismatch" }
- set sql "SELECT * FROM $tbl ORDER BY [join $col1 ,]"
+ set sql "SELECT * FROM $tbl ORDER BY [join $quoted ,]"
set data1 [$db1 eval $sql]
set data2 [$db2 eval $sql]
if {$data1 != $data2} {
diff --git a/ext/session/session_gen.test b/ext/session/session_gen.test
new file mode 100644
index 000000000..e9de4beab
--- /dev/null
+++ b/ext/session/session_gen.test
@@ -0,0 +1,191 @@
+# 2025 Jan 28
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+
+if {![info exists testdir]} {
+ set testdir [file join [file dirname [info script]] .. .. test]
+}
+source [file join [file dirname [info script]] session_common.tcl]
+source $testdir/tester.tcl
+ifcapable !session {finish_test; return}
+
+set testprefix session_gen
+
+
+foreach {otn sct} {
+ 1 VIRTUAL
+ 2 STORED
+} {
+eval [string map [list %TYPE% $sct] {
+ reset_db
+ set testprefix $testprefix-$otn
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+
+ CREATE TABLE t2(a INTEGER PRIMARY KEY, b AS (c+1) %TYPE%, c);
+
+ CREATE TABLE t3(
+ a,
+ b AS (a+10) %TYPE%,
+ c,
+ d AS (c+1) %TYPE%,
+ e,
+ PRIMARY KEY(c, e)
+ ) WITHOUT ROWID;
+
+ CREATE TABLE t4(a AS (c*100) %TYPE%, b INTEGER PRIMARY KEY, c);
+
+ CREATE TABLE t5(x, y);
+}
+
+foreach {tn sql changeset} {
+
+ 0.1 {
+ INSERT INTO t5 VALUES('abc', 'def');
+ } {
+ {INSERT t5 0 X.. {} {i 1 t abc t def}}
+ }
+ 0.2 {
+ UPDATE t5 SET y='xyz' WHERE rowid=1;
+ } {
+ {UPDATE t5 0 X.. {i 1 {} {} t def} {{} {} {} {} t xyz}}
+ }
+ 0.3 {
+ DELETE FROM t5;
+ } {
+ {DELETE t5 0 X.. {i 1 t abc t xyz} {}}
+ }
+
+ 1.1 {
+ INSERT INTO t2 VALUES(1, 2);
+ INSERT INTO t2 VALUES(2, 123);
+ } {
+ {INSERT t2 0 X. {} {i 1 i 2}}
+ {INSERT t2 0 X. {} {i 2 i 123}}
+ }
+ 1.2 {
+ UPDATE t2 SET c=456 WHERE a=1
+ } {
+ {UPDATE t2 0 X. {i 1 i 2} {{} {} i 456}}
+ }
+
+ 1.3 {
+ DELETE FROM t2 WHERE a=2
+ } {
+ {DELETE t2 0 X. {i 2 i 123} {}}
+ }
+
+ 1.4 {
+ UPDATE t2 SET a=15
+ } {
+ {INSERT t2 0 X. {} {i 15 i 456}}
+ {DELETE t2 0 X. {i 1 i 456} {}}
+ }
+
+ 2.1 {
+ INSERT INTO t3 VALUES(5, 6, 7);
+ INSERT INTO t3 VALUES(8, 9, 10);
+ } {
+ {INSERT t3 0 .XX {} {i 8 i 9 i 10}}
+ {INSERT t3 0 .XX {} {i 5 i 6 i 7}}
+ }
+
+ 2.2 {
+ UPDATE t3 SET a = 505 WHERE (c, e) = (6, 7);
+ } {
+ {UPDATE t3 0 .XX {i 5 i 6 i 7} {i 505 {} {} {} {}}}
+ }
+
+ 2.3 {
+ DELETE FROM t3 WHERE (c, e) = (9, 10);
+ } {
+ {DELETE t3 0 .XX {i 8 i 9 i 10} {}}
+ }
+
+ 2.4 {
+ UPDATE t3 SET c=1000
+ } {
+ {DELETE t3 0 .XX {i 505 i 6 i 7} {}}
+ {INSERT t3 0 .XX {} {i 505 i 1000 i 7}}
+ }
+
+ 3.1 {
+ INSERT INTO t4 VALUES(100, 100);
+ } {
+ {INSERT t4 0 X. {} {i 100 i 100}}
+ }
+
+} {
+ do_test 1.$tn.1 {
+ sqlite3session S db main
+ S object_config rowid 1
+ S attach *
+ execsql $sql
+ } {}
+
+ do_changeset_test 1.$tn.2 S $changeset
+
+ S delete
+}
+#-------------------------------------------------------------------------
+reset_db
+
+forcedelete test.db2
+sqlite3 db2 test.db2
+
+do_common_sql {
+ CREATE TABLE t0(x INTEGER PRIMARY KEY, y);
+ INSERT INTO t0 VALUES(1, 'one');
+ INSERT INTO t0 VALUES(2, 'two');
+
+ CREATE TABLE t1(a AS (c*10) %TYPE%, b INTEGER PRIMARY KEY, c);
+ INSERT INTO t1 VALUES(1, 5);
+ INSERT INTO t1 VALUES(2, 10);
+ INSERT INTO t1 VALUES(3, 5);
+
+ CREATE TABLE t2(
+ a, b, c AS (a*b) %TYPE%,
+ 'k 1', 'k 2', PRIMARY KEY('k 1', 'k 2')
+ ) WITHOUT ROWID;
+ INSERT INTO t2 VALUES('a', 'b', 1, 11);
+ INSERT INTO t2 VALUES('A', 'B', 2, 22);
+ INSERT INTO t2 VALUES('Aa', 'Bb', 3, 33);
+}
+
+foreach {tn sql} {
+ 1.1 { INSERT INTO t0 VALUES(4, 15) }
+ 1.2 { INSERT INTO t1 VALUES(4, 15) }
+ 1.3 { INSERT INTO t2 VALUES(1, 2, 3, 4) }
+
+ 2.1 { UPDATE t1 SET c=100 WHERE b=2 }
+ 2.2 { UPDATE t2 SET a=11 }
+
+ 3.1 { DELETE FROM t2 WHERE (t2.'k 1') = 2 }
+ 3.2 { DELETE FROM t1 }
+} {
+ do_test 2.$tn.1 {
+ # execsql { PRAGMA vdbe_listing = 1 } db2
+ do_then_apply_sql $sql
+ } {}
+ do_test 2.$tn.2 {
+ compare_db db db2
+ } {}
+}
+db2 close
+
+}]}
+
+
+
+
+finish_test
diff --git a/ext/session/sessionnoact.test b/ext/session/sessionnoact.test
index aa1cde474..54e9a6215 100644
--- a/ext/session/sessionnoact.test
+++ b/ext/session/sessionnoact.test
@@ -59,7 +59,7 @@ do_execsql_test 1.2 {
set ::nConflict 0
proc conflict {args} {
incr ::nConflict
- return "OMIT"
+ return "ABORT"
}
sqlite3changeset_apply_v2 db $C conflict
@@ -82,7 +82,6 @@ do_execsql_test 1.5 {
UPDATE p1 SET c=12345 WHERE a = 45;
}
-breakpoint
sqlite3changeset_apply_v2 -noaction db $C conflict
do_execsql_test 1.6 {
SELECT * FROM c1
@@ -108,4 +107,126 @@ do_execsql_test 1.8 {
PRAGMA foreign_key_check
}
+#-------------------------------------------------------------------------
+# Check that a changeset that causes an FK violation may not be applied,
+# even if SQLITE_CHANGESETAPPLY_FKNOACTION is specified.
+#
+# UPDATE: Unless the conflict-handler returns OMIT. In that case it can
+# be committed. See test cases 3.* in this file.
+#
+reset_db
+do_execsql_test 2.0 {
+ CREATE TABLE p1(a INTEGER PRIMARY KEY, b, c UNIQUE);
+ INSERT INTO p1 VALUES(1, 1, 'one');
+ INSERT INTO p1 VALUES(2, 2, 'two');
+
+ CREATE TABLE c1(x REFERENCES p1(c) ON DELETE CASCADE);
+ INSERT INTO c1 VALUES('two');
+}
+
+db_save
+
+set C [changeset_from_sql {
+ DELETE FROM p1 WHERE a=2;
+}]
+
+db_restore_and_reopen
+
+do_test 2.1 {
+ sqlite3changeset_apply_v2 -noaction db $C conflict
+} {}
+do_execsql_test 2.2 {
+ SELECT * FROM p1
+} {1 1 one}
+
+db_restore_and_reopen
+db eval { PRAGMA foreign_keys = 1 }
+
+do_test 2.3 {
+ list [catch { sqlite3changeset_apply_v2 -noaction db $C conflict } msg] $msg
+} {1 SQLITE_CONSTRAINT}
+do_execsql_test 2.4 {
+ SELECT * FROM p1;
+} {1 1 one 2 2 two}
+do_execsql_test 2.5 {
+ SELECT * FROM c1;
+} {two}
+
+db_restore_and_reopen
+db eval { PRAGMA foreign_keys = 1 }
+
+do_test 2.6 {
+ list [catch {
+ sqlite3changeset_apply_v2 -ignorenoop -noaction db $C conflict
+ } msg] $msg
+} {1 SQLITE_CONSTRAINT}
+do_execsql_test 2.7 {
+ SELECT * FROM p1;
+} {1 1 one 2 2 two}
+do_execsql_test 2.8 {
+ SELECT * FROM c1;
+} {two}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 3.0 {
+ CREATE TABLE p1(a INTEGER PRIMARY KEY, b, c UNIQUE);
+ INSERT INTO p1 VALUES(1, 1, 'one');
+ INSERT INTO p1 VALUES(2, 2, 'two');
+
+ CREATE TABLE c1(x REFERENCES p1(c) ON DELETE CASCADE);
+ INSERT INTO c1 VALUES('two');
+}
+
+set ::nConflict 0
+proc conflict {args} {
+ incr ::nConflict
+ return "OMIT"
+}
+
+db_save
+
+set C [changeset_from_sql {
+ DELETE FROM p1 WHERE a=2;
+}]
+
+db_restore_and_reopen
+
+do_test 3.1 {
+ sqlite3changeset_apply_v2 -noaction db $C conflict
+} {}
+do_execsql_test 3.2 {
+ SELECT * FROM p1
+} {1 1 one}
+
+db_restore_and_reopen
+db eval { PRAGMA foreign_keys = 1 }
+
+do_test 3.3 {
+ list [catch { sqlite3changeset_apply_v2 -noaction db $C conflict } msg] $msg
+} {0 {}}
+do_execsql_test 3.4 {
+ SELECT * FROM p1;
+} {1 1 one}
+do_execsql_test 3.5 {
+ SELECT * FROM c1;
+} {two}
+
+db_restore_and_reopen
+db eval { PRAGMA foreign_keys = 1 }
+
+do_test 3.6 {
+ list [catch {
+ sqlite3changeset_apply_v2 -ignorenoop -noaction db $C conflict
+ } msg] $msg
+} {0 {}}
+do_execsql_test 3.7 {
+ SELECT * FROM p1;
+} {1 1 one}
+do_execsql_test 3.8 {
+ SELECT * FROM c1;
+} {two}
+
finish_test
+
diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c
index f2eb942e6..1cf1bf466 100644
--- a/ext/session/sqlite3session.c
+++ b/ext/session/sqlite3session.c
@@ -139,11 +139,13 @@ struct sqlite3_changeset_iter {
struct SessionTable {
SessionTable *pNext;
char *zName; /* Local name of table */
- int nCol; /* Number of columns in table zName */
+ int nCol; /* Number of non-hidden columns */
+ int nTotalCol; /* Number of columns including hidden */
int bStat1; /* True if this is sqlite_stat1 */
int bRowid; /* True if this table uses rowid for PK */
const char **azCol; /* Column names */
const char **azDflt; /* Default value expressions */
+ int *aiIdx; /* Index to pass to xNew/xOld */
u8 *abPK; /* Array of primary key flags */
int nEntry; /* Total number of entries in hash table */
int nChange; /* Size of apChange[] array */
@@ -546,22 +548,22 @@ static int sessionPreupdateHash(
unsigned int h = 0; /* Hash value to return */
int i; /* Used to iterate through columns */
+ assert( pTab->nTotalCol==pSession->hook.xCount(pSession->hook.pCtx) );
if( pTab->bRowid ){
- assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) );
h = sessionHashAppendI64(h, iRowid);
}else{
assert( *pbNullPK==0 );
- assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
for(i=0; i<pTab->nCol; i++){
if( pTab->abPK[i] ){
int rc;
int eType;
sqlite3_value *pVal;
+ int iIdx = pTab->aiIdx[i];
if( bNew ){
- rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
+ rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal);
}else{
- rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal);
}
if( rc!=SQLITE_OK ) return rc;
@@ -898,6 +900,7 @@ static int sessionPreupdateEqual(
sqlite3_value *pVal; /* Value returned by preupdate_new/old */
int rc; /* Error code from preupdate_new/old */
int eType = *a++; /* Type of value from change record */
+ int iIdx = pTab->aiIdx[iCol];
/* The following calls to preupdate_new() and preupdate_old() can not
** fail. This is because they cache their return values, and by the
@@ -906,10 +909,10 @@ static int sessionPreupdateEqual(
** this (that the method has already been called). */
if( op==SQLITE_INSERT ){
/* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
- rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
+ rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal);
}else{
/* assert( db->pPreUpdate->pUnpacked ); */
- rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal);
}
assert( rc==SQLITE_OK );
(void)rc; /* Suppress warning about unused variable */
@@ -1034,9 +1037,11 @@ static int sessionTableInfo(
const char *zDb, /* Name of attached database (e.g. "main") */
const char *zThis, /* Table name */
int *pnCol, /* OUT: number of columns */
+ int *pnTotalCol, /* OUT: number of hidden columns */
const char **pzTab, /* OUT: Copy of zThis */
const char ***pazCol, /* OUT: Array of column names for table */
const char ***pazDflt, /* OUT: Array of default value expressions */
+ int **paiIdx, /* OUT: Array of xNew/xOld indexes */
u8 **pabPK, /* OUT: Array of booleans - true for PK col */
int *pbRowid /* OUT: True if only PK is a rowid */
){
@@ -1051,6 +1056,7 @@ static int sessionTableInfo(
char **azCol = 0;
char **azDflt = 0;
u8 *abPK = 0;
+ int *aiIdx = 0;
int bRowid = 0; /* Set to true to use rowid as PK */
assert( pazCol && pabPK );
@@ -1058,6 +1064,8 @@ static int sessionTableInfo(
*pazCol = 0;
*pabPK = 0;
*pnCol = 0;
+ if( pnTotalCol ) *pnTotalCol = 0;
+ if( paiIdx ) *paiIdx = 0;
if( pzTab ) *pzTab = 0;
if( pazDflt ) *pazDflt = 0;
@@ -1067,9 +1075,9 @@ static int sessionTableInfo(
if( rc==SQLITE_OK ){
/* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
zPragma = sqlite3_mprintf(
- "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL "
- "SELECT 1, 'idx', '', 0, '', 2 UNION ALL "
- "SELECT 2, 'stat', '', 0, '', 0"
+ "SELECT 0, 'tbl', '', 0, '', 1, 0 UNION ALL "
+ "SELECT 1, 'idx', '', 0, '', 2, 0 UNION ALL "
+ "SELECT 2, 'stat', '', 0, '', 0, 0"
);
}else if( rc==SQLITE_ERROR ){
zPragma = sqlite3_mprintf("");
@@ -1077,7 +1085,7 @@ static int sessionTableInfo(
return rc;
}
}else{
- zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
+ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_xinfo('%q')", zDb, zThis);
}
if( !zPragma ){
return SQLITE_NOMEM;
@@ -1094,7 +1102,9 @@ static int sessionTableInfo(
while( SQLITE_ROW==sqlite3_step(pStmt) ){
nByte += sqlite3_column_bytes(pStmt, 1); /* name */
nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */
- nDbCol++;
+ if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */
+ nDbCol++;
+ }
if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */
}
if( nDbCol==0 ) bRowid = 0;
@@ -1103,7 +1113,7 @@ static int sessionTableInfo(
rc = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ){
- nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1);
+ nByte += nDbCol * (sizeof(const char *)*2 +sizeof(int)+sizeof(u8) + 1 + 1);
pAlloc = sessionMalloc64(pSession, nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
@@ -1114,8 +1124,8 @@ static int sessionTableInfo(
if( rc==SQLITE_OK ){
azCol = (char **)pAlloc;
azDflt = (char**)&azCol[nDbCol];
- pAlloc = (u8 *)&azDflt[nDbCol];
- abPK = (u8 *)pAlloc;
+ aiIdx = (int*)&azDflt[nDbCol];
+ abPK = (u8 *)&aiIdx[nDbCol];
pAlloc = &abPK[nDbCol];
if( pzTab ){
memcpy(pAlloc, zThis, nThis+1);
@@ -1130,27 +1140,32 @@ static int sessionTableInfo(
azCol[i] = (char*)pAlloc;
pAlloc += nName+1;
abPK[i] = 1;
+ aiIdx[i] = -1;
i++;
}
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- int nName = sqlite3_column_bytes(pStmt, 1);
- int nDflt = sqlite3_column_bytes(pStmt, 4);
- const unsigned char *zName = sqlite3_column_text(pStmt, 1);
- const unsigned char *zDflt = sqlite3_column_text(pStmt, 4);
-
- if( zName==0 ) break;
- memcpy(pAlloc, zName, nName+1);
- azCol[i] = (char *)pAlloc;
- pAlloc += nName+1;
- if( zDflt ){
- memcpy(pAlloc, zDflt, nDflt+1);
- azDflt[i] = (char *)pAlloc;
- pAlloc += nDflt+1;
- }else{
- azDflt[i] = 0;
+ if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */
+ int nName = sqlite3_column_bytes(pStmt, 1);
+ int nDflt = sqlite3_column_bytes(pStmt, 4);
+ const unsigned char *zName = sqlite3_column_text(pStmt, 1);
+ const unsigned char *zDflt = sqlite3_column_text(pStmt, 4);
+
+ if( zName==0 ) break;
+ memcpy(pAlloc, zName, nName+1);
+ azCol[i] = (char *)pAlloc;
+ pAlloc += nName+1;
+ if( zDflt ){
+ memcpy(pAlloc, zDflt, nDflt+1);
+ azDflt[i] = (char *)pAlloc;
+ pAlloc += nDflt+1;
+ }else{
+ azDflt[i] = 0;
+ }
+ abPK[i] = sqlite3_column_int(pStmt, 5);
+ aiIdx[i] = sqlite3_column_int(pStmt, 0);
+ i++;
}
- abPK[i] = sqlite3_column_int(pStmt, 5);
- i++;
+ if( pnTotalCol ) (*pnTotalCol)++;
}
rc = sqlite3_reset(pStmt);
}
@@ -1163,6 +1178,7 @@ static int sessionTableInfo(
if( pazDflt ) *pazDflt = (const char**)azDflt;
*pabPK = abPK;
*pnCol = nDbCol;
+ if( paiIdx ) *paiIdx = aiIdx;
}else{
sessionFree(pSession, azCol);
}
@@ -1194,7 +1210,8 @@ static int sessionInitTable(
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
rc = sessionTableInfo(pSession, db, zDb,
- pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK,
+ pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol,
+ &pTab->azDflt, &pTab->aiIdx, &abPK,
((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0)
);
if( rc==SQLITE_OK ){
@@ -1229,15 +1246,17 @@ static int sessionInitTable(
*/
static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){
int nCol = 0;
+ int nTotalCol = 0;
const char **azCol = 0;
const char **azDflt = 0;
+ int *aiIdx = 0;
u8 *abPK = 0;
int bRowid = 0;
assert( pSession->rc==SQLITE_OK );
pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
- pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK,
+ pTab->zName, &nCol, &nTotalCol, 0, &azCol, &azDflt, &aiIdx, &abPK,
(pSession->bImplicitPK ? &bRowid : 0)
);
if( pSession->rc==SQLITE_OK ){
@@ -1260,8 +1279,10 @@ static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){
const char **a = pTab->azCol;
pTab->azCol = azCol;
pTab->nCol = nCol;
+ pTab->nTotalCol = nTotalCol;
pTab->azDflt = azDflt;
pTab->abPK = abPK;
+ pTab->aiIdx = aiIdx;
azCol = a;
}
if( pSession->bEnableSize ){
@@ -1579,7 +1600,7 @@ static int sessionUpdateMaxSize(
int ii;
for(ii=0; ii<pTab->nCol; ii++){
sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, pTab->aiIdx[ii], &p);
sessionSerializeValue(0, p, &nNew);
}
}
@@ -1599,8 +1620,9 @@ static int sessionUpdateMaxSize(
int bChanged = 1;
int nOld = 0;
int eType;
+ int iIdx = pTab->aiIdx[ii];
sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p);
if( p==0 ){
return SQLITE_NOMEM;
}
@@ -1697,11 +1719,11 @@ static void sessionPreupdateOneChange(
/* Check the number of columns in this xPreUpdate call matches the
** number of columns in the table. */
nExpect = pSession->hook.xCount(pSession->hook.pCtx);
- if( (pTab->nCol-pTab->bRowid)<nExpect ){
+ if( pTab->nTotalCol<nExpect ){
if( sessionReinitTable(pSession, pTab) ) return;
if( sessionUpdateChanges(pSession, pTab) ) return;
}
- if( (pTab->nCol-pTab->bRowid)!=nExpect ){
+ if( pTab->nTotalCol!=nExpect ){
pSession->rc = SQLITE_SCHEMA;
return;
}
@@ -1758,14 +1780,15 @@ static void sessionPreupdateOneChange(
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
- for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
+ for(i=pTab->bRowid; i<pTab->nCol; i++){
+ int iIdx = pTab->aiIdx[i];
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
/* This may fail if the column has a non-NULL default and was added
** using ALTER TABLE ADD COLUMN after this record was created. */
- rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p);
}else if( pTab->abPK[i] ){
- TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
+ TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx,iIdx,&p);
assert( trc==SQLITE_OK );
}
@@ -1800,12 +1823,13 @@ static void sessionPreupdateOneChange(
sessionPutI64(&pC->aRecord[1], iRowid);
nByte = 9;
}
- for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
+ for(i=pTab->bRowid; i<pTab->nCol; i++){
sqlite3_value *p = 0;
+ int iIdx = pTab->aiIdx[i];
if( op!=SQLITE_INSERT ){
- pSession->hook.xOld(pSession->hook.pCtx, i, &p);
+ pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p);
}else if( pTab->abPK[i] ){
- pSession->hook.xNew(pSession->hook.pCtx, i, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p);
}
sessionSerializeValue(&pC->aRecord[nByte], p, &nByte);
}
@@ -2207,7 +2231,8 @@ int sqlite3session_diff(
int bRowid = 0;
u8 *abPK;
const char **azCol = 0;
- rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK,
+ rc = sessionTableInfo(0, db, zFrom, zTbl,
+ &nCol, 0, 0, &azCol, 0, 0, &abPK,
pSession->bImplicitPK ? &bRowid : 0
);
if( rc==SQLITE_OK ){
@@ -2531,9 +2556,11 @@ static void sessionAppendIdent(
char *zOut = (char *)&p->aBuf[p->nBuf];
const char *zIn = zStr;
*zOut++ = '"';
- while( *zIn ){
- if( *zIn=='"' ) *zOut++ = '"';
- *zOut++ = *(zIn++);
+ if( zIn!=0 ){
+ while( *zIn ){
+ if( *zIn=='"' ) *zOut++ = '"';
+ *zOut++ = *(zIn++);
+ }
}
*zOut++ = '"';
p->nBuf = (int)((u8 *)zOut - p->aBuf);
@@ -2784,10 +2811,10 @@ static int sessionSelectStmt(
int rc = SQLITE_OK;
char *zSql = 0;
const char *zSep = "";
- const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*";
int nSql = -1;
int i;
+ SessionBuffer cols = {0, 0, 0};
SessionBuffer nooptest = {0, 0, 0};
SessionBuffer pkfield = {0, 0, 0};
SessionBuffer pkvar = {0, 0, 0};
@@ -2800,9 +2827,16 @@ static int sessionSelectStmt(
sessionAppendStr(&pkvar,
"?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc
);
- zCols = "tbl, ?2, stat";
+ sessionAppendStr(&cols, "tbl, ?2, stat", &rc);
}else{
+ #if 0
+ if( bRowid ){
+ sessionAppendStr(&cols, SESSIONS_ROWID, &rc);
+ }
+ #endif
for(i=0; i<nCol; i++){
+ if( cols.nBuf ) sessionAppendStr(&cols, ", ", &rc);
+ sessionAppendIdent(&cols, azCol[i], &rc);
if( abPK[i] ){
sessionAppendStr(&pkfield, zSep, &rc);
sessionAppendStr(&pkvar, zSep, &rc);
@@ -2820,7 +2854,7 @@ static int sessionSelectStmt(
if( rc==SQLITE_OK ){
zSql = sqlite3_mprintf(
"SELECT %s%s FROM %Q.%Q WHERE (%s) IS (%s)",
- zCols, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
+ (char*)cols.aBuf, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
zDb, zTab, (char*)pkfield.aBuf, (char*)pkvar.aBuf
);
if( zSql==0 ) rc = SQLITE_NOMEM;
@@ -2863,6 +2897,7 @@ static int sessionSelectStmt(
sqlite3_free(nooptest.aBuf);
sqlite3_free(pkfield.aBuf);
sqlite3_free(pkvar.aBuf);
+ sqlite3_free(cols.aBuf);
return rc;
}
@@ -5203,7 +5238,8 @@ static int sessionChangesetApply(
sqlite3changeset_pk(pIter, &abPK, 0);
rc = sessionTableInfo(0, db, "main", zNew,
- &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid
+ &sApply.nCol, 0, &zTab, &sApply.azCol, 0, 0,
+ &sApply.abPK, &sApply.bRowid
);
if( rc!=SQLITE_OK ) break;
for(i=0; i<sApply.nCol; i++){
@@ -5283,12 +5319,17 @@ static int sessionChangesetApply(
}
}
}
- sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
+
+ {
+ int rc2 = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
if( rc==SQLITE_OK ){
rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
- }else{
+ }
+ if( rc!=SQLITE_OK ){
sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
}
diff --git a/ext/session/test_session.c b/ext/session/test_session.c
index 29aeadf53..41d6aaa10 100644
--- a/ext/session/test_session.c
+++ b/ext/session/test_session.c
@@ -719,7 +719,6 @@ static int replace_handler(
const char *zTab; /* Name of table conflict is on */
int nCol; /* Number of columns in table zTab */
int i;
- int x = 0;
sqlite3changeset_op(pIter, &zTab, &nCol, &op, 0);
@@ -728,7 +727,6 @@ static int replace_handler(
sqlite3_value *pVal;
sqlite3changeset_old(pIter, i, &pVal);
sqlite3_value_text16(pVal);
- x++;
}
}
@@ -737,7 +735,6 @@ static int replace_handler(
sqlite3_value *pVal;
sqlite3changeset_new(pIter, i, &pVal);
sqlite3_value_text16(pVal);
- x++;
}
}
diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile
index 19ad75990..c9852e389 100644
--- a/ext/wasm/GNUmakefile
+++ b/ext/wasm/GNUmakefile
@@ -32,19 +32,16 @@
#
# - Emscripten SDK: https://emscripten.org/docs/getting_started/downloads.html
# - The bash shell
-# - GNU make, GNU sed, GNU awk, GNU grep (all in the $PATH)
+# - GNU make, GNU sed, GNU awk, GNU grep (all in the $PATH and without
+# a "g" prefix like they have on some non-GNU systems)
# - wasm-strip for release builds: https://github.com/WebAssembly/wabt
# - InfoZip for 'dist' zip file
########################################################################
default: all
#default: quick
-SHELL := $(firstword $(shell which bash) $(wildcard /usr/local/bin/bash /usr/bin/bash /bin/bash))
-ifeq (,$(SHELL))
- $(error Cannot find the bash shell)
-endif
MAKEFILE := $(lastword $(MAKEFILE_LIST))
CLEAN_FILES :=
-DISTCLEAN_FILES :=
+DISTCLEAN_FILES := config.make
MAKING_CLEAN := $(if $(filter %clean,$(MAKECMDGOALS)),1,0)
.PHONY: clean distclean
clean:
@@ -52,6 +49,67 @@ clean:
distclean: clean
-rm -f $(DISTCLEAN_FILES)
+
+########################################################################
+# Special-case builds for which we require certain pre-conditions
+# which, if not met, may cause warnings or fatal errors in the build.
+# This also affects the default optimization level flags. Note that
+# the fiddle targets are in this list because they are used for
+# generating sqlite.org/fiddle.
+OPTIMIZED_TARGETS := dist snapshot fiddle fiddle.debug
+
+ifeq (1,$(MAKING_CLEAN))
+ bin.wasm-strip := echo "not stripping"
+ bin.wasm-opt := irrelevant
+ bin.emcc := irrelevant
+ bin.bash := irrelevant
+ emcc.version := unknown
+else
+ # Include config.make and perform some bootstrapping...
+ ifeq (,$(wildcard ./config.make))
+ $(error Missing config.make (gets generated by the configure script if the EMSDK is found))
+ endif
+ include ./config.make
+ ifeq (,$(bin.bash))
+ $(error Configure script did not find the bash shell)
+ endif
+ ifeq (,$(bin.emcc))
+ $(error Configure script did not find emcc)
+ endif
+ emcc.version := $(shell $(bin.emcc) --version | sed -n 1p | sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;')
+ $(info using emcc version [$(emcc.version)])
+ ifeq (,$(bin.wasm-strip))
+ ####################################################################
+ # We need wasm-strip for release builds (see below for why) but
+ # not strictly for non-release builds.
+ $(info WARNING: *******************************************************************)
+ $(info WARNING: Builds using -Oz will minify WASM-exported names, breaking)
+ $(info WARNING: _All The Things_. The workaround for that is to build)
+ $(info WARNING: with -g3 (which explodes the file size) and then strip the debug)
+ $(info WARNING: info after compilation, using wasm-strip, to shrink the wasm file.)
+ $(info WARNING: wasm-strip was not found in the PATH so we cannot strip those.)
+ $(info WARNING: If this build uses any optimization level higher than -O1 then)
+ $(info WARNING: the ***resulting JS code WILL NOT BE USABLE***.)
+ $(info WARNING: wasm-strip is part of the wabt package:)
+ $(info WARNING: https://github.com/WebAssembly/wabt)
+ $(info WARNING: on Ubuntu-like systems it can be installed with:)
+ $(info WARNING: sudo apt install wabt)
+ $(info WARNING: *******************************************************************)
+ ifneq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
+ $(error Cannot make release-quality binary because wasm-strip is not available.)
+ endif
+ bin.wasm-strip := echo "not wasm-stripping"
+ endif
+ ifeq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
+ $(info ==============================================================)
+ $(info == Development build. Make one of (dist, snapshot) for a)
+ $(info == smaller release build.)
+ $(info ==============================================================)
+ endif
+endif
+# ^^^ end of are-we-MAKING_CLEAN
+maybe-wasm-strip := $(bin.wasm-strip)
+
########################################################################
# JS_BUILD_NAMES exists for documentation purposes only. It enumerates
# the core build styles:
@@ -107,7 +165,7 @@ dir.wasmfs := $(dir.dout)
MKDIR.bld := $(dir.tmp)
$(MKDIR.bld):
- -mkdir -p $@ $(dir.dout)
+ @mkdir -p $@ $(dir.dout)
CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~ $(dir.fiddle)/*~ \
$(dir.fiddle-debug)/* $(dir.dout)/* $(dir.tmp)/*
@@ -133,13 +191,15 @@ sqlite3.canonical.c := $(dir.top)/sqlite3.c
sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c))
sqlite3.h := $(dir.top)/sqlite3.h
-ifneq (1,$(MAKING_CLEAN))
-ifeq (,$(shell grep sqlite3_activate_see $(sqlite3.c)))
+ifeq (1,$(MAKING_CLEAN))
SQLITE_C_IS_SEE := 0
else
- SQLITE_C_IS_SEE := 1
- $(info This is an SEE build)
-endif
+ ifeq (,$(shell grep sqlite3_activate_see $(sqlite3.c)))
+ SQLITE_C_IS_SEE := 0
+ else
+ SQLITE_C_IS_SEE := 1
+ $(info This is an SEE build)
+ endif
endif
########################################################################@
@@ -152,65 +212,6 @@ $(sqlite3.h):
$(sqlite3.c): $(sqlite3.h)
########################################################################
-# Special-case builds for which we require certain pre-conditions
-# which, if not met, may cause warnings or fatal errors in the build.
-# This also affects the default optimization level flags. Note that
-# the fiddle targets are in this list because they are used for
-# generating sqlite.org/fiddle.
-OPTIMIZED_TARGETS := dist snapshot fiddle fiddle.debug
-
-ifneq (1,$(MAKING_CLEAN))
- ifeq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
- $(info ==============================================================)
- $(info == Development build. Make one of (dist, snapshot) for a)
- $(info == smaller release build.)
- $(info ==============================================================)
- endif
-endif
-
-########################################################################
-# Find emcc (Emscripten compiler)...
-ifeq (1,$(MAKING_CLEAN))
- emcc.bin := echo
- emcc.version := unknown
-else
- emcc.bin := $(dir.tool)/emcc.sh
- ifeq (,$(wildcard $(emcc.bin)))
- $(error Configure script did not find emcc.)
- endif
- emcc.version := $(shell $(emcc.bin) --version | sed -n 1p | sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;')
- $(info using emcc version [$(emcc.version)])
-endif
-#########################################################################
-# Find wasm-strip, which we need for release builds (see below for
-# why) but not strictly for non-release builds.
-ifeq (1,$(MAKING_CLEAN))
- wasm-strip-bin := irrelevant
-else
- wasm-strip.bin ?= $(shell which wasm-strip 2>/dev/null)
- ifeq (,$(wasm-strip.bin))
- $(info WARNING: *******************************************************************)
- $(info WARNING: Builds using -O2/-O3/-Os/-Oz will minify WASM-exported names,)
- $(info WARNING: breaking _All The Things_. The workaround for that is to build)
- $(info WARNING: with -g3 (which explodes the file size) and then strip the debug)
- $(info WARNING: info after compilation, using wasm-strip, to shrink the wasm file.)
- $(info WARNING: wasm-strip was not found in the PATH so we cannot strip those.)
- $(info WARNING: If this build uses any optimization level higher than -O1 then)
- $(info WARNING: the ***resulting JS code WILL NOT BE USABLE***.)
- $(info WARNING: wasm-strip is part of the wabt package:)
- $(info WARNING: https://github.com/WebAssembly/wabt)
- $(info WARNING: on Ubuntu-like systems it can be installed with:)
- $(info WARNING: sudo apt install wabt)
- $(info WARNING: *******************************************************************)
- ifneq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
- $(error Cannot make release-quality binary because wasm-strip is not available.)
- endif
- wasm-strip.bin := echo "not wasm-stripping"
- endif
-endif
-maybe-wasm-strip := $(wasm-strip.bin)
-
-########################################################################
# barebones=1 disables all "extraneous" stuff from sqlite3-wasm.c, the
# goal being to create a WASM file with only the core APIs.
ifeq (1,$(barebones))
@@ -376,20 +377,7 @@ $(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
DISTCLEAN_FILES += $(bin.stripccomments)
########################################################################
-# bin.mkwb is used for generating some of the makefile code for the
-# various wasm builds. It used to be generated in this makefile via a
-# difficult-to-read/maintain block of $(eval)'d code. Attempts were
-# made to generate it from tcl and bash (shell) but having to escape
-# the $ references in those languages made it just as illegible as the
-# native makefile code. Somewhat surprisingly, moving that code generation
-# to C makes it slightly less illegible than the previous 3 options.
-bin.mkwb := ./mkwasmbuilds
-$(bin.mkwb): $(bin.mkwb).c $(MAKEFILE)
- $(CC) -o $@ $<
-DISTCLEAN_FILES += $(bin.mkwb)
-
-########################################################################
-# C-PP.FILTER: a $(call)able to transform $(1) to $(2) via:
+# SQLITE.CALL.C-PP.FILTER: a $(call)able to transform $(1) to $(2) via:
#
# ./c-pp -f $(1) -o $(2) $(3)
#
@@ -419,7 +407,7 @@ DISTCLEAN_FILES += $(bin.mkwb)
# JS/WASM build. They are solely for use with $(bin.c-pp) itself.
#
# -D... flags which should be included in all invocations should be
-# appended to $(C-PP.FILTER.global).
+# appended to $(SQLITE.CALL.C-PP.FILTER.global).
bin.c-pp := ./c-pp
$(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
$(CC) -O0 -o $@ c-pp.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top) \
@@ -427,20 +415,21 @@ $(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
-DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_WAL -DSQLITE_THREADSAFE=0 \
-DSQLITE_TEMP_STORE=3
DISTCLEAN_FILES += $(bin.c-pp)
-C-PP.FILTER.global ?=
+SQLITE.CALL.C-PP.FILTER.global ?=
ifeq (1,$(SQLITE_C_IS_SEE))
- C-PP.FILTER.global += -Denable-see
+ SQLITE.CALL.C-PP.FILTER.global += -Denable-see
endif
-define C-PP.FILTER
+define SQLITE.CALL.C-PP.FILTER
# Create $2 from $1 using $(bin.c-pp)
# $1 = Input file: c-pp -f $(1).js
# $2 = Output file: c-pp -o $(2).js
# $3 = optional c-pp -D... flags
-$(2): $(1) $$(MAKEFILE) $$(bin.c-pp)
- $$(bin.c-pp) -f $(1) -o $$@ $(3) $(C-PP.FILTER.global)
+$(2): $(1) $$(MAKEFILE_LIST) $$(bin.c-pp)
+ @mkdir -p $$(dir $$@)
+ $$(bin.c-pp) -f $(1) -o $$@ $(3) $(SQLITE.CALL.C-PP.FILTER.global)
#CLEAN_FILES += $(2)
endef
-# /end C-PP.FILTER
+# /end SQLITE.CALL.C-PP.FILTER
########################################################################
# cflags.common = C compiler flags for all builds
@@ -618,7 +607,6 @@ emcc.cflags += -I. -I$(dir.top)
########################################################################
# emcc flags specific to building .js/.wasm files...
emcc.jsflags := -fPIC
-emcc.jsflags += --minify 0
emcc.jsflags += --no-entry
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
emcc.jsflags += -sMODULARIZE
@@ -631,6 +619,12 @@ emcc.exportedRuntimeMethods := \
emcc.jsflags += $(emcc.exportedRuntimeMethods)
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
emcc.jsflags += -sIMPORTED_MEMORY
+ifeq (,$(filter -O0,$(emcc_opt)))
+emcc.assert ?= 0
+else
+emcc.assert ?= 2
+endif
+emcc.jsflags += -sASSERTIONS=$(emcc.assert)
emcc.jsflags += -sSTRICT_JS=0
# STRICT_JS disabled due to:
# https://github.com/emscripten-core/emscripten/issues/18610
@@ -826,7 +820,7 @@ sqlite3-wasmfs.cfiles := $(sqlite3-wasm.cfiles)
########################################################################
########################################################################
-# SQLITE3.xJS.ESM-EXPORT-DEFAULT is used by mkwasmbuilds.c and the
+# SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT is used by mkwasmbuilds.c and the
# wasmfs build. $1 is 1 if the build mode needs this workaround
# (modes: esm, bundler-friendly, node) and 0 if not (vanilla). $2 must
# be 0 for all builds except sqlite3-wasmfs.mjs, in which case it must
@@ -847,9 +841,9 @@ sqlite3-wasmfs.cfiles := $(sqlite3-wasm.cfiles)
#
# Maintenance reminder: Mac sed works differently than GNU sed, so we
# use awk instead of sed for this.
-define SQLITE3.xJS.ESM-EXPORT-DEFAULT
+define SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT
if [ x1 = x$(1) ]; then \
- echo "Fragile workaround for emscripten/issues/18237. See SQLITE3.xJS.ESM-EXPORT-DEFAULT."; \
+ echo "Fragile workaround for emscripten/issues/18237. See SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT."; \
{\
awk '/^export default/ && !f{f=1; next} 1' $@ > $@.tmp && mv $@.tmp $@; \
} || exit $$?; \
@@ -873,14 +867,6 @@ sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs
sqlite3-api-wasmfs.mjs := $(dir.tmp)/sqlite3-api-wasmfs.mjs
sqlite3-wasmfs.mjs := $(dir.wasmfs)/sqlite3-wasmfs.mjs
EXPORTED_FUNCTIONS.fiddle := $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
-ifneq (1,$(MAKING_CLEAN))
-.wasmbuilds.make: $(bin.mkwb)
- @rm -f $@
- $(bin.mkwb) > $@
- @chmod -w $@
--include .wasmbuilds.make
-endif
-DISTCLEAN_FILES += .wasmbuilds.make
# The various -D... values used by *.c-pp.js include:
#
@@ -930,22 +916,47 @@ sqlite3-worker1-promiser.js := $(dir.dout)/sqlite3-worker1-promiser.js
sqlite3-worker1-promiser.mjs := $(dir.dout)/sqlite3-worker1-promiser.mjs
sqlite3-worker1-bundler-friendly.mjs := $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs
sqlite3-worker1-promiser-bundler-friendly.js := $(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js
-$(eval $(call C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1.js)))
-$(eval $(call C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1-bundler-friendly.mjs),\
+
+ifneq (1,$(MAKING_CLEAN))
+# This block MUST come between the above definitions of
+# sqlite3-...js/mjs and the $(eval) calls below this block which use
+# SQLITE.CALL.C-PP.FILTER.
+########################################################################
+# bin.mkwb is used for generating some of the makefile code for the
+# various wasm builds. It used to be generated in this makefile via a
+# difficult-to-read/maintain block of $(eval)'d code. Attempts were
+# made to generate it from tcl and bash (shell) but having to escape
+# the $ references in those languages made it just as illegible as the
+# native makefile code. Somewhat surprisingly, moving that code generation
+# to C makes it slightly less illegible than the previous 3 options.
+bin.mkwb := ./mkwasmbuilds
+$(bin.mkwb): $(bin.mkwb).c $(MAKEFILE)
+ $(CC) -o $@ $<
+DISTCLEAN_FILES += $(bin.mkwb)
+.wasmbuilds.make: $(bin.mkwb)
+ @rm -f $@
+ $(bin.mkwb) > $@
+ @chmod -w $@
+-include .wasmbuilds.make
+endif
+DISTCLEAN_FILES += .wasmbuilds.make
+
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1.js)))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1-bundler-friendly.mjs),\
$(c-pp.D.sqlite3-bundler-friendly)))
-$(eval $(call C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.js)))
-$(eval $(call C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),\
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.js)))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),\
$(sqlite3-worker1-promiser-bundler-friendly.js),\
$(c-pp.D.sqlite3-bundler-friendly)))
-$(eval $(call C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.mjs),\
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.mjs),\
-Dtarget=es6-module -Dtarget=es6-bundler-friendly))
$(sqlite3-bundler-friendly.mjs): $(sqlite3-worker1-bundler-friendly.mjs) \
$(sqlite3-worker1-promiser-bundler-friendly.js)
-$(eval $(call C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.js))
-$(eval $(call C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.mjs,\
+$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.js))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.mjs,\
-Dtarget=es6-module))
-$(eval $(call C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser.html))
-$(eval $(call C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser-esm.html,\
+$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser.html))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser-esm.html,\
-Dtarget=es6-module))
all: $(sqlite3-worker1.js) \
$(sqlite3-worker1-promiser.js) $(sqlite3-worker1-promiser.mjs)
@@ -1042,7 +1053,7 @@ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \
$(pre-post-speedtest1-vanilla.deps) \
$(EXPORTED_FUNCTIONS.speedtest1)
@echo "Building $@ ..."
- $(emcc.bin) \
+ $(bin.emcc) \
$(emcc.speedtest1) \
$(emcc.speedtest1.common) \
$(emcc.flags.speedtest1-vanilla) $(pre-post-speedtest1-vanilla.flags) \
@@ -1052,6 +1063,7 @@ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \
$(speedtest1.exit-runtime0) \
-o $@ $(speedtest1.cfiles) -lm
$(maybe-wasm-strip) $(speedtest1.wasm)
+ sed -i -e '/^var _sqlite3.*createExportWrapper/d' $@
chmod -x $(speedtest1.wasm)
ls -la $@ $(speedtest1.wasm)
@@ -1077,10 +1089,10 @@ all: speedtest1
# tester1.mjs: cases 3 and 4
#
# To create those, we filter tester1.c-pp.js with $(bin.c-pp)...
-$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.js))
-$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.sqlite3-esm)))
-$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html))
-$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.sqlite3-esm)))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.js,tester1.js))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.sqlite3-esm)))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.html,tester1.html))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.sqlite3-esm)))
tester1: tester1.js tester1.mjs tester1.html tester1-esm.html
# Note that we do not include $(sqlite3-bundler-friendly.mjs) in this
# because bundlers are client-specific.
diff --git a/ext/wasm/README-dist.txt b/ext/wasm/README-dist.txt
index 6656a2072..4a527fc5e 100644
--- a/ext/wasm/README-dist.txt
+++ b/ext/wasm/README-dist.txt
@@ -31,16 +31,20 @@ build:
use of and is not demonstrated here.
Browsers will not serve WASM files from file:// URLs, so the test and
-demonstration apps require a web server and that server must include
-the following headers in its response when serving the files:
+demonstration apps require a web server and that server must, for the
+OPFS[^1]-related features, include the following headers in its response
+when serving the files:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
-The core library will function without those headers but certain
-features, most notably OPFS storage, will not be available.
+Most functionality will work without those headers but the OPFS[^1]
+storage capability will not be available without them.
One simple way to get the demo apps up and running on Unix-style
systems is to install althttpd (https://sqlite.org/althttpd) and run:
althttpd --enable-sab --page index.html
+
+
+[^1]: https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system
diff --git a/ext/wasm/README.md b/ext/wasm/README.md
index 0c328310d..c41e54bd2 100644
--- a/ext/wasm/README.md
+++ b/ext/wasm/README.md
@@ -29,8 +29,16 @@ $ ./emsdk install latest
$ ./emsdk activate latest
```
-The following needs to be run for each shell instance which needs the
-`emcc` compiler:
+(Sidebar: Emscripten updates can and do _change things_, i.e. _break
+things_, so it's considered _required practice_ to test thoroughly
+after upgrading it! Our build process makes no guarantees about which
+Emscripten version(s) will or won't work, but it's important that
+production builds are built using a compatible version. During active
+development, the EMSDK is frequently updated, the goal being to keep
+`sqlite3.wasm` working with "the latest" EMSDK.)
+
+The SQLite configure script will search for the EMSDK. One way
+to ensure that it finds it is:
```
# Activate PATH and other environment variables in the current terminal:
@@ -38,15 +46,27 @@ $ source ./emsdk_env.sh
$ which emcc
/path/to/emsdk/upstream/emscripten/emcc
+
+$ ./configure ...
+```
+
+Optionally, add that `source` part to your login shell's resource file
+(`~/.bashrc` or equivalent).
+
+Another way is to pass the EMSDK dir to configure:
+
+```
+$ ./configure --with-emsdk=/path/to/emsdk
```
-Optionally, add that to your login shell's resource file (`~/.bashrc`
-or equivalent).
+The build tree uses a small wrapper for invoking the `emcc` (the
+Emscripten compiler): `tool/emcc.sh` is generated from
+`tool/emcc.sh.in` using the EMSDK path found by the configure process.
-That `env` script needs to be sourced for building this application
-from the top of the sqlite3 build tree:
+With that in place, the most common build approaches are:
```
+# From the top of the tree:
$ make fiddle
```
@@ -57,7 +77,7 @@ $ cd ext/wasm
$ make
```
-That will generate the a number of files required for a handful of
+Those will generate the a number of files required for a handful of
test and demo applications which can be accessed via
`index.html`. WASM content cannot, due to XMLHttpRequest security
limitations, be loaded if the containing HTML file is opened directly
@@ -68,16 +88,21 @@ needs to be served via an HTTP server. For example, using
```
$ cd ext/wasm
$ althttpd --enable-sab --max-age 1 --page index.html
+# Or, more simply, from the ext/wasm dir:
+$ make httpd
```
-That will open the system's browser and run the index page, from which
-all of the test and demo applications can be accessed.
+That will open the system's browser and visit the index page, from
+which (almost) all of the test and demo applications can be accessed.
+(`ext/wasm/SQLTester` is not listed in that page because it's only of
+real utility when it's used in conjunction with the project's
+proprietary test suite, which most users don't have access to.)
Note that when serving this app via [althttpd][], it must be a version
from 2022-09-26 or newer so that it recognizes the `--enable-sab`
flag, which causes althttpd to emit two HTTP response headers which
are required to enable JavaScript's `SharedArrayBuffer` and `Atomics`
-APIs. Those APIs are required in order to enable the OPFS-related
+APIs. Those APIs are required in order to enable the [OPFS][]-related
features in the apps which use them.
# Testing on a remote machine that is accessed via SSH
@@ -104,3 +129,4 @@ be tunneled using SSH.
[emscripten]: https://emscripten.org
[althttpd]: https://sqlite.org/althttpd
[SharedArrayBuffer]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer
+[OPFS]: https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system
diff --git a/ext/wasm/api/README.md b/ext/wasm/api/README.md
index ebd4aaacb..ce7e58ebe 100644
--- a/ext/wasm/api/README.md
+++ b/ext/wasm/api/README.md
@@ -85,17 +85,18 @@ browser client:
Installs the `sqlite3.vtab` namespace, which contain helpers for use
by downstream code which creates `sqlite3_module` implementations.
- **`sqlite3-vfs-opfs.c-pp.js`**\
- is an sqlite3 VFS implementation which supports the Origin-Private
- FileSystem (OPFS) as a storage layer to provide persistent storage
- for database files in a browser. It requires...
+ is an sqlite3 VFS implementation which supports the [Origin-Private
+ FileSystem (OPFS)][OPFS] as a storage layer to provide persistent
+ storage for database files in a browser. It requires...
- **`sqlite3-opfs-async-proxy.js`**\
- is the asynchronous backend part of the OPFS proxy. It speaks
- directly to the (async) OPFS API and channels those results back
- to its synchronous counterpart. This file, because it must be
- started in its own Worker, is not part of the amalgamation.
+ is the asynchronous backend part of the [OPFS][] proxy. It
+ speaks directly to the (async) OPFS API and channels those
+ results back to its synchronous counterpart. This file, because
+ it must be started in its own Worker, is not part of the
+ amalgamation.
- **`sqlite3-vfs-opfs-sahpool.c-pp.js`**\
- is another sqlite3 VFS supporting the OPFS, but uses a completely
- different approach that the above-listed one.
+ is another sqlite3 VFS supporting the [OPFS][], but uses a
+ completely different approach that the above-listed one.
- **`sqlite3-api-cleanup.js`**\
The previous files do not immediately extend the library. Instead
they add callback functions to be called during its
@@ -152,7 +153,7 @@ into the build-generated `sqlite3.js` along with `sqlite3-api.js`.
flag. This file overwrites the Emscripten-installed
`sqlite3InitModule()` function with one which, after the module is
loaded, also initializes the asynchronous parts of the sqlite3
- module. For example, the OPFS VFS support.
+ module. For example, the [OPFS][] VFS support.
<a id='c-pp'></a>
Preprocessing of Source Files
@@ -164,3 +165,6 @@ builds. The preprocessor application itself is in
[`c-pp.c`](/file/ext/wasm/c-pp.c) and the complete technical details
of such preprocessing are maintained in
[`GNUMakefile`](/file/ext/wasm/GNUmakefile).
+
+
+[OPFS]: https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system
diff --git a/ext/wasm/api/extern-post-js.c-pp.js b/ext/wasm/api/extern-post-js.c-pp.js
index 63e55051c..3598c0d6f 100644
--- a/ext/wasm/api/extern-post-js.c-pp.js
+++ b/ext/wasm/api/extern-post-js.c-pp.js
@@ -12,6 +12,7 @@
const toExportForESM =
//#endif
(function(){
+ //console.warn("this is extern-post-js");
/**
In order to hide the sqlite3InitModule()'s resulting
Emscripten module from downstream clients (and simplify our
@@ -62,6 +63,16 @@ const toExportForESM =
globalThis.sqlite3InitModule = function ff(...args){
//console.warn("Using replaced sqlite3InitModule()",globalThis.location);
return originalInit(...args).then((EmscriptenModule)=>{
+ //console.warn("originalInit() then() arg =",EmscriptenModule);
+ //console.warn("initModuleState =",initModuleState);
+ EmscriptenModule.runSQLite3PostLoadInit(EmscriptenModule);
+ const s = EmscriptenModule.sqlite3;
+ s.scriptInfo = initModuleState;
+ //console.warn("sqlite3.scriptInfo =",s.scriptInfo);
+ if(ff.__isUnderTest) s.__isUnderTest = true;
+ const f = s.asyncPostInit;
+ delete s.asyncPostInit;
+ const rv = f();
//#if wasmfs
if('undefined'!==typeof WorkerGlobalScope &&
EmscriptenModule['ENVIRONMENT_IS_PTHREAD']){
@@ -74,14 +85,7 @@ const toExportForESM =
return EmscriptenModule;
}
//#endif
- //console.warn("sqlite3InitModule() returning sqlite3 object.");
- const s = EmscriptenModule.sqlite3;
- s.scriptInfo = initModuleState;
- //console.warn("sqlite3.scriptInfo =",s.scriptInfo);
- if(ff.__isUnderTest) s.__isUnderTest = true;
- const f = s.asyncPostInit;
- delete s.asyncPostInit;
- return f();
+ return rv;
}).catch((e)=>{
console.error("Exception loading sqlite3 module:",e);
throw e;
diff --git a/ext/wasm/api/post-js-footer.js b/ext/wasm/api/post-js-footer.js
index 58882cbd9..7af12cbe3 100644
--- a/ext/wasm/api/post-js-footer.js
+++ b/ext/wasm/api/post-js-footer.js
@@ -1,4 +1,6 @@
/* The current function scope was opened via post-js-header.js, which
gets prepended to this at build-time. This file closes that
scope. */
-})/*postRun.push(...)*/;
+//console.warn("This is the end of the Module.runSQLite3PostLoadInit handler.");
+}/*Module.runSQLite3PostLoadInit()*/;
+//console.warn("This is the end of the setup of the (pending) Module.runSQLite3PostLoadInit");
diff --git a/ext/wasm/api/post-js-header.js b/ext/wasm/api/post-js-header.js
index 7fd82a7d6..77e3cd227 100644
--- a/ext/wasm/api/post-js-header.js
+++ b/ext/wasm/api/post-js-header.js
@@ -7,22 +7,27 @@
installs will be run after the WASM module is loaded, at which
point the sqlite3 JS API bits will get set up.
*/
-if(!Module.postRun) Module.postRun = [];
-Module.postRun.push(function(Module/*the Emscripten-style module object*/){
+Module.runSQLite3PostLoadInit = function(EmscriptenModule/*the Emscripten-style module object*/){
+ /** ^^^ Don't use Module.postRun, as that runs a different time
+ depending on whether this file is built with emcc 3.1.x or
+ 4.0.x. This function name is intentionally obnoxiously verbose to
+ ensure that we don't collide with current and future Emscripten
+ symbol names. */
'use strict';
+ //console.warn("This is the start of Module.runSQLite3PostLoadInit()");
/* This function will contain at least the following:
- - post-js-header.js (this file)
+ - post-js-header.js => this file
- sqlite3-api-prologue.js => Bootstrapping bits to attach the rest to
- common/whwasmutil.js => Replacements for much of Emscripten's glue
- - jaccwaby/jaccwabyt.js => Jaccwabyt (C/JS struct binding)
+ - jaccwabyt/jaccwabyt.js => Jaccwabyt (C/JS struct binding)
- sqlite3-api-glue.js => glues previous parts together
- - sqlite3-api-oo.js => SQLite3 OO API #1
+ - sqlite3-api-oo1.js => SQLite3 OO API #1
- sqlite3-api-worker1.js => Worker-based API
- sqlite3-vfs-helper.c-pp.js => Utilities for VFS impls
- sqlite3-vtab-helper.c-pp.js => Utilities for virtual table impls
- - sqlite3-vfs-opfs.c-pp.js => OPFS VFS
+ - sqlite3-vfs-opfs.c-pp.js => OPFS VFS
- sqlite3-vfs-opfs-sahpool.c-pp.js => OPFS SAHPool VFS
- sqlite3-api-cleanup.js => final API cleanup
- - post-js-footer.js => closes this postRun() function
+ - post-js-footer.js => closes this function
*/
diff --git a/ext/wasm/api/sqlite3-api-cleanup.js b/ext/wasm/api/sqlite3-api-cleanup.js
index 65dbb4eb6..7fb29e648 100644
--- a/ext/wasm/api/sqlite3-api-cleanup.js
+++ b/ext/wasm/api/sqlite3-api-cleanup.js
@@ -14,6 +14,9 @@
intended to be appended after all other sqlite3-api-*.js files so
that it can finalize any setup and clean up any global symbols
temporarily used for setting up the API's various subsystems.
+
+ In Emscripten builds it's run in the context of a Module.postRun
+ handler.
*/
'use strict';
if('undefined' !== typeof Module){ // presumably an Emscripten build
diff --git a/ext/wasm/api/sqlite3-api-glue.c-pp.js b/ext/wasm/api/sqlite3-api-glue.c-pp.js
index 680218370..a40b83282 100644
--- a/ext/wasm/api/sqlite3-api-glue.c-pp.js
+++ b/ext/wasm/api/sqlite3-api-glue.c-pp.js
@@ -228,13 +228,49 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}),
'*'
]],
+ /**
+ We do not have a way to automatically clean up destructors
+ which are automatically converted from JS functions via the
+ final argument to sqlite3_set_auxdata(). Because of that,
+ automatic function conversion is not supported for this
+ function. Clients should use wasm.installFunction() to create
+ such callbacks, then pass that pointer to
+ sqlite3_set_auxdata(). Relying on automated conversions here
+ would lead to leaks of JS/WASM proxy functions because
+ sqlite3_set_auxdata() is frequently called in UDFs.
+
+ The sqlite3.oo1.DB class's onclose handlers can be used for this
+ purpose. For example:
+
+ const pAuxDtor = wasm.installFunction('v(p)', function(ptr){
+ //free ptr
+ });
+ myDb.onclose = {
+ after: ()=>{
+ wasm.uninstallFunction(pAuxDtor);
+ }
+ };
+
+ Then pass pAuxDtor as the final argument to appropriate
+ sqlite3_set_auxdata() calls.
+
+ Note that versions prior to 3.49.0 ostensibly had automatic
+ function conversion here but a typo prevented it from
+ working. Rather than fix it, it was removed because testing the
+ fix brought the huge potential for memory leaks to the
+ forefront.
+ */
["sqlite3_set_auxdata", undefined, [
"sqlite3_context*", "int", "*",
- new wasm.xWrap.FuncPtrAdapter({
- name: 'xDestroyAuxData',
- signature: 'v(*)',
- contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
- })
+ true
+ ? "*"
+ : new wasm.xWrap.FuncPtrAdapter({
+ /* If we can find a way to automate their cleanup, JS functions can
+ be auto-converted with this. */
+ name: 'xDestroyAuxData',
+ signature: 'v(p)',
+ contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
+ })
]],
["sqlite3_shutdown", undefined],
["sqlite3_sourceid", "string"],
@@ -1047,6 +1083,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
'sqlite3_set_authorizer',
'sqlite3_trace_v2',
'sqlite3_update_hook'
+ /*
+ We do not yet have a way to clean up automatically-converted
+ sqlite3_set_auxdata() finalizers.
+ */
]) {
const x = wasm.exports[name];
if( !x ){
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index c8db3698c..6b032be84 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -12,12 +12,12 @@
This file is intended to be combined at build-time with other
related code, most notably a header and footer which wraps this
- whole file into an Emscripten Module.postRun() handler. The sqlite3
- JS API has no hard requirements on Emscripten and does not expose
- any Emscripten APIs to clients. It is structured such that its build
- can be tweaked to include it in arbitrary WASM environments which
- can supply the necessary underlying features (e.g. a POSIX file I/O
- layer).
+ whole file into a single callback which can be run after Emscripten
+ loads the corresponding WASM module. The sqlite3 JS API has no hard
+ requirements on Emscripten and does not expose any Emscripten APIs
+ to clients. It is structured such that its build can be tweaked to
+ include it in arbitrary WASM environments which can supply the
+ necessary underlying features (e.g. a POSIX file I/O layer).
Main project home page: https://sqlite.org
@@ -1712,41 +1712,48 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
missing or falsy pointer argument as 0.
*/
capi.sqlite3_db_config = function(pDb, op, ...args){
- if(!this.s){
- this.s = wasm.xWrap('sqlite3__wasm_db_config_s','int',
- ['sqlite3*', 'int', 'string:static']
- /* MAINDBNAME requires a static string */);
- this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int',
- ['sqlite3*', 'int', '*','int', 'int']);
- this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip','int',
- ['sqlite3*', 'int', 'int','*']);
- }
switch(op){
- case capi.SQLITE_DBCONFIG_ENABLE_FKEY:
- case capi.SQLITE_DBCONFIG_ENABLE_TRIGGER:
- case capi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
- case capi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
- case capi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE:
- case capi.SQLITE_DBCONFIG_ENABLE_QPSG:
- case capi.SQLITE_DBCONFIG_TRIGGER_EQP:
- case capi.SQLITE_DBCONFIG_RESET_DATABASE:
- case capi.SQLITE_DBCONFIG_DEFENSIVE:
- case capi.SQLITE_DBCONFIG_WRITABLE_SCHEMA:
- case capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE:
- case capi.SQLITE_DBCONFIG_DQS_DML:
- case capi.SQLITE_DBCONFIG_DQS_DDL:
- case capi.SQLITE_DBCONFIG_ENABLE_VIEW:
- case capi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT:
- case capi.SQLITE_DBCONFIG_TRUSTED_SCHEMA:
- case capi.SQLITE_DBCONFIG_STMT_SCANSTATUS:
- case capi.SQLITE_DBCONFIG_REVERSE_SCANORDER:
- return this.ip(pDb, op, args[0], args[1] || 0);
- case capi.SQLITE_DBCONFIG_LOOKASIDE:
- return this.pii(pDb, op, args[0], args[1], args[2]);
- case capi.SQLITE_DBCONFIG_MAINDBNAME:
- return this.s(pDb, op, args[0]);
- default:
- return capi.SQLITE_MISUSE;
+ case capi.SQLITE_DBCONFIG_ENABLE_FKEY:
+ case capi.SQLITE_DBCONFIG_ENABLE_TRIGGER:
+ case capi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
+ case capi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
+ case capi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE:
+ case capi.SQLITE_DBCONFIG_ENABLE_QPSG:
+ case capi.SQLITE_DBCONFIG_TRIGGER_EQP:
+ case capi.SQLITE_DBCONFIG_RESET_DATABASE:
+ case capi.SQLITE_DBCONFIG_DEFENSIVE:
+ case capi.SQLITE_DBCONFIG_WRITABLE_SCHEMA:
+ case capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE:
+ case capi.SQLITE_DBCONFIG_DQS_DML:
+ case capi.SQLITE_DBCONFIG_DQS_DDL:
+ case capi.SQLITE_DBCONFIG_ENABLE_VIEW:
+ case capi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT:
+ case capi.SQLITE_DBCONFIG_TRUSTED_SCHEMA:
+ case capi.SQLITE_DBCONFIG_STMT_SCANSTATUS:
+ case capi.SQLITE_DBCONFIG_REVERSE_SCANORDER:
+ case capi.SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE:
+ case capi.SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE:
+ case capi.SQLITE_DBCONFIG_ENABLE_COMMENTS:
+ if( !this.ip ){
+ this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip','int',
+ ['sqlite3*', 'int', 'int', '*']);
+ }
+ return this.ip(pDb, op, args[0], args[1] || 0);
+ case capi.SQLITE_DBCONFIG_LOOKASIDE:
+ if( !this.pii ){
+ this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int',
+ ['sqlite3*', 'int', '*', 'int', 'int']);
+ }
+ return this.pii(pDb, op, args[0], args[1], args[2]);
+ case capi.SQLITE_DBCONFIG_MAINDBNAME:
+ if(!this.s){
+ this.s = wasm.xWrap('sqlite3__wasm_db_config_s','int',
+ ['sqlite3*', 'int', 'string:static']
+ /* MAINDBNAME requires a static string */);
+ }
+ return this.s(pDb, op, args[0]);
+ default:
+ return capi.SQLITE_MISUSE;
}
}.bind(Object.create(null));
diff --git a/ext/wasm/api/sqlite3-api-worker1.c-pp.js b/ext/wasm/api/sqlite3-api-worker1.c-pp.js
index 991862545..5e088f438 100644
--- a/ext/wasm/api/sqlite3-api-worker1.c-pp.js
+++ b/ext/wasm/api/sqlite3-api-worker1.c-pp.js
@@ -279,11 +279,11 @@
The arguments are in the same form accepted by oo1.DB.exec(), with
the exceptions noted below.
- If the `countChanges` arguments property (added in version 3.43) is
- truthy then the `result` property contained by the returned object
- will have a `changeCount` property which holds the number of changes
- made by the provided SQL. Because the SQL may contain an arbitrary
- number of statements, the `changeCount` is calculated by calling
+ If `args.countChanges` (added in version 3.43) is truthy then the
+ `result` property contained by the returned object will have a
+ `changeCount` property which holds the number of changes made by the
+ provided SQL. Because the SQL may contain an arbitrary number of
+ statements, the `changeCount` is calculated by calling
`sqlite3_total_changes()` before and after the SQL is evaluated. If
the value of `countChanges` is 64 then the `changeCount` property
will be returned as a 64-bit integer in the form of a BigInt (noting
@@ -292,6 +292,15 @@
calling `sqlite3_total_changes64()` before and after the SQL is
evaluated.
+ If the `args.lastInsertRowId` (added in version 3.50.0) is truthy
+ then the `result` property contained by the returned object will
+ have a `lastInsertRowId` will hold a BigInt-type value corresponding
+ to the result of sqlite3_last_insert_rowid(). This value is only
+ fetched once, after the SQL is run, regardless of how many
+ statements the SQL contains. This API has no idea whether the SQL
+ contains any INSERTs, so it is up to the client to apply/rely on
+ this property only when it makes sense to do so.
+
A function-type args.callback property cannot cross
the window/Worker boundary, so is not useful here. If
args.callback is a string then it is assumed to be a
@@ -542,6 +551,12 @@ sqlite3.initWorker1API = function(){
if(undefined !== changeCount){
rc.changeCount = db.changes(true,64===rc.countChanges) - changeCount;
}
+ const lastInsertRowId = !!rc.lastInsertRowId
+ ? sqlite3.capi.sqlite3_last_insert_rowid(db)
+ : undefined;
+ if( undefined!==lastInsertRowId ){
+ rc.lastInsertRowId = lastInsertRowId;
+ }
if(rc.callback instanceof Function){
rc.callback = theCallback;
/* Post a sentinel message to tell the client that the end
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index c5dd495e5..461afe066 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -331,7 +331,6 @@ SQLITE_WASM_EXPORT void sqlite3__wasm_pstack_restore(unsigned char * p){
*/
SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_alloc(int n){
if( n<=0 ) return 0;
- //if( n & 0x7 ) n += 8 - (n & 0x7) /* align to 8-byte boundary */;
n = (n + 7) & ~7 /* align to 8-byte boundary */;
if( PStack.pBegin + n > PStack.pPos /*not enough space left*/
|| PStack.pBegin + n <= PStack.pBegin /*overflow*/ ) return 0;
@@ -597,6 +596,9 @@ const char * sqlite3__wasm_enum_json(void){
DefInt(SQLITE_DBCONFIG_TRUSTED_SCHEMA);
DefInt(SQLITE_DBCONFIG_STMT_SCANSTATUS);
DefInt(SQLITE_DBCONFIG_REVERSE_SCANORDER);
+ DefInt(SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE);
+ DefInt(SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE);
+ DefInt(SQLITE_DBCONFIG_ENABLE_COMMENTS);
DefInt(SQLITE_DBCONFIG_MAX);
} _DefGroup;
@@ -1630,6 +1632,9 @@ int sqlite3__wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
case SQLITE_DBCONFIG_TRUSTED_SCHEMA:
case SQLITE_DBCONFIG_STMT_SCANSTATUS:
case SQLITE_DBCONFIG_REVERSE_SCANORDER:
+ case SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE:
+ case SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE:
+ case SQLITE_DBCONFIG_ENABLE_COMMENTS:
return sqlite3_db_config(pDb, op, arg1, pArg2);
default: return SQLITE_MISUSE;
}
diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js
index 25400d48e..509d33b37 100644
--- a/ext/wasm/common/whwasmutil.js
+++ b/ext/wasm/common/whwasmutil.js
@@ -51,7 +51,7 @@
Its global-scope symbol is intended only to provide an easy way to
make it available to 3rd-party scripts and "should" be deleted
- after calling it. That symbols is _not_ used within the library.
+ after calling it. That symbol is _not_ used within the library.
Forewarning: this API explicitly targets only browser
environments. If a given non-browser environment has the
@@ -69,7 +69,8 @@
- WASM-exported "indirect function table" access and
manipulation. e.g. creating new WASM-side functions using JS
functions, analog to Emscripten's addFunction() and
- uninstallFunction() but slightly different.
+ uninstallFunction() but slightly different and with more useful
+ lifetime semantics.
- Get/set specific heap memory values, analog to Emscripten's
getValue() and setValue().
@@ -165,11 +166,11 @@
This code is developed and maintained in conjunction with the
Jaccwabyt project:
- https://fossil.wanderinghorse.net/r/jaccwabbyt
+ https://fossil.wanderinghorse.net/r/jaccwabyt
More specifically:
- https://fossil.wanderinghorse.net/r/jaccwabbyt/file/common/whwasmutil.js
+ https://fossil.wanderinghorse.net/r/jaccwabyt/file/common/whwasmutil.js
*/
globalThis.WhWasmUtilInstaller = function(target){
'use strict';
@@ -1627,7 +1628,7 @@ globalThis.WhWasmUtilInstaller = function(target){
need a level of hand-written wrappers around them, depending on
how they're used, in order to provide the client with JS
strings. Alternately, clients will need to perform such conversions
- on their own, e.g. using cstrtojs(). Or maybe we can find a way
+ on their own, e.g. using cstrToJs(). Or maybe we can find a way
to perform such conversions here, via addition of an xWrap()-style
function signature to the options argument.
*/
@@ -2055,7 +2056,7 @@ globalThis.WhWasmUtilInstaller = function(target){
if(1===argc) return xcvPart.get(typeName);
else if(2===argc){
if(!adapter){
- delete xcvPart.get(typeName);
+ xcvPart.delete(typeName);
return func;
}else if(!(adapter instanceof Function)){
toss(modeName,"requires a function argument.");
diff --git a/ext/wasm/config.make.in b/ext/wasm/config.make.in
new file mode 100644
index 000000000..f30baac3f
--- /dev/null
+++ b/ext/wasm/config.make.in
@@ -0,0 +1,15 @@
+# Gets filtered by the configure script
+bin.bash = @BIN_BASH@
+bin.emcc = @EMCC_WRAPPER@
+bin.wasm-strip = @BIN_WASM_STRIP@
+bin.wasm-opt = @BIN_WASM_OPT@
+
+SHELL := $(bin.bash)
+
+# The following overrides can be uncommented to test various
+# validation and if/else branches the makefile code:
+#
+#bin.bash :=
+#bin.emcc :=
+#bin.wasm-strip :=
+#bin.wasm-opt :=
diff --git a/ext/wasm/demo-worker1-promiser.c-pp.js b/ext/wasm/demo-worker1-promiser.c-pp.js
index f6fc9568a..0b8557b82 100644
--- a/ext/wasm/demo-worker1-promiser.c-pp.js
+++ b/ext/wasm/demo-worker1-promiser.c-pp.js
@@ -115,6 +115,7 @@ delete globalThis.sqlite3Worker1Promiser;
"insert into t(a,b) values(1,2),(3,4),(5,6)"
].join(';'),
resultRows: [], columnNames: [],
+ lastInsertRowId: true,
countChanges: sqConfig.bigIntEnabled ? 64 : true
}, function(ev){
ev = ev.result;
@@ -122,7 +123,9 @@ delete globalThis.sqlite3Worker1Promiser;
.assert(0===ev.columnNames.length)
.assert(sqConfig.bigIntEnabled
? (3n===ev.changeCount)
- : (3===ev.changeCount));
+ : (3===ev.changeCount))
+ .assert('bigint'===typeof ev.lastInsertRowId)
+ .assert(ev.lastInsertRowId>=3);
});
await wtest('exec',{
diff --git a/ext/wasm/demo-worker1.js b/ext/wasm/demo-worker1.js
index 60f5e8dec..1a05cc7ac 100644
--- a/ext/wasm/demo-worker1.js
+++ b/ext/wasm/demo-worker1.js
@@ -156,11 +156,14 @@
sql: ["create table t(a,b);",
"insert into t(a,b) values(1,2),(3,4),(5,6)"
],
+ lastInsertRowId: true,
resultRows: [], columnNames: []
}, function(ev){
ev = ev.result;
T.assert(0===ev.resultRows.length)
- .assert(0===ev.columnNames.length);
+ .assert(0===ev.columnNames.length)
+ .assert('bigint'===typeof ev.lastInsertRowId)
+ .assert(ev.lastInsertRowId>=3);
});
runOneTest('exec',{
sql: 'select a a, b b from t order by a',
diff --git a/ext/wasm/dist.make b/ext/wasm/dist.make
index e820e066d..60699ff5c 100644
--- a/ext/wasm/dist.make
+++ b/ext/wasm/dist.make
@@ -97,6 +97,16 @@ STRIP_K2.js := $(sqlite3.js) $(sqlite3.mjs) \
# Note that we require $(bin.version-info) in order to figure out the
# dist file's name, so cannot (without a recursive make) have the
# target name equal to the archive name.
+#
+# 2025-01-15: Emsdk 4.0.0 introduces, in its generated code, a regex
+# which contains the pattern /*. That, of course, confuses any C-style
+# comment-stripper which is not specifically JS-aware and smart enough
+# to know that it's in a regex or string literal. Because of that,
+# comment-stripping is currently disabled, which means the builds will
+# be significantly larger than before.
+#apply_comment_stripper := false
+apply_comment_stripper := true
+# ^^^ shell command true or false
dist: \
$(bin.stripccomments) $(bin.version-info) \
$(dist.build) $(STRIP_K1.js) $(STRIP_K2.js) \
@@ -109,8 +119,8 @@ dist: \
@cp -p README-dist.txt $(dist-dir.top)/README.txt
@cp -p index-dist.html $(dist-dir.top)/index.html
@cp -p $(dist.jswasm.extras) $(dist-dir.jswasm)
- @$(foreach JS,$(STRIP_K1.js),$(call DIST_STRIP_COMMENTS,$(JS),-k))
- @$(foreach JS,$(STRIP_K2.js),$(call DIST_STRIP_COMMENTS,$(JS),-k -k))
+ @if $(apply_comment_stripper); then $(foreach JS,$(STRIP_K1.js),$(call DIST_STRIP_COMMENTS,$(JS),-k)) fi
+ @if $(apply_comment_stripper); then $(foreach JS,$(STRIP_K2.js),$(call DIST_STRIP_COMMENTS,$(JS),-k -k)) fi
@cp -p $(dist.common.extras) $(dist-dir.common)
@set -e; \
vnum=$$($(bin.version-info) --download-version); \
diff --git a/ext/wasm/index-dist.html b/ext/wasm/index-dist.html
index 7b778b020..47bae3f7a 100644
--- a/ext/wasm/index-dist.html
+++ b/ext/wasm/index-dist.html
@@ -97,8 +97,8 @@
wrapper is significantly easier to use, however.</li>
<li><a href='demo-worker1-promiser.html'>demo-worker1-promiser</a>:
a demo of the Promise-based wrapper of the Worker1 API.</li>
- <li><a href='demo-worker1-promiser-esm.html'>demo-worker1-promiser-esm</a>:
- same as the previous demo except loads the promiser from an ESM module.</li>
+ <!--li><a href='demo-worker1-promiser-esm.html'>demo-worker1-promiser-esm</a>:
+ same as the previous demo except loads the promiser from an ESM module.</li-->
</ul>
</li>
</ul>
diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c
index 29b6cafae..91c03b6d4 100644
--- a/ext/wasm/mkwasmbuilds.c
+++ b/ext/wasm/mkwasmbuilds.c
@@ -64,6 +64,75 @@ static void mk_prologue(void){
ps("# pre-post-jses.deps.* = a list of dependencies for the");
ps("# --[extern-][pre/post]-js files.");
ps("pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)");
+
+ {
+ /* SQLITE.CALL.WASM-OPT = shell code to run $(1) (source wasm file
+ ** name) through $(bin.wasm-opt) */
+ const char * zOptFlags =
+ /*
+ ** Flags for wasm-opt. It has many, many, MANY "passes" options
+ ** and the ones which appear here were selected solely on the
+ ** basis of trial and error.
+ **
+ ** All wasm file size savings/costs mentioned below are based on
+ ** the vanilla build of sqlite3.wasm with -Oz (our shipping
+ ** configuration). Comments like "saves nothing" may not be
+ ** technically correct: "nothing" means "some neglible amount."
+ **
+ ** Note that performance gains/losses are _not_ taken into
+ ** account here: only wasm file size.
+ */
+ "--enable-bulk-memory-opt " /* required */
+ "--all-features " /* required */
+ "--post-emscripten " /* Saves roughly 12kb */
+ "--strip-debug " /* We already wasm-strip, but in
+ ** case this environment has no
+ ** wasm-strip... */
+ /*
+ ** The rest are trial-and-error. See wasm-opt --help and search
+ ** for "Optimization passes" to find the full list.
+ **
+ ** With many flags this gets unusuably slow.
+ */
+ /*"--converge " saves nothing for the options we're using */
+ /*"--dce " saves nothing */
+ /*"--directize " saves nothing */
+ /*"--gsi " no: requires --closed-world flag, which does not
+ ** sound like something we want. */
+ /*"--gufa --gufa-cast-all --gufa-optimizing " costs roughly 2kb */
+ /*"--heap-store-optimization " saves nothing */
+ /*"--heap2local " saves nothing */
+ //"--inlining --inlining-optimizing " costs roughly 3kb */
+ "--local-cse " /* saves roughly 1kb */
+ /*"--once-reduction " saves nothing */
+ /*"--remove-memory-init " presumably a performance tweak */
+ /*"--remove-unused-names " saves nothing */
+ /*"--safe-heap "*/
+ /*"--vacuum " saves nothing */
+ ;
+ ps("ifeq (,$(bin.wasm-opt))");
+ ps("define SQLITE.CALL.WASM-OPT");
+ ps("echo 'wasm-opt not available for $(1)'");
+ ps("endef");
+ ps("else");
+ ps("define SQLITE.CALL.WASM-OPT");
+ pf("echo -n 'Before wasm-opt:'; ls -l $(1);\\\n"
+ "\trm -f wasm-opt-tmp.wasm;\\\n"
+ /* It's very likely that the set of wasm-opt flags varies from
+ ** version to version, so we'll ignore any errors here. */
+ "\tif $(bin.wasm-opt) $(1) -o wasm-opt-tmp.wasm \\\n"
+ "\t\t%s; then \\\n"
+ "\t\tmv wasm-opt-tmp.wasm $(1); \\\n"
+ "\t\techo -n 'After wasm-opt: '; \\\n"
+ "\t\tls -l $(1); \\\n"
+ "\telse \\\n"
+ "\t\techo 'WARNING: ignoring wasm-opt failure'; \\\n"
+ "\tfi\n",
+ zOptFlags
+ );
+ ps("endef");
+ ps("endif");
+ }
}
/*
@@ -75,23 +144,23 @@ static void mk_pre_post(const char *zName /* build name */,
const char *zMode /* build mode */,
const char *zCmppD /* optional -D flags for c-pp for the
** --pre/--post-js files. */){
- pf("%s# Begin --pre/--post flags for %s-%s\n", zBanner, zName, zMode);
+ pf("%s# Begin --pre/--post flags for %s-%s\n", zBanner, zNM);
pf("c-pp.D.%s-%s := %s\n", zNM, zCmppD ? zCmppD : "");
pf("pre-post-%s-%s.flags ?=\n", zNM);
/* --pre-js=... */
pf("pre-js.js.%s-%s := $(dir.tmp)/pre-js.%s-%s.js\n",
zNM, zNM);
- pf("$(pre-js.js.%s-%s): $(MAKEFILE)\n", zNM);
+ pf("$(pre-js.js.%s-%s): $(MAKEFILE_LIST)\n", zNM);
#if 1
- pf("$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.%s-%s),"
+ pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.%s-%s),"
"$(c-pp.D.%s-%s)))\n", zNM, zNM);
#else
/* This part is needed if/when we re-enable the custom
** Module.instantiateModule() impl in api/pre-js.c-pp.js. */
pf("pre-js.js.%s-%s.intermediary := $(dir.tmp)/pre-js.%s-%s.intermediary.js\n",
zNM, zNM);
- pf("$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.%s-%s.intermediary),"
+ pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.%s-%s.intermediary),"
"$(c-pp.D.%s-%s) -Dcustom-Module.instantiateModule))\n", zNM, zNM);
pf("$(pre-js.js.%s-%s): $(pre-js.js.%s-%s.intermediary)\n", zNM, zNM);
pf("\tcp $(pre-js.js.%s-%s.intermediary) $@\n", zNM);
@@ -107,12 +176,12 @@ static void mk_pre_post(const char *zName /* build name */,
/* --post-js=... */
pf("post-js.js.%s-%s := $(dir.tmp)/post-js.%s-%s.js\n", zNM, zNM);
- pf("$(eval $(call C-PP.FILTER,$(post-js.js.in),"
+ pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(post-js.js.in),"
"$(post-js.js.%s-%s),$(c-pp.D.%s-%s)))\n", zNM, zNM);
/* --extern-post-js=... */
pf("extern-post-js.js.%s-%s := $(dir.tmp)/extern-post-js.%s-%s.js\n", zNM, zNM);
- pf("$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.%s-%s),"
+ pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.%s-%s),"
"$(c-pp.D.%s-%s)))\n", zNM, zNM);
/* Combine flags for use with emcc... */
@@ -130,7 +199,7 @@ static void mk_pre_post(const char *zName /* build name */,
zNM, zNM, zNM);
pf("pre-post-%s-%s.deps := $(pre-post-jses.%s-%s.deps) $(dir.tmp)/pre-js.%s-%s.js\n",
zNM, zNM, zNM);
- pf("# End --pre/--post flags for %s-%s%s", zName, zMode, zBanner);
+ pf("# End --pre/--post flags for %s-%s%s", zNM, zBanner);
}
/*
@@ -149,29 +218,29 @@ static void mk_fiddle(){
pf("fiddle-module.js%s := %s/fiddle-module.js\n", zTail, zDir);
pf("fiddle-module.wasm%s := "
"$(subst .js,.wasm,$(fiddle-module.js%s))\n", zTail, zTail);
- pf("$(fiddle-module.js%s):%s $(MAKEFILE) $(MAKEFILE.fiddle) "
+ pf("$(fiddle-module.js%s):%s $(MAKEFILE_LIST) $(MAKEFILE.fiddle) "
"$(EXPORTED_FUNCTIONS.fiddle) "
"$(fiddle.cses) $(pre-post-fiddle-module-vanilla.deps) "
"$(SOAP.js)\n",
zTail, (i ? " $(fiddle-module.js)" : ""));
if( 1==i ){/*fiddle.debug*/
- pf(" @test -d \"$(dir $@)\" || mkdir -p \"$(dir $@)\"\n");
+ pf("\t@test -d \"$(dir $@)\" || mkdir -p \"$(dir $@)\"\n");
}
- pf(" $(emcc.bin) -o $@ $(fiddle.emcc-flags%s) "
+ pf("\t$(bin.emcc) -o $@ $(fiddle.emcc-flags%s) "
"$(pre-post-fiddle-module-vanilla.flags) $(fiddle.cses)\n",
zTail);
- pf(" $(maybe-wasm-strip) $(fiddle-module.wasm%s)\n", zTail);
- pf(" @cp -p $(SOAP.js) $(dir $@)\n");
+ pf("\t$(maybe-wasm-strip) $(fiddle-module.wasm%s)\n", zTail);
+ pf("\t@cp -p $(SOAP.js) $(dir $@)\n");
if( 1==i ){/*fiddle.debug*/
- pf(" cp -p $(dir.fiddle)/index.html "
+ pf("\tcp -p $(dir.fiddle)/index.html "
"$(dir.fiddle)/fiddle.js "
"$(dir.fiddle)/fiddle-worker.js "
"$(dir $@)\n");
}
- pf(" @for i in %s/*.*js %s/*.html %s/*.wasm; do \\\n"
- " test -f $${i} || continue; \\\n"
- " gzip < $${i} > $${i}.gz; \\\n"
- " done\n", zDir, zDir, zDir);
+ pf("\t@for i in %s/*.*js %s/*.html %s/*.wasm; do \\\n"
+ "\t\ttest -f $${i} || continue; \\\n"
+ "\t\tgzip < $${i} > $${i}.gz; \\\n"
+ "\tdone\n", zDir, zDir, zDir);
if( 0==i ){
ps("fiddle: $(fiddle-module.js)");
}else{
@@ -193,6 +262,10 @@ static void mk_lib_mode(const char *zName /* build name */,
const char *zJsOut /* name of generated sqlite3.js/.mjs */,
const char *zCmppD /* extra -D flags for c-pp */,
const char *zEmcc /* extra flags for emcc */){
+ const char * zWasmOut = "$(basename $@).wasm"
+ /* The various targets named X.js or X.mjs (zJsOut) also generate
+ ** X.wasm, and we need that part of the name to perform some
+ ** post-processing after Emscripten generates X.wasm. */;
assert( zName );
assert( zMode );
assert( zApiJsOut );
@@ -201,22 +274,29 @@ static void mk_lib_mode(const char *zName /* build name */,
if( !zEmcc ) zEmcc = "";
pf("%s# Begin build [%s-%s]\n", zBanner, zNM);
- pf("ifneq (1,$(MAKING_CLEAN))\n");
+ pf("# zApiJsOut=%s\n# zJsOut=%s\n# zCmppD=%s\n", zApiJsOut, zJsOut, zCmppD);
pf("$(info Setting up build [%s-%s]: %s)\n", zNM, zJsOut);
mk_pre_post(zNM, zCmppD);
pf("\nemcc.flags.%s.%s ?=\n", zNM);
if( zEmcc[0] ){
pf("emcc.flags.%s.%s += %s\n", zNM, zEmcc);
}
- pf("$(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), %s, %s))\n",
+ pf("$(eval $(call SQLITE.CALL.C-PP.FILTER, $(sqlite3-api.js.in), %s, %s))\n",
zApiJsOut, zCmppD);
/* target zJsOut */
- pf("%s: %s $(MAKEFILE) $(sqlite3-wasm.cfiles) $(EXPORTED_FUNCTIONS.api) "
- "$(pre-post-%s-%s.deps)\n",
+ pf("%s: %s $(MAKEFILE_LIST) $(sqlite3-wasm.cfiles) $(EXPORTED_FUNCTIONS.api) "
+ "$(pre-post-%s-%s.deps) "
+ "$(sqlite3-api.ext.jses)"
+ /* ^^^ maintenance reminder: we set these as deps so that they
+ get copied into place early. That allows the developer to
+ reload the base-most test pages while the later-stage builds
+ are still compiling, which is especially helpful when running
+ builds with long build times (like -Oz). */
+ "\n",
zJsOut, zApiJsOut, zNM);
pf("\t@echo \"Building $@ ...\"\n");
- pf("\t$(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \\\n");
+ pf("\t$(bin.emcc) -o $@ $(emcc_opt_full) $(emcc.flags) \\\n");
pf("\t\t$(emcc.jsflags) -sENVIRONMENT=$(emcc.environment.%s) \\\n", zMode);
pf("\t\t$(pre-post-%s-%s.flags) \\\n", zNM);
pf("\t\t$(emcc.flags.%s) $(emcc.flags.%s.%s) \\\n", zName, zNM);
@@ -224,36 +304,59 @@ static void mk_lib_mode(const char *zName /* build name */,
"\t\t$(cflags.%s) $(cflags.%s.%s) \\\n"
"\t\t$(cflags.wasm_extra_init) $(sqlite3-wasm.cfiles)\n", zName, zNM);
if( bIsEsm ){
- /* TODO? Replace this CALL with the corresponding makefile code.
- ** OTOH, we also use this $(call) in the speedtest1-wasmfs build,
- ** which is not part of the rules emitted by this program. */
- pf("\t@$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,1,%d)\n",
+ /* TODO? Replace this $(call) with the corresponding makefile
+ ** code. OTOH, we also use this $(call) in the speedtest1-wasmfs
+ ** build, which is not part of the rules emitted by this
+ ** program. */
+ pf("\t@$(call SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT,1,%d)\n",
0==strcmp("sqlite3-wasmfs", zName) ? 1 : 0);
}
- pf("\t@dotwasm=$(basename $@).wasm; \\\n"
- "\tchmod -x $$dotwasm; \\\n"
- "\t$(maybe-wasm-strip) $$dotwasm; \\\n");
+ pf("\t@chmod -x %s; \\\n"
+ "\t\t$(maybe-wasm-strip) %s;\n",
+ zWasmOut, zWasmOut);
+ pf("\t@$(call SQLITE.CALL.WASM-OPT,%s)\n", zWasmOut);
+ pf("\t@sed -i -e '/^var _sqlite3.*createExportWrapper/d' %s || exit; \\\n"
+ /* ^^^^^^ reminder: Mac/BSD sed has no -i flag */
+ "\t\techo 'Stripped out createExportWrapper() parts.'\n",
+ zJsOut) /* Our JS code installs bindings of each WASM export. The
+ generated Emscripten JS file does the same using its
+ own framework, but we don't use those results and can
+ speed up lib init, and reduce memory cost
+ considerably, by stripping them out. */;
/*
- ** The above $(emcc.bin) call will write zJsOut and will create a
- ** like-named .wasm file. That .wasm file name gets hard-coded into
- ** zJsOut so we need to, for some cases, patch zJsOut to use the
- ** name sqlite3.wasm instead. Note that the resulting .wasm file is
- ** identical for all builds for which zEmcc is empty.
+ ** The above $(bin.emcc) call will write zJsOut and will create a
+ ** like-named .wasm file (zWasmOut). That .wasm file name gets
+ ** hard-coded into zJsOut so we need to, for some cases, patch
+ ** zJsOut to use the name sqlite3.wasm instead. Note that the
+ ** resulting .wasm file is identical for all builds for which zEmcc
+ ** is empty.
*/
if( 0==strcmp("bundler-friendly", zMode)
- || 0==strcmp("node", zMode) ) {
- pf("\techo 'Patching $@ for %s.wasm...' \\\n", zName);
- pf("\trm -f $$dotwasm; dotwasm=; \\\n"
- "\tsed -i -e 's/%s-%s.wasm/%s.wasm/g' $@ || exit $$?; \\\n",
+ || 0==strcmp("node", zMode) ){
+ pf("\t@echo 'Patching $@ for %s.wasm...'; \\\n", zName);
+ pf("\t\trm -f %s; \\\n", zWasmOut);
+ pf("\t\tsed -i -e 's/%s-%s.wasm/%s.wasm/g' $@ || exit;\n",
+ /* ^^^^^^ reminder: Mac/BSD sed has no -i flag */
zNM, zName);
+ pf("\t@ls -la $@\n");
+ if( 0==strcmp("bundler-friendly", zMode) ){
+ /* Avoid a 3rd occurance of the bug fixed by 65798c09a00662a3,
+ ** which was (in two cases) caused by makefile refactoring and
+ ** not recognized until after a release was made with the broken
+ ** sqlite3-bundler-friendly.mjs: */
+ pf("\t@if grep -e '^ *importScripts(' $@; "
+ "then echo 'ERROR: bug fixed in 65798c09a00662a3 has re-appeared'; "
+ "exit 1; fi;\n");
+ }
+
+ }else{
+ pf("\t@ls -la %s $@\n", zWasmOut);
}
- pf("\tls -la $$dotwasm $@\n");
if( 0!=strcmp("sqlite3-wasmfs", zName) ){
/* The sqlite3-wasmfs build is optional and needs to be invoked
** conditionally using info we don't have here. */
pf("all: %s\n", zJsOut);
}
- ps("endif\n# ^^^ !$(MAKING_CLEAN)");
pf("# End build [%s-%s]%s", zNM, zBanner);
}
diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js
index a21a1c330..28d61de07 100644
--- a/ext/wasm/tester1.c-pp.js
+++ b/ext/wasm/tester1.c-pp.js
@@ -1241,6 +1241,12 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}finally{
wasm.pstack.restore(stack);
}
+
+ capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_ENABLE_COMMENTS, 0, null);
+ T.mustThrow(()=>this.db.exec("select 1 /* with comments */"), "SQL comments are disallowed");
+ capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_ENABLE_COMMENTS, 1, null);
+ this.db.exec("select 1 /* with comments */");
+ /* SQLITE_DBCONFIG_ENABLE_ATTACH_... are in the ATTACH-specific tests */
})
////////////////////////////////////////////////////////////////////
@@ -1999,7 +2005,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}/*window UDFs*/)
////////////////////////////////////////////////////////////////////
- .t("ATTACH", function(){
+ .t("ATTACH", function(sqlite3){
const db = this.db;
const resultRows = [];
db.exec({
@@ -2078,7 +2084,36 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
db.exec("detach foo");
T.mustThrow(()=>db.exec("select * from foo.bar"),
"Because foo is no longer attached.");
- })
+
+ /* SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE/WRITE... */
+ const db2 = new sqlite3.oo1.DB();
+ try{
+ capi.sqlite3_db_config(db2, capi.SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE, 0, null);
+ T.mustThrow(()=>db2.exec("attach 'attached.db' as foo"),
+ "Cannot create a new db via ATTACH");
+ capi.sqlite3_db_config(db2, capi.SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE, 1, null);
+ db2.exec([
+ "attach 'attached.db' as foo;",
+ "create table foo.t(a);",
+ "insert into foo.t(a) values(1);",
+ "detach foo;"
+ ]);
+ capi.sqlite3_db_config(db2, capi.SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE, 0, null);
+ db2.exec("attach 'attached.db' as foo");
+ T.mustThrow(()=>db2.exec("insert into foo.t(a) values(2)"),
+ "ATTACH_WRITE is false");
+ capi.sqlite3_db_config(db2, capi.SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE, 1, null);
+ db2.exec([
+ "detach foo;",
+ "attach 'attached.db' as foo;",
+ "insert into foo.t(a) values(2);",
+ "drop table foo.t;",
+ "detach foo"
+ ]);
+ }finally{
+ db2.close();
+ }
+ })/*ATTACH tests*/
////////////////////////////////////////////////////////////////////
.t("Read-only", function(sqlite3){
@@ -3402,6 +3437,71 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}
}
})
+ .t({
+ /* https://github.com/sqlite/sqlite-wasm/issues/92 */
+ name: 'sqlite3_set_auxdata() binding signature',
+ test: function(sqlite3){
+ const db = new sqlite3.oo1.DB();
+ const stack = wasm.pstack.pointer;
+ const pAux = wasm.pstack.alloc(4);
+ let pAuxDestructed = 0;
+ const pAuxDtor = wasm.installFunction('v(p)', function(ptr){
+ //log("freeing auxdata");
+ ++pAuxDestructed;
+ });
+ let pAuxDtorDestructed = false;
+ db.onclose = {
+ after: ()=>{
+ pAuxDtorDestructed = true;
+ wasm.uninstallFunction(pAuxDtor);
+ }
+ };
+ let nAuxSet = 0 /* how many times we set aux data */;
+ let nAuxReused = 0 /* how many times we reused aux data */;
+ try{
+ db.createFunction("auxtest",{
+ xFunc: function(pCx, x, y){
+ T.assert(wasm.isPtr(pCx));
+ const localAux = capi.sqlite3_get_auxdata(pCx, 0);
+ if( !localAux ){
+ //log("setting auxdata");
+ /**
+ We do not currently an automated way to clean up
+ auxdata finalizer functions (the 4th argument to
+ sqlite3_set_auxdata()) which get automatically
+ converted from JS to WASM. Because of that, enabling
+ automated conversions here would lead to leaks more
+ often than not. Instead, follow the pattern show in
+ this function: use wasm.installFunction() to create
+ the function, then pass the resulting function
+ pointer this function, and cleanup (at some point)
+ using wasm.uninstallFunction().
+ */
+ ++nAuxSet;
+ capi.sqlite3_set_auxdata(pCx, 0, pAux, pAuxDtor);
+ }else{
+ //log("reusing auxdata",localAux);
+ T.assert(pAux===localAux);
+ ++nAuxReused;
+ }
+ return x;
+ }
+ });
+ db.exec([
+ "create table t(a);",
+ "insert into t(a) values(1),(2),(3);",
+ "select auxtest(1,a), auxtest(1,a) from t order by a"
+ ]);
+ }finally{
+ db.close();
+ wasm.pstack.restore(stack);
+ }
+ T.assert(nAuxSet>0).assert(nAuxReused>0)
+ .assert(6===nAuxReused+nAuxSet);
+ T.assert(pAuxDestructed>0);
+ T.assert(pAuxDtorDestructed);
+ }
+ })
;/*end of Bug Reports group*/;
////////////////////////////////////////////////////////////////////////
diff --git a/ext/wasm/wasmfs.make b/ext/wasm/wasmfs.make
index 9de5574f2..2c6fa35bd 100644
--- a/ext/wasm/wasmfs.make
+++ b/ext/wasm/wasmfs.make
@@ -101,7 +101,7 @@ $(speedtest1-wasmfs.mjs): $(speedtest1.cfiles) $(sqlite3-wasmfs.js) \
$(emcc.flags.sqlite3-wasmfs) \
$(emcc.flags.speedtest1-wasmfs) \
-o $@ $(speedtest1.cfiles) -lm
- @$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,1,1)
+ @$(call SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT,1,1)
$(maybe-wasm-strip) $(speedtest1-wasmfs.wasm)
chmod -x $(speedtest1-wasmfs.wasm)
ls -la $@ $(speedtest1-wasmfs.wasm)
diff --git a/main.mk b/main.mk
index f98850731..9eec5495e 100644
--- a/main.mk
+++ b/main.mk
@@ -163,9 +163,11 @@ LDFLAGS.rpath ?= -Wl,-rpath -Wl,$(prefix)/lib
LDFLAGS.pthread ?= -lpthread
LDFLAGS.dlopen ?= -ldl
LDFLAGS.shlib ?= -shared
+LDFLAGS.rt ?= # nanosleep on some platforms
LDFLAGS.icu ?= # -licui18n -licuuc -licudata
CFLAGS.icu ?=
LDFLAGS.libsqlite3.soname ?= # see https://sqlite.org/src/forumpost/5a3b44f510df8ded
+LDFLAGS.libsqlite3.os-specific ?= # see https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7
# libreadline (or a workalike):
# To activate readline in the shell: SHELL_OPT = -DHAVE_READLINE=1
LDFLAGS.readline ?= -lreadline # these vary across platforms
@@ -412,7 +414,7 @@ LDFLAGS.libsqlite3 = \
$(LDFLAGS.rpath) $(LDFLAGS.pthread) \
$(LDFLAGS.math) $(LDFLAGS.dlopen) \
$(LDFLAGS.zlib) $(LDFLAGS.icu) \
- $(LDFLAGS.configure)
+ $(LDFLAGS.rt) $(LDFLAGS.configure)
#
# $(install-dir.XYZ) = dirs for installation.
@@ -434,7 +436,8 @@ install-dir.all = $(install-dir.bin) $(install-dir.include) \
$(install-dir.lib) $(install-dir.man1) \
$(install-dir.pkgconfig)
$(install-dir.all):
- $(INSTALL) -d "$@"
+ if [ ! -d "$@" ]; then $(INSTALL) -d "$@"; fi
+# ^^^^ on some platforms, install -d fails if the target already exists.
#
# After jimsh is compiled, we run some sanity checks to ensure that
@@ -1043,9 +1046,9 @@ T.link.tcl = $(T.tcl.env.source); $(T.link)
rm -rf tsrc
mkdir tsrc
cp -f $(SRC) tsrc
- rm tsrc/sqlite.h.in tsrc/parse.y
+ rm -f tsrc/sqlite.h.in tsrc/parse.y
$(B.tclsh) $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new
- mv vdbe.new tsrc/vdbe.c
+ mv -f vdbe.new tsrc/vdbe.c
cp fts5.c fts5.h tsrc
touch .target_source
@@ -1066,7 +1069,7 @@ mksourceid$(B.exe): $(MAKE_SANITY_CHECK) $(TOP)/tool/mksourceid.c
sqlite3.h: $(MAKE_SANITY_CHECK) $(TOP)/src/sqlite.h.in \
$(TOP)/manifest mksourceid$(B.exe) \
$(TOP)/VERSION $(B.tclsh)
- $(B.tclsh) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
+ $(B.tclsh) $(TOP)/tool/mksqlite3h.tcl $(TOP) -o sqlite3.h
sqlite3.c: .target_source sqlite3.h $(TOP)/tool/mksqlite3c.tcl src-verify$(B.exe) \
$(B.tclsh)
@@ -1075,7 +1078,7 @@ sqlite3.c: .target_source sqlite3.h $(TOP)/tool/mksqlite3c.tcl src-verify$(B.exe
cp $(TOP)/ext/session/sqlite3session.h .
sqlite3r.h: sqlite3.h $(B.tclsh)
- $(B.tclsh) $(TOP)/tool/mksqlite3h.tcl $(TOP) --enable-recover >sqlite3r.h
+ $(B.tclsh) $(TOP)/tool/mksqlite3h.tcl $(TOP) --enable-recover -o sqlite3r.h
sqlite3r.c: sqlite3.c sqlite3r.h $(B.tclsh)
cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
@@ -1411,7 +1414,7 @@ all: lib
#
$(libsqlite3.SO): $(LIBOBJ)
$(T.link.shared) -o $@ $(LIBOBJ) $(LDFLAGS.libsqlite3) \
- $(LDFLAGS.libsqlite3.soname)
+ $(LDFLAGS.libsqlite3.os-specific) $(LDFLAGS.libsqlite3.soname)
$(libsqlite3.SO)-1: $(libsqlite3.SO)
$(libsqlite3.SO)-0 $(libsqlite3.SO)-:
so: $(libsqlite3.SO)-$(ENABLE_SHARED)
@@ -1429,6 +1432,9 @@ all: so
# unnecessary unless we want to set SONAME to libsqlite3.so.3, which
# is also unnecessary.
#
+# N.B. different transformations are applied on systems where $(T.dll)
+# is ".dylib" and none of the following docs apply on such systems.
+#
# The link named libsqlite3.so.0 is provided in an attempt to reduce
# downstream disruption when performing upgrades from pre-3.48 to a
# version 3.48 or higher. That name is considered a legacy remnant
@@ -1465,8 +1471,16 @@ all: so
#
install-so-1: $(install-dir.lib) $(libsqlite3.SO)
$(INSTALL) $(libsqlite3.SO) "$(install-dir.lib)"
- @echo "Setting up $(libsqlite3.SO) symlinks..."; \
- cd "$(install-dir.lib)" || exit $$?; \
+ @echo "Setting up $(libsqlite3.SO) version symlinks..."; \
+ cd "$(install-dir.lib)" || exit $$?; \
+ if [ x.dylib = x$(T.dll) ]; then \
+ rm -f libsqlite3.0$(T.dll) libsqlite3.$(PACKAGE_VERSION)$(T.dll) || exit $$?; \
+ dllname=libsqlite3.$(PACKAGE_VERSION)$(T.dll); \
+ mv $(libsqlite3.SO) $$dllname || exit $$?; \
+ ln -s $$dllname $(libsqlite3.SO) || exit $$?; \
+ ln -s $$dllname libsqlite3.0$(T.dll) || exit $$?; \
+ ls -la $$dllname $(libsqlite3.SO) libsqlite3.0$(T.dll); \
+ else \
rm -f $(libsqlite3.SO).0 $(libsqlite3.SO).$(PACKAGE_VERSION) || exit $$?; \
mv $(libsqlite3.SO) $(libsqlite3.SO).$(PACKAGE_VERSION) || exit $$?; \
ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO) || exit $$?; \
@@ -1482,7 +1496,8 @@ install-so-1: $(install-dir.lib) $(libsqlite3.SO)
rm -f libsqlite3.la $(libsqlite3.SO).0.8.6 || exit $$?; \
ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0.8.6 || exit $$?; \
ls -la $(libsqlite3.SO).0.8.6; \
- fi
+ fi; \
+ fi
install-so-0 install-so-:
install-so: install-so-$(ENABLE_SHARED)
install: install-so
@@ -1507,7 +1522,7 @@ install: install-headers
# libtclsqlite3...
#
pkgIndex.tcl:
- echo 'package ifneeded sqlite3 $(PACKAGE_VERSION) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@
+ echo 'package ifneeded sqlite3 $(PACKAGE_VERSION) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] Sqlite3]' > $@
pkgIndex.tcl-1: pkgIndex.tcl
pkgIndex.tcl-0 pkgIndex.tcl-:
tcl: pkgIndex.tcl-$(HAVE_TCL)
@@ -1572,7 +1587,14 @@ tclextension-uninstall:
# by $TCLSH_CMD, including prior versions.
#
tclextension-list:
- $(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --info
+ @ $(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --info
+
+# Verify that the SQLite TCL extension that is loaded by default
+# in $(TCLSH_CMD) is the same as the version of SQLite for the
+# current source tree
+#
+tclextension-verify: sqlite3.h
+ @ $(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --version-check
#
# FTS5 things
@@ -1929,6 +1951,21 @@ amalgamation-tarball: sqlite3.c sqlite3rc.h
snapshot-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
+# Build a ZIP archive snapshot of the latest check-in.
+#
+sqlite-src.zip: $(TOP)/tool/mksrczip.tcl
+ $(TCLSH_CMD) $(TOP)/tool/mksrczip.tcl
+
+# Build a ZIP archive of the amaglamation
+#
+sqlite-amalgamation.zip: $(TOP)/tool/mkamalzip.tcl sqlite3.c sqlite3.h shell.c sqlite3ext.h
+ $(TCLSH_CMD) $(TOP)/tool/mkamalzip.tcl
+
+# Build all the source code deliverables
+#
+src-archives: sqlite-amalgamation.zip amalgamation-tarball sqlite-src.zip
+ ls -ltr *.zip *.tar.gz | tail -3
+
# Build a ZIP archive containing various command-line tools.
#
tool-zip: testfixture$(T.exe) sqlite3$(T.exe) sqldiff$(T.exe) \
@@ -1995,7 +2032,7 @@ sqlite3d$(T.exe): shell.c $(LIBOBJS0)
$(LDFLAGS.libsqlite3) $(LDFLAGS.readline)
install-shell-0: sqlite3$(T.exe) $(install-dir.bin)
- $(INSTALL) -s sqlite3$(T.exe) "$(install-dir.bin)"
+ $(INSTALL) sqlite3$(T.exe) "$(install-dir.bin)"
install-shell-1:
install: install-shell-$(HAVE_WASI_SDK)
@@ -2009,7 +2046,7 @@ sqldiff$(T.exe): $(sqldiff.$(LINK_TOOLS_DYNAMICALLY).deps)
$(sqldiff.$(LINK_TOOLS_DYNAMICALLY).rules)
install-diff: sqldiff$(T.exe) $(install-dir.bin)
- $(INSTALL) -s sqldiff$(T.exe) "$(install-dir.bin)"
+ $(INSTALL) sqldiff$(T.exe) "$(install-dir.bin)"
#install: install-diff
dbhash$(T.exe): $(TOP)/tool/dbhash.c sqlite3.o sqlite3.h
@@ -2188,7 +2225,7 @@ SHELL_DEP = \
$(TOP)/src/test_windirent.h
shell.c: $(SHELL_DEP) $(TOP)/tool/mkshellc.tcl $(B.tclsh)
- $(B.tclsh) $(TOP)/tool/mkshellc.tcl >shell.c
+ $(B.tclsh) $(TOP)/tool/mkshellc.tcl shell.c
#
# Rules to build the extension objects.
@@ -2296,7 +2333,7 @@ tidy: tidy-.
rm -f lemon$(B.exe) sqlite*.tar.gz
rm -f mkkeywordhash$(B.exe) mksourceid$(B.exe)
rm -f parse.* fts5parse.*
- rm -f $(libsqlite3.SO) $(libsqlite3.LIB) $(libtclsqlite3.SO)
+ rm -f $(libsqlite3.SO) $(libsqlite3.LIB) $(libtclsqlite3.SO) libsqlite3$(T.dll).a
rm -f tclsqlite3$(T.exe) $(TESTPROGS)
rm -f LogEst$(T.exe) fts3view$(T.exe) rollback-test$(T.exe) showdb$(T.exe)
rm -f showjournal$(T.exe) showstat4$(T.exe) showwal$(T.exe) speedtest1$(T.exe)
diff --git a/manifest b/manifest
index 32d9f7e9f..75514bd2c 100644
--- a/manifest
+++ b/manifest
@@ -1,31 +1,30 @@
-C Experimental\schange\sto\sallow\sclients\sto\sblock\swhen\staking\sa\sSHARED\slock\sto\sconnect\sto\sa\swal\smode\sdatabase.
-D 2025-02-10T20:46:14.679
+C Merge\slatest\schanges\sfrom\strunk\sinto\sthis\sbranch.
+D 2025-02-11T17:10:46.191
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
-F Makefile.in ad349acf91b3569033439fe498fa197aa530cafaa01362eb7daad2f84e43d265
+F Makefile.in aa869faf7ca086f35c9b3e974fddc7fd65ed2dc45a246b1a94e6f9fdc99b0ed5
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
-F Makefile.msc 1fc95c6cb5677efe36b804a4b9afcb19e2c42caa3deef6e7455bb317a140e132
+F Makefile.msc b12d09789c2cd6e342ca13e9426e443400e31a766b2b93e1030b5955386cb9ed
F README.md c3c0f19532ce28f6297a71870f3c7b424729f0e6d9ab889616d3587dd2332159
-F VERSION 8dc0c3df15fd5ff0622f88fc483533fce990b1cbb2f5fb9fdfb4dbd71eef2889
+F VERSION 001dea55eb8304ec9130b6b44a32d3fc349f279d45a7e224fc0730c3cb8e2372
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F art/sqlite370.svg 40b7e2fe8aac3add5d56dd86ab8d427a4eca5bcb3fe4f8946cb3794e1821d531
-F auto.def 63dfbbc58b041d1c5c516f31a02679cce8d79123c89ad87fd2783f4ef26dedbb
-F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
-F autoconf/Makefile.am adedc1324b6a87fdd1265ddd336d2fb7d4f36a0e77b86ea553ae7cc4ea239347
+F auto.def ccf74471ec89edfd5bf942fd6d60fc8ce09f7aa7527d668a1ac44d1bbbcb412d
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
-F autoconf/Makefile.msc ffff61fe851443015ddb6600ab69a9df503cfec25459b336be7ba8c9a9e473f8
-F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
-F autoconf/README.txt 5e946ffb6fbdbb114c81e1bdc862df27fce8beab557d7b0421820b0fe8fc048f
-F autoconf/configure.ac ec7fa914c5e74ff212fe879f9bb6918e1234497e05facfb641f30c4d5893b277
+F autoconf/Makefile.in 7bd73a4c8cd89025cbc92b4f887c6fd1b8cd8ecbe62c4ac1f36ac84d04043479 w autoconf/Makefile.am
+F autoconf/Makefile.msc 0a071367537dc395285a5d624ac4f99f3a387b27cc5e89752423c0499e15aec4
+F autoconf/README.first f1d3876e9a7852c22f275a6f06814e64934cecbc0b5b9617d64849094c1fd136
+F autoconf/README.txt 7f01dc3915e2d68f329011073662369e62a0938a2c69398807823c57591cb288
+F autoconf/auto.def f468a32e6f57c52390e0fe2466974d0afaa1b0fc1d51cbacb4cb3950bd089f67
F autoconf/tea/Makefile.in ba0556fee8da09c066bad85a4457904e46ee2c2eabaa309c0e83a78f2f151a8e
F autoconf/tea/README.txt 61e62e519579e4a112791354d6d440f8b51ea6db3b0bab58d59f29df42d2dfe3
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
-F autoconf/tea/configure.ac ff2d745f88e493080810b67958d88b4f7a7d79f19e2ee8e7f72ffd6fc04eabc7
+F autoconf/tea/configure.ac 830cb2af5a3888312d0fd88402c2509d551d60e4c03f0481006a07c78313ef12
F autoconf/tea/doc/sqlite3.n e1fe45d4f5286ee3d0ccc877aca2a0def488e9bb
F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523
F autoconf/tea/pkgIndex.tcl.in 55aec3c6d7e9a1de9b8d2fdc9c27fd055da3ac3a51b572195e2ae7300bcfd3a2
@@ -38,7 +37,7 @@ F autoconf/tea/win/rules.vc 94a18c3e453535459b4a643983acca52fb8756e79055bd2ad4b0
F autoconf/tea/win/targets.vc 96a25a1fa6e9e9cfb348fd3760a5395b4ce8acafc8ed10f0412937ec200d5dbd
F autosetup/LICENSE 41a26aebdd2cd185d1e2b210f71b7ce234496979f6b35aef2cbf6b80cbed4ce4
F autosetup/README.autosetup a78ff8c4a3d2636a4268736672a74bf14a82f42687fcf0631a70c516075c031e
-F autosetup/README.md 1a02f5a94fd460eb7ffc8dea5d6f1657e38ddf8ffa2d6c5dce9a630b97021a69
+F autosetup/README.md b306314e8a87ccf873cb5b2a360c4a27bbf841df5b76f3acbd65322cff165476
F autosetup/autosetup df8b53928b1fe3c67db5bc77c8e1eb8160c1b6a26c370e9a06c68748f803b7e4 x
F autosetup/autosetup-config.guess dfa101c5e8220e864d5e9c72a85e87110df60260d36cb951ad0a85d6d9eaa463 x
F autosetup/autosetup-config.sub a38fb074d0dece01cf919e9fb534a26011608aa8fa606490864295328526cd73 x
@@ -48,19 +47,21 @@ F autosetup/cc-db.tcl 6e0ed90146197a5a05b245e649975c07c548e30926b218ca3e1d4dc034
F autosetup/cc-lib.tcl 493c5935b5dd3bf9bd4eca89b07c8b1b1a9356d61783035144e21795facf7360
F autosetup/cc-shared.tcl 4f024e94a47f427ba61de1739f6381ef0080210f9fae89112d5c1de1e5460d78
F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e45f
-F autosetup/jimsh0.c d40e381ea4526a067590e7b91bd4b2efa6d4980d286f908054c647b3df4aee14
+F autosetup/jimsh0.c 6573f6bc6ff204de0139692648d7037ca0b6c067bac83a7b4e087f20a86866a4
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
-F autosetup/proj.tcl 2e817159b997077cb79bd871f6255276b787558f386dfc0830b0f825f6a53767
+F autosetup/proj.tcl cef1e0aa0f2dee2042af66f28c97a9445f84d55d858ba9db4f6116846a1a325f
+F autosetup/sqlite-config.tcl 62fd6e8782ecfb9f8e54cf2860e590ce9d8692218f03cfa8b25e87ff6b1d0b9b
F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9
F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
-F doc/compile-for-unix.md 7d6a5770611ea0643de456b385581923dac7c0a7c3758825dda810d12fc3e5b2
-F doc/compile-for-windows.md 17e1491897a117ff0247531a61671b26d487bc1dad25c3894c04ad4fca936a7f
+F doc/compile-for-unix.md c9dce1ddd4bf0d25efccc5c63eb047e78c01ce06a6ff29c73e0a8af4a0f4adbc
+F doc/compile-for-windows.md 5141661e783c9ca9e3fd30e813345898712f5c311d71316f183db87038fa28a6
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/jsonb.md 5fab4b8613aa9153fbeb6259297bd4697988af8b3d23900deba588fa7841456b
F doc/lemon.html 8b266ff711d2ec7f867c3dca37634963f48a630329908cc282beebfa8c708706
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
+F doc/tcl-extension-testing.md 864875c3b672db79e7d42348dd726f9a4fbd852b1d8e5efcf09fe3d1ff6bf2a2
F doc/testrunner.md 15583cf8c7d8a1c3378fd5d4319ca769a14c4d950a5df9b015d01d5be290dc69
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
F doc/vdbesort-memory.md 4da2639c14cd24a31e0af694b1a8dd37eaf277aff3867e9a8cc14046bc49df56
@@ -77,16 +78,16 @@ F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c 9f8ce82bbf4ec0636e6170e58f17b04817fa4c39b2d5126ac06f005d485f6d5e
+F ext/fts3/fts3.c b840ee915a6fb36571e3fe3c096e8a481a4a9cd8a35199a1b976b132b9f84ad3
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h 968f7d7cae541a6926146e9fd3fb2b2ccbd3845b7890a8ed03de0c06ac776682
+F ext/fts3/fts3Int.h 2fe7c76dfd7d46dff964d17d3f4c53bca2116cf5d6252552ebbc22e38afdf4e0
F ext/fts3/fts3_aux.c 7eab82a9cf0830f6551ba3abfdbe73ed39e322a4d3940ee82fbf723674ecd9f3
F ext/fts3/fts3_expr.c 365849a2a1185e19028a9db2d9f1ea63efe909a3a6aca7ec86fc26a13a60bd58
F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
F ext/fts3/fts3_icu.c 305ce7fb6036484085b5556a9c8e62acdc7763f0f4cdf5fd538212a9f3720116
F ext/fts3/fts3_porter.c e19807ce0ae31c1c6e9898e89ecc93183d7ec224ea101af039722a4f49e5f2b8
-F ext/fts3/fts3_snippet.c c38117a2e4dcc9485a170a57a6134423955247b230fef7073c46fa9c51239540
+F ext/fts3/fts3_snippet.c 7a3d5e2cefbb1cb51fb9c65458670cc269647ede18e1ffd57b513f9b4ec10c3e
F ext/fts3/fts3_term.c 6a96027ad364001432545fe43322b6af04ed28bb5619ec51af1f59d0710d6d69
F ext/fts3/fts3_test.c 7a9cb3d61774134211bf4bfdf1adcb581a1a0377f2d050a121ae7ab44baef0e3
F ext/fts3/fts3_tokenize_vtab.c 7fd9ef364f257b97218b9c331f2378e307375c592f70fd541f714e747d944962
@@ -111,9 +112,9 @@ F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70
F ext/fts5/fts5_config.c e7d8dd062b44a66cd77e5a0f74f23a2354cd1f3f8575afb967b2773c3384f7f8
F ext/fts5/fts5_expr.c 69b8d976058512c07dfe86e229521b7a871768157bd1607cedf1a5038dfd72c9
F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1
-F ext/fts5/fts5_index.c cef6791bd9f9db4305494292d6dd5d24a7379aabf370a4d6b559e16b740fa88e
-F ext/fts5/fts5_main.c 72527efa1d634054b93a21eafe854763cbc5c270e8a4ab99bbb589557b818482
-F ext/fts5/fts5_storage.c 337b05e4c66fc822d031e264d65bde807ec2fab08665ca2cc8aaf9c5fa06792c
+F ext/fts5/fts5_index.c f1eec0931548b529ddd7ebd274eaef37de7461fe2b0ebdc9818f37324bdf9494
+F ext/fts5/fts5_main.c 9a1daef7247f9b8a50b4159323e340efa6b0e4bea4fcd83580480f94d4f2c888
+F ext/fts5/fts5_storage.c 1ad05dab4830a4e2eaf2900bb143477f93bc17437093582f36f4b818809e88d8
F ext/fts5/fts5_tcl.c 7fb5a3d3404099075aaa2457307cb459bbc257c0de3dbd52b1e80a5b503e0329
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
@@ -146,7 +147,7 @@ F ext/fts5/test/fts5bigpl.test 8f09858aab866c33593560e6480b2b6975ae7ff29ca32ad7b
F ext/fts5/test/fts5bigtok.test 541119e616c637caea925a8c028c37c2c29e94383e00aa2f9198d530724b6e36
F ext/fts5/test/fts5blob.test 9644a5f917306690e08c5f89a470a3f2489376eaa52026eeca3209d149d6af74
F ext/fts5/test/fts5cat.test bf67dd335f964482ee658287521b81e2b88697b45eb7f73933e15f198ed447cb
-F ext/fts5/test/fts5circref.test f880dfd0d99f6fb73b88ccacb0927d18e833672fd906cc47d6b4e529419eaa62
+F ext/fts5/test/fts5circref.test 0918c69440a73fff429bc9797b07086fc74d018eb3abb1cf9738980390bb2713
F ext/fts5/test/fts5colset.test 544f4998cdbfe06a3123887fc0221612e8aa8192cdaff152872f1aadb10e6897
F ext/fts5/test/fts5columnsize.test 0af91d63985afdf663455d4b572b935238380140d74079eac362760866d3297b
F ext/fts5/test/fts5config.test 017daf10d2642496e97402baa0134de8b5b46b9c37e53c229cd9ab711d21522c
@@ -160,9 +161,9 @@ F ext/fts5/test/fts5contentless4.test ec34dc69ef474ca9997dae6d91e072906e0e9a5a4b
F ext/fts5/test/fts5contentless5.test 38cd0392c730dc7090c550321ce3c24ba4c392bc97308b51a4180e9959dca7b5
F ext/fts5/test/fts5corrupt.test 6485f721b88ba355ca5d701e7ee87a4efa3ea578d8e6adb26f51ef956c8328bd
F ext/fts5/test/fts5corrupt2.test 335911e3f68b9625d850325f9e29a128db3f4276a8c9d4e32134580da8f924c4
-F ext/fts5/test/fts5corrupt3.test 4fc3bf129f1616bea00884a23fd9d7b0e46d01791d2b57fe8d68ac36e8d3ff7c
+F ext/fts5/test/fts5corrupt3.test 3420ad30bf9e9bbdbd43b3224c582431744899530a65b11b60ddacdf14200e19
F ext/fts5/test/fts5corrupt4.test dc08d19f5b8943e95a7778a7d8da592042504faf18dd93f68f7d7a0d7d7dd733
-F ext/fts5/test/fts5corrupt5.test 11b47126f5772cc37b67e3e8b2ed05895c4d07c05338bc07e4eea225bfe32c76
+F ext/fts5/test/fts5corrupt5.test bcf0801b0c991eadae3cb8e978e82b4bf01412cb4df41874a90d5aa279c7cc96
F ext/fts5/test/fts5corrupt6.test 2d72db743db7b5d9c9a6d0cfef24d799ed1aa5e8192b66c40e871a37ed9eed06
F ext/fts5/test/fts5corrupt7.test 4e830875c33b9ea3c4cf1ba71e692b63893cbb4faae8c69b1071889dc26e211c
F ext/fts5/test/fts5corrupt8.test b81d802e41631e98100f49a1aadeeffef860e30a62d6ed7d743c2797c477239e
@@ -190,7 +191,7 @@ F ext/fts5/test/fts5faultE.test 844586ce71dab4be85bb86880e87b624d089f851654cd22e
F ext/fts5/test/fts5faultF.test 4abef99f86e99d9f0c6460dd68c586a766b6b9f1f660ada55bf2e8266bd1bbc1
F ext/fts5/test/fts5faultG.test 0544411ffcb3e19b42866f757a8a5e0fb8fef3a62c06f61d14deebc571bb7ea9
F ext/fts5/test/fts5faultH.test 2b2b5b8cb1b3fd7679f488c06e22af44107fbc6137eaf45b3e771dc7b149312d
-F ext/fts5/test/fts5faultI.test 0706b307b208638554c9e65b4091e1c0dd8c92941535089a301df454ff2c56f4
+F ext/fts5/test/fts5faultI.test 9b33d664bccee4bbde0f275a48b2df3ea2f05d41f6d1d171aa2e844382cba621
F ext/fts5/test/fts5first.test bfd685b96905bf541d99d8644e0a7219d1d833455a08ab64e344071a613b6ba9
F ext/fts5/test/fts5full.test 97d263c1072f4a560929cca31e70f65d2ae232610e17e6affcf7e979df59547b
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
@@ -205,7 +206,7 @@ F ext/fts5/test/fts5locale.test 83ba7ee12628b540d3098f39c39c1de0c0440eddff8f7512
F ext/fts5/test/fts5matchinfo.test 877520582feb86bbfd95ab780099bcba4526f18ac75ee34979144cf86ba3a5a3
F ext/fts5/test/fts5merge.test 2654df0bcdb2d117c2d38b6aeb0168061be01c643f9e9194b36c43a2970e8082
F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2
-F ext/fts5/test/fts5misc.test 8c3cc771f773dc4bb4973620c51e7729e324ca2cc80eb8894f1c2c605e361f0b
+F ext/fts5/test/fts5misc.test f4dee7da898d605a6488c5b7afaace3158ed6bb9addff78faa1b37b402b77fb9
F ext/fts5/test/fts5multi.test a15bc91cdb717492e6e1b66fec1c356cb57386b980c7ba5af1915f97fe878581
F ext/fts5/test/fts5multiclient.test 5ff811c028d6108045ffef737f1e9f05028af2458e456c0937c1d1b8dea56d45
F ext/fts5/test/fts5near.test 33d60867581066e5db7016deb5d651628125d7ff4e0233a88175aa5b65874c74
@@ -230,7 +231,7 @@ F ext/fts5/test/fts5rank.test 47c1e8e5d84754ff18e012fdd629776088b5a15de41bdd2495
F ext/fts5/test/fts5rebuild.test 83e72d77636378833233fadc7cb7517a2fa446ea7d1f94dd526ba3e7e104b9f5
F ext/fts5/test/fts5restart.test 9af2084b8e065130037b95f05f3f220bb7973903a7701e2c5fb916dff7cf80c5
F ext/fts5/test/fts5rowid.test 8632829fec04996832a4cfb4f0bd89721ba65b7e398c1731741bdb63f070e1a3
-F ext/fts5/test/fts5savepoint.test 7f373184cf2d6c1c472d2bc732e1fce62211ffe023f13e381db0f5e4fd06e41d
+F ext/fts5/test/fts5savepoint.test 1447758d7900afe903cef08b4524c5331fb60c1126ae6fba7f4d8704268013c5
F ext/fts5/test/fts5secure.test a02f771742fb2b1b9bdcb4bf523bcf2d0aa1ff597831d40fe3e72aaa6d0ec40f
F ext/fts5/test/fts5secure2.test 2e961d7eef939f294c56b5d895cac7f1c3a60b934ee2cfd5e5e620bdf1ba6bbc
F ext/fts5/test/fts5secure3.test 6d066828d225b0dbe5db818d4d6165df7bb70210e68a577e858e8762400d5a23
@@ -263,7 +264,7 @@ F ext/fts5/test/fts5unindexed.test 168838d2c385e131120bbf5b516d2432a5fabc4caa225
F ext/fts5/test/fts5unindexed2.test 516236eceaac05ace322290a0d3705b4c4ffe4760d8eb9d014d9d27d56dfcc02
F ext/fts5/test/fts5update.test b8affd796e45c94a4d19ad5c26606ea06065a0f162a9562d9f005b5a80ccf0bc
F ext/fts5/test/fts5update2.test c5baa76799ac605ebb8e5e21035db2014b396cef25c903eb96ba39b1d6f9f046
-F ext/fts5/test/fts5version.test c22d163c17e60a99f022cbc52de5a48bb7f84deaa00fe15e9bc4c3aa1996204e
+F ext/fts5/test/fts5version.test 44ab35566267b7618c090443de2d9ad84f633df5d20bf72e9bad199ae5fced84
F ext/fts5/test/fts5vocab.test 2a2bdb60d0998fa3124d541b6d30b019504918dc43a6584645b63a24be72f992
F ext/fts5/test/fts5vocab2.test bbba149c254375d00055930c1a501c9a51e80b0d20bf7b98f3e9fa3b03786373
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
@@ -399,15 +400,15 @@ F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f23
F ext/misc/amatch.c 5001711cbecdd57b288cb613386789f3034e5beb58fbe0c79f2b3d643ffd4e03
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
-F ext/misc/base64.c a71b131e50300c654a66c469a25b62874481f3d1cb3beb56aca9a68edd812e0d
-F ext/misc/base85.c 073054111988db593ef5fdb87ab8c459df1ea0c3aaaddf0f5bfa3d72b7e6280a
+F ext/misc/base64.c 73c31eb325c71bae2e27276565e3f674fc095d8b0d7a651becb3b241a4d2fa57
+F ext/misc/base85.c a70c885c5c9350261ea6e7b166038eab21a09cf4fceae856ce41fae9c2213b60
F ext/misc/basexx.c 89ad6b76558efbceb627afd5e2ef1d84b2e96d9aaf9b7ecb20e3d00b51be6fcf
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
F ext/misc/btreeinfo.c cb952620eedf5c0b7625b678f0f08e54d2ec0011d4e50efda5ebdc97f3df7d04
F ext/misc/carray.c 34fac63770971611c5285de0a9f0ac67d504eaf66be891f637add9290f1c76a5
F ext/misc/carray.h 503209952ccf2431c7fd899ebb92bf46bf7635b38aace42ec8aa1b8d7b6e98a5
F ext/misc/cksumvfs.c 3a7931dd30667be6348af919f3f9e6188dfd7646b42af8e399a499b327f5bd63
-F ext/misc/closure.c 0e04f52d93e678dd6f950f195f365992edf3c380df246f3d80425cba4c13891e
+F ext/misc/closure.c 87e0967772e0087e709887ce7ca9cf13aa32d2096e33b5d3382c8b8d477c6cb1
F ext/misc/completion.c cb978c88d5577821323617a8ea775ce1b920e02dcdb593858f02044a4d008eea
F ext/misc/compress.c 2c79a74330e0e0ba6cb3f7397f8ba5af12d46377ef5d3ee075e12dd8a6ed57f0
F ext/misc/csv.c 575c2c05fba0a451586a4d42c2c81e711780c41e797126f198d8d9e0a308dcdb
@@ -415,7 +416,7 @@ F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f82
F ext/misc/decimal.c 172cf81a8634e6a0f0bedaf71a8372fee63348cf5a3c4e1b78bb233c35889fdc
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b
-F ext/misc/fileio.c e6b34db4df4b55b96265086c0010264e257b6eab1644e665697a6da587659403
+F ext/misc/fileio.c 07cf3109ec6452789e3a989a010234e2a17b599ce82ea29212c948572456abac
F ext/misc/fossildelta.c 8c026e086e406e2b69947f1856fa3b848fff5379962276430d10085b8756b05a
F ext/misc/fuzzer.c 8b28acf1a7e95d50e332bdd47e792ff27054ad99d3f9bc2e91273814d4b31a5a
F ext/misc/ieee754.c 62a90978204d2c956d5036eb89e548e736ca5fac0e965912867ddd7bb833256d
@@ -431,7 +432,7 @@ F ext/misc/percentile.c 82531c62cd015b9cdca95ad6bb10c3a907ceb570d21ebd4fb7d634c8
F ext/misc/prefixes.c 82645f79229877afab08c8b08ca1e7fa31921280906b90a61c294e4f540cd2a6
F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47cc06c
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
-F ext/misc/regexp.c 4bdd0045912f81c84908bd535ec5ad3b1c8540b4287c70ab84070963624047db
+F ext/misc/regexp.c 388e7f237307c7dfbfb8dde44e097946f6c437801d63f0d7ad63f3320d4e61cc
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
@@ -441,7 +442,7 @@ F ext/misc/shathree.c f3a778f27bf3e71b666a77f28e463a3b931c4dbe4219447e61bb678b4b
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F ext/misc/spellfix.c bcc42ef3fd29429bc01a83e751332b8d4690e65d45008449bdffe7656371487f
F ext/misc/sqlar.c a6175790482328171da47095f87608b48a476d4fac78d8a9ff18b03a2454f634
-F ext/misc/sqlite3_stdio.c 5657afb6ec81bef31790973528980af778e0e1388a93db780d33007336efe6e6
+F ext/misc/sqlite3_stdio.c 0fe5a45bd332b30aef2b68c64edbe69e31e9c42365b0fa79ce95a034bca6fbb0
F ext/misc/sqlite3_stdio.h f05eaf5e0258f0573910324a789a9586fc360a57678c57a6d63cfaa2245b6176
F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321
F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc
@@ -453,7 +454,7 @@ F ext/misc/urifuncs.c f71360d14fa9e7626b563f1f781c6148109462741c5235ac63ae0f8917
F ext/misc/uuid.c 5bb2264c1b64d163efa46509544fd7500cb8769cb7c16dd52052da8d961505cf
F ext/misc/vfslog.c 3932ab932eeb2601dbc4447cb14d445aaa9fbe43b863ef5f014401c3420afd20
F ext/misc/vfsstat.c a85df08654743922a19410d7b1e3111de41bb7cd07d20dd16eda4e2b808d269d
-F ext/misc/vfstrace.c 4d8b39570cbede1a05928c77e2142f8a744468443bf649cf86da3924e5e60fca
+F ext/misc/vfstrace.c a73386403c350b210dc788a2d23a0f5cc89c49b176109a66af11b5078c116331
F ext/misc/vtablog.c 1100250ce8782db37c833e3a9a5c9a3ecf1af5e15b8325572b82e6e0a138ffb5
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f65b4fc0668
@@ -575,14 +576,14 @@ F ext/rtree/visual01.txt e9c2564083bcd30ec51b07f881bffbf0e12b50a3f6fced0c222c5c1
F ext/session/changeset.c 7a1e6a14c7e92d36ca177e92e88b5281acd709f3b726298dc34ec0fb58869cb5
F ext/session/changesetfuzz.c 227076ab0ae4447d742c01ee88a564da6478bbf26b65108bf8fac9cd8b0b24aa
F ext/session/changesetfuzz1.test 15b629004e58d5ffcc852e6842a603775bb64b1ce51254831f3d12b113b616cd
-F ext/session/session1.test e94f764fbfb672147c0ef7026b195988133b371dc8cf9e52423eba6cad69717e
+F ext/session/session1.test cc7e58976c2cc6263fb7ef0c5125a98eafc2f213c75929f986768d2dbc224725
F ext/session/session2.test ee83bb973b9ce17ccce4db931cdcdae65eb40bbb22089b2fe6aa4f6be3b9303f
F ext/session/session3.test 2cc1629cfb880243aec1a7251145e07b78411d851b39b2aa1390704550db8e6a
F ext/session/session4.test 823f6f018fcbb8dacf61e2960f8b3b848d492b094f8b495eae1d9407d9ab7219
F ext/session/session5.test 716bc6fafd625ce60dfa62ae128971628c1a1169
F ext/session/session6.test 35279f2ec45448cd2e24a61688219dc6cf7871757716063acf4a8b5455e1e926
F ext/session/session8.test 326f3273abf9d5d2d7d559eee8f5994c4ea74a5d935562454605e6607ee29904
-F ext/session/session9.test 5409d90d8141881d08285ed1c2c0d8d10fb92069
+F ext/session/session9.test 4e3aff62d6b4294498ddbe309076de06f4fddffad4fe5f5a6c033358b01df083
F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f
F ext/session/sessionB.test c4fb7f8a688787111606e123a555f18ee04f65bb9f2a4bb2aa71d55ce4e6d02c
F ext/session/sessionC.test f8a5508bc059ae646e5ec9bdbca66ad24bc92fe99fda5790ac57e1f59fce2fdf
@@ -591,7 +592,8 @@ F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d
F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401
F ext/session/sessionG.test 3efe388282d641b65485b5462e67851002cd91a282dc95b685d085eb8efdad0a
F ext/session/sessionH.test 71bbff6b1abb2c4ac62b84dee53273c37e0b21e5fde3aed80929403e091ef859
-F ext/session/session_common.tcl e5598096425486b363718e2cda48ee85d660c96b4f8ea9d9d7a4c3ef514769da
+F ext/session/session_common.tcl a31f537a929a695a852d241c9434f2847cadf329856401921139fbb03a5a7697
+F ext/session/session_gen.test 942a0002df10da53c45b40b581cc3ed25e7ff42bda1e7ba497273dc2887aa8e6
F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3
F ext/session/sessionalter.test e852acb3d2357aac7d0b920a2109da758c4331bfdf85b41d39aa3a8c18914f65
F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee
@@ -605,7 +607,7 @@ F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576d
F ext/session/sessionfault3.test ce0b5d182133935c224d72507dbf1c5be1a1febf7e85d0b0fbd6d2f724b32b96
F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
-F ext/session/sessionnoact.test 2563dff62a2a80dc7c88002241b2fd1578c3e5438735e180fb7e941ebbc66214
+F ext/session/sessionnoact.test 4c7ae5c7d351cb5323bca62b6b095592ad24bd90a6713c178b62ab0063d23e19
F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7
F ext/session/sessionnoop2.test de4672dce88464396ec9f30ed08c6c01643a69c53ae540fadbbf6d30642d64e8
F ext/session/sessionrebase.test 702378bdcb5062f1106e74457beca8797d09c113a81768734a58b197b5b334e2
@@ -613,13 +615,13 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
-F ext/session/sqlite3session.c 3d0a7f0f7a1c946e01818c716a55a40ae30542a29a9045cb05daf7fb658cdafa
+F ext/session/sqlite3session.c 52a680dbb03c4734748b215d95987fb4d95ab23baaf053a01ac2626610963b58
F ext/session/sqlite3session.h 683ccbf16e2c2521661fc4c1cf918ce57002039efbcabcd8097fa4bca569104b
-F ext/session/test_session.c aa29abdcc9011ac02f4fa38e8ede226106eaeee7c3ea7d8b2b999a124e0c368c
+F ext/session/test_session.c 12e0a2c15fd60f92da4bb29c697c9177ff0c0dbcdc5129a54c47e999f147937a
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
-F ext/wasm/GNUmakefile 311aa0d5edc7006409962cc77cc26560d92f9be69c2c4302e8bbc68189fd02db
-F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
-F ext/wasm/README.md a8a2962c3aebdf8d2104a9102e336c5554e78fc6072746e5daf9c61514e7d193
+F ext/wasm/GNUmakefile 06e0556e9840fd3d8870997025c2507ace9ba7bf11195f770295fc7947dfc1b5
+F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
+F ext/wasm/README.md b89605f65661cf35bf034ff6d43e448cc169b8017fc105d498e33b81218b482c
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
F ext/wasm/SQLTester/SQLTester.mjs 66e1adc3d79467b68e3e40614fd42c1a577c7e219ec0985db966eded52a941e5
F ext/wasm/SQLTester/SQLTester.run.mjs 57f2adb33f43f2784abbf8026c1bfd049d8013af1998e7dcb8b50c89ffc332e0
@@ -629,24 +631,24 @@ F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core 2bcbbfe3b95c043ed6037e2708a2ee078
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras fe40d6d758646e38f8b15f709044951e10884214f5453d35502100179c388c13
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
-F ext/wasm/api/README.md 34fe11466f9c1d81b10a0469e1114e5f1c5a6365c73d80a1a6ca639a1a358b73
-F ext/wasm/api/extern-post-js.c-pp.js c4154a7f90c2d7e51fd6738273908152036c3457fdc0b6523f1be3ef51105aac
+F ext/wasm/api/README.md c64ec8e84449c069e0217706d9d7d31b3bd53627228b2ba0c3cddbdc2350ca66
+F ext/wasm/api/extern-post-js.c-pp.js 3fcd904f1204685dea84e5ae90d8b7e65a1dcebab1e838386d8328b74cce46c9
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
-F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1
-F ext/wasm/api/post-js-header.js 04dc12c3edd666b64a1b4ef3b6690c88dcc653f26451fd4734472d8e29c1c122
+F ext/wasm/api/post-js-footer.js 365405929f41ca0e6d389ed8a8da3f3c93e11d3ef43a90ae151e37fa9f75bf41
+F ext/wasm/api/post-js-header.js 53740d824e5d9027eb1e6fd59e216abbd2136740ce260ea5f0699ff2acb0a701
F ext/wasm/api/pre-js.c-pp.js a614a2c82b12c4d96d8e3ba77330329efc53c4d56a8a7e60ade900f341866cfb
-F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
-F ext/wasm/api/sqlite3-api-glue.c-pp.js fb6dbfe692cc23000a65a4cd95a1a47ed5eb592dc9d8b55363b3c2952a787244
+F ext/wasm/api/sqlite3-api-cleanup.js 3ac1786e461ada63033143be8c3b00b26b939540661f3e839515bb92f2e35359
+F ext/wasm/api/sqlite3-api-glue.c-pp.js 5c0209e6a28164b4c2c1a34b0bb4aee3b7b1a264988d7e71fac08b8ede5b7ae3
F ext/wasm/api/sqlite3-api-oo1.c-pp.js f3a8e2004c6625d17946c11f2fb32008be78bc5207bf746fc77d59848813225f
-F ext/wasm/api/sqlite3-api-prologue.js 6f1257e04885632ed9f44d43aba200b86e0bc16709ffdba29abbbeb1bc8e8b76
-F ext/wasm/api/sqlite3-api-worker1.c-pp.js 5cc22a3c0d52828cb32aad8691488719f47d27567e63e8bc8b832d74371c352d
+F ext/wasm/api/sqlite3-api-prologue.js 9e7d89a2c0d02b8b2052a62757a89f1e7e4dbcc0d9cd3f2dafa896786954dad2
+F ext/wasm/api/sqlite3-api-worker1.c-pp.js f646a65257973b8c4481f8a6a216370b85644f23e64b126e7ae113570587c0ab
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 3774befd97cd1a5e2895c8225a894aad946848c6d9b4028acc988b5d123475af
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js bb5e96cd0fd6e1e54538256433f1c60a4e3095063c4d1a79a8a022fc59be9571
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 9b86ca2d8276cf919fbc9ba2a10e9786033b64f92c2db844d951804dee6c4b4e
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js e809739d71e8b35dfe1b55d24d91f02d04239e6aef7ca1ea92a15a29e704f616
-F ext/wasm/api/sqlite3-wasm.c 83f5e9f998e9fa4261eb84e9f092210e3ffe03895119f5ded0429eb34ab9d2be
+F ext/wasm/api/sqlite3-wasm.c 6f9d8529072d072359cd22dc5dfb0572c524684686569cfbd0f9640d7619fc10
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 46f303ba8ddd1b2f0a391798837beddfa72e8c897038c8047eda49ce7d5ed46b
F ext/wasm/api/sqlite3-worker1.c-pp.js 5e8706c2c4af2a57fbcdc02f4e7ef79869971bc21bb8ede777687786ce1c92d5
F ext/wasm/batch-runner-sahpool.html e9a38fdeb36a13eac7b50241dfe7ae066fe3f51f5c0b0151e7baee5fce0d07a7
@@ -657,27 +659,28 @@ F ext/wasm/c-pp.c 6d131069644964223305582a80973477fa8b06b57306781690d7874ebd3a4f
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
-F ext/wasm/common/whwasmutil.js 6181f8cd958700f3723350bd4d76c7cc797db331a9aa14b25b42d121f12d6fee
+F ext/wasm/common/whwasmutil.js c2e459286c1ada789cda6b17761bb1eea6034be572468eed78c049354f1051ba
+F ext/wasm/config.make.in 4bc43443f768a61efd43cf995a5e618f58ac9afc0936706014193537d82c41cb
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
F ext/wasm/demo-123.js c7b3cca50c55841c381a9ca4f9396e5bbdc6114273d0b10a43e378e32e7be5bf
F ext/wasm/demo-jsstorage.html 409c4be4af5f207fb2877160724b91b33ea36a3cd8c204e8da1acb828ffe588e
F ext/wasm/demo-jsstorage.js 44e3ae7ec2483b6c511384c3c290beb6f305c721186bcf5398ca4e00004a06b8
F ext/wasm/demo-worker1-promiser.c-pp.html 635cf90685805e21772a5f7a35d1ace80f98a9ef7c42ff04d7a125ddca7e5db8
-F ext/wasm/demo-worker1-promiser.c-pp.js fcc628cb42fcfaf07d250477801de1e6deb1e319d003976612a0db8d76b9fccc
+F ext/wasm/demo-worker1-promiser.c-pp.js af168699d3cab1c27ad2364ebe06cd49db300bdbf404e23b00d5742ed52816ba
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
-F ext/wasm/demo-worker1.js 836bece8615b17b1b572584f7b15912236a5947fe8c68b98d2737d7e287447ef
-F ext/wasm/dist.make 653e212c1e84aa3be168d62a10616ccea45ee9585b0192745d2706707a5248ce
+F ext/wasm/demo-worker1.js 08720227e98fa5b44761cf6e219269cee3e9dd0421d8d91459535da776950314
+F ext/wasm/dist.make 92ef4ffe33022a50f92d602acabad10bd8dd91759f3eb7df27fc6d7d37072b96
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
F ext/wasm/fiddle.make d4969f0322a582c57a22ce3541f10a5b09a609d14eab32891f613f43b3c14d8b
F ext/wasm/fiddle/fiddle-worker.js 850e66fce39b89d59e161d1abac43a181a4caa89ddeea162765d660277cd84ce
F ext/wasm/fiddle/fiddle.js b444a5646a9aac9f3fc06c53d78af5e1912eb235d69a8e6010723e4eb0e9d4a1
F ext/wasm/fiddle/index.html c79b1741cbeba78f88af0a84cf5ec7de87a909a6a8d10a369b1f4824c66c2088
-F ext/wasm/index-dist.html 564b5ec5669676482c5a25dea9e721d8eafed426ecb155f93d29aeff8507511f
+F ext/wasm/index-dist.html 56132399702b15d70c474c3f1952541e25cb0922942868f70daf188f024b3730
F ext/wasm/index.html e4bbffdb3d40eff12b3f9c7abedef91787e2935620b7f8d40f2c774b80ad8fa9
F ext/wasm/jaccwabyt/jaccwabyt.js 1264710db3cfbcb6887d95665b7aeba60c1126eaef789ca4cf1a4a17d5bc7f54
F ext/wasm/jaccwabyt/jaccwabyt.md 59a20df389abcc3606eb4eaea7fb7ba14504beb3e345dbea9b99a0618ba3bec8
-F ext/wasm/mkwasmbuilds.c e3580b26bc393e4e4beb25f6349b999878782f3319b740469f64c2e772632e03
+F ext/wasm/mkwasmbuilds.c baf6636e139e2c1e3b56e8dc26073ec80f6d14ae1876b023985315f43ccf312b
F ext/wasm/module-symbols.html dc476b403369b26a1a23773e13b80f41b9a49f0825e81435fe3600a7cfbbe337
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
@@ -693,13 +696,13 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
-F ext/wasm/tester1.c-pp.js 228101c290003423f0bfb66a6ebbfc6904fa7b1b69466e700c135f74ee83d62a
+F ext/wasm/tester1.c-pp.js 05a0143c44a4114aad0ed40ce73c528febc3e0d6b69f48a51c895d7030015b74
F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
-F ext/wasm/wasmfs.make bc8bb227f35d5bd3863a7bd2233437c37472a0d81585979f058f9b9b503bef35
+F ext/wasm/wasmfs.make 68999f5bd8c489239592d59a420f8c627c99169bbd6fa16a404751f757b9f702
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
-F main.mk 1ec3c7a81198397b14bf75c9304f01e891a5d464797cd402d4f3781feadd3331
+F main.mk c85055d36c36c188cee94cabe2e252cd912d10d1a9d62af477e855533b9531b2
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
@@ -709,9 +712,9 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
F sqlite3.pc.in 0977c03a4da7c4204bd60e784a0efb8d51a190448aba78a4e973fe7192bdaf03
-F src/alter.c aa93e37e4a36a0525bbb2a2aeda20d2018f0aa995542c7dc658e031375e3f532
-F src/analyze.c 9a8b67239d899ac12289db5db3f5bfe7f7a0ad1277f80f87ead1d048085876eb
-F src/attach.c f541c1fb59e56a1c8ba6b023d5e1844448b499fac669d2cbca18be7b6e7d4998
+F src/alter.c 1751e231d8385067fa0d0145f0d461a092db6bd3d7edbfc3172db625aceccd9a
+F src/analyze.c 0823d2edb3ce564157e9d62714cc729027933209b712e95fbabb23e47fff0aec
+F src/attach.c 28fe81ea9eddae3188a7454e47994328179cfa9b0b197bed8c7e35ec14b941c9
F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
@@ -719,28 +722,28 @@ F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
F src/btree.c 63ca6b647342e8cef643863cd0962a542f133e1069460725ba4461dcda92b03c
F src/btree.h 18e5e7b2124c23426a283523e5f31a4bff029131b795bb82391f9d2f3136fc50
F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6
-F src/build.c c6b09342d870a509529244ed8e19b4175a261f2e3163c199241d69e1d8a57607
-F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
+F src/build.c 602fc45ea6301a3dc03ec20a9f9b294c492b7e1766ae96651f2ba8044dc445a6
+F src/callback.c acae8c8dddda41ee85cfdf19b926eefe830f371069f8aadca3aa39adf5b1c859
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c d35723024b963edce9c0fad5b3303e8bb9266083784844baed10a6dedfe26f3b
-F src/date.c 89ce1ff20512a7fa5070ba6e7dd5c171148ca7d580955795bf97c79c2456144a
-F src/dbpage.c b1aeb47c1004f26c39c6800f0045b8d729d232aca24f6aa430c491b83003d033
+F src/date.c 842c08ac143a56a627b05ac51d68624f2b7b03e3b4cba596205e735eed64ee57
+F src/dbpage.c 2e677acb658a29965e55398bbc61161cb7819da538057c8032adac7ab8e4a8c0
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
-F src/expr.c 3329173aacc6c37da3971b6253827799b32e301673be00126df8271bf018e15f
+F src/expr.c ca943270395374afc65256ce86cdb152a22fa6ff146895175833b89ba870e117
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
-F src/func.c e6e997efb9ffaf8b07842e745159695669fdfa020f03635a2f774adab8b0f4af
+F src/func.c b2fb33139972d7d65640b27ea962a49f1616265428001090cab39fcf270228e1
F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b
-F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
-F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
+F src/hash.c 73934a7f7ab1cb110614a9388cb516893b0cf5b7b69e4fd1a0780ac4ce166be7
+F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
-F src/insert.c f8d1a0f8ee258411009c6b7f2d93170e351bd19f5ad89d57e1180644297cbe70
-F src/json.c 68a98c020c22127f2d65f08855f7fc7460ff352a6ce0b543d8931dde83319c22
+F src/insert.c 05e04ef637cbc0dccb9a5c5d188a5a2608891e554c8ec17c7a71afe2cf896a06
+F src/json.c 2663a0c7e574cb928de944720dcdcc11c931877d877549b8f1258a4002efd6f7
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
-F src/main.c ad702f1ad48cd82f700b3e1b28b523154488874655cbd39bc9336d0bb2e8f728
+F src/main.c 7ace1b61344be773705132dc1fb607940ddd886170fd6613c004631d8c2dc470
F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -761,12 +764,12 @@ 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 e15305b49518d2e2cd405d14ede027a7ca52679d4d31b25635fb88d545211feb
+F src/os_unix.c 49ee8571f42e1bfddc7d56829f68bce86f00c3000240ffbed0f49170631136ae
F src/os_win.c 48c536ebd662a4b39623fffba41d95234854ddfbea4865d03fef1f51c29da187
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c 2fdd489447aa6bb0f672973bacb801ced92225ca9a1c874ed9b856d2741dc54e
+F src/pager.c 3a1c4e7f69af482e33c8cba8a75afe0dda0ea6391240adac22b040ce1bdeef44
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
-F src/parse.y dcf45a81b61223ac93e61fdfe9b22d635dd371c446e8222634d90aa37e25e5f6
+F src/parse.y f84673f1454e2bcf517623d4346e67fb2d73e57826ea103681ad5848238f6029
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 49516ad7718a3626f28f710fa7448ef1fce3c07fd169acbb4817341950264319
@@ -775,20 +778,20 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c 1832be043fce7d489959aae6f994c452d023914714c4d5457beaed51c0f3d126
F src/printf.c 96f7f8baeedc7639da94e4e7a4a2c200e2537c4eec9e5e1c2ffc821f40eb3105
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
-F src/resolve.c c8a5372b97b2a2e972a280676f06ddb5b74e885d3b1f5ce383f839907b57ef68
+F src/resolve.c 626c24b258b111f75c22107aa5614ad89810df3026f5ca071116d3fe75925c75
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c 83e88fbb36f89b6703b348777491619554f0fd6f917c9fdf51e4c2e9cda6c04e
-F src/shell.c.in ee54de10e9bd5572f689a6bc0c8e6fa58a8870e1670978ded44412d2715fd908
-F src/sqlite.h.in 78a34c8c6564ae43b16322bac5e843167ef97f5084c9c663684f67576ddcbcb2
+F src/select.c 57893cc8b099f231f7ed5b84faff14841f2aabb4776e32e17fae00aeae0a8993
+F src/shell.c.in b377a59822f207106424f08aead37e78b609222e98f86f04cc8a03563ccf3237
+F src/sqlite.h.in 5ad5afb4262e139f6214bce5af6d08cd3fd604137c0947b6018dcbc6fbfd3f06
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h b6e49765628a6b74e2c47a4e19f5245fa226ef32c6abc1b82849af8107a6b042
+F src/sqliteInt.h 6fa99f64ab558dd8e3ae44a8e67f78f5058bd452b5df959c44b00c9b74140675
F src/sqliteLimit.h 1bbdbf72bd0411d003267ffebc59a262f061df5653027a75627d03f48ca30523
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c 90441d3cc16f966a23499d9096a3d2d971e5e8fddb4d1413b096b79c2b2cff07
+F src/tclsqlite.c 5c1e367e26711044730c93d4b81312170918a8d1fe811f45be740ab48f7de8c1
F src/tclsqlite.h 65e2c761446e1c9fa0342b7d2612a703483643c8b6a316d12a65b745a4727395
-F src/test1.c 1be101915405d022cef33bf7a13bdc0753015785de409a028b393fd4b8c7fc9b
+F src/test1.c ba7b93478a6a7a3f48ec5507f28bc662636ac5d9f9791700d3648a8e788f0bb2
F src/test2.c 7ebc518e6735939d8979273a6f7b1d9b5702babf059f6ad62499f7f60a9eb9a3
F src/test3.c e7573aa0f78ee4e070a4bc8c3493941c1aa64d5c66d4825c74c0f055451f432b
F src/test4.c 13e57ae7ec7a959ee180970aef09deed141252fe9bb07c61054f0dfa4f1dfd5d
@@ -809,11 +812,11 @@ F src/test_fs.c c411c40baba679536fc34e2679349f59d8225570aed3488b5b3ef1908525a3d5
F src/test_func.c 858d4dddb7acf88222ebcba7cffb585f6dde83e4a15b838c0d05ccdf8d5219b9
F src/test_hexio.c 7449504e4bde876ba91b202617a9228c7c8c2e7bd8b957302f3803ac0e9e353c
F src/test_init.c 17313332d58e90defc527129d5eda4a08bd6b6e8de7207a231523c8d98fb445e
-F src/test_intarray.c e4216aadee9df2de7d1aee7e70f6b22c80ee79ece72a63d57105db74217639e5
+F src/test_intarray.c 3fcf8ca7bb5c8776ea83f6aa9b66f8df0d1f37a99207b0097c8486f9c15cedbf
F src/test_intarray.h 6c3534641108cd1bea517a8e117dcba237081310a29a4c35bd2190caa8972293
F src/test_journal.c a0b9709b2f12b1ec819eea8a1176f283bca6d688a6d4a502bd6fd79786f4e287
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
-F src/test_malloc.c a0295e022103b14a1bc5e0660cc2af7fbec05e0d029098782e326e50612e69d9
+F src/test_malloc.c 4954125ee89aa51d9f641d5cb272cc93ca4cb03dcc7c9c941d70210354c69567
F src/test_md5.c 811a45330c9391933360f998156a8907ee29909c828ab83ac05d329942cbea8f
F src/test_multiplex.c b99d7f43ec859e6b93a40aaa5455420b3ad133053cce3db739498d29ea30735f
F src/test_multiplex.h f0ff5b6f4462bfd46dac165d6375b9530d08089b7bcbe75e88e0926110db5363
@@ -838,33 +841,33 @@ F src/test_windirent.h da2e5b73c32d09905fbdd00f27cd802212a32a58ead882736fe4f5eb7
F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
-F src/tokenize.c fe17e03175cae35b6694d0f879e7bc3d1ddea2fd4ab148cba9bbd025b7a7bb12
-F src/treeview.c 921392561385e05ef5703f20a7a72f0a0a45c1fb749558d7467fae2c3f525006
-F src/trigger.c 247e2d712d5edc6021d52a169f6ac9a9c10d7144bc4ac7ea06c1ed2aa414659f
-F src/update.c 0e01aa6a3edf9ec112b33eb714b9016a81241497b1fb7c3e74332f4f71756508
+F src/tokenize.c 375a772e2342274f4bf73605a70633237da09deed00a9bf4c4816a56777ea7c9
+F src/treeview.c d85ce76e6d1498d781957c07cb234da6d77ce0ed2d196480d516f54dabc62279
+F src/trigger.c da3c25786870d8bf97cd46b493374c2375d1abaf20a9b0f5f8629a3f2f2ce383
+F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
F src/utf.c 8b29d9a5956569ea2700f869669b8ef67a9662ee5e724ff77ab3c387e27094ba
-F src/util.c e5f6a5eeaa26b69054a43bbd0048cfe3d2851f6961052b35aed8f695df922850
+F src/util.c 9ff6470dabcf943fd796d2da766c98bd328c8f6fe036a31e5b338e628603f989
F src/vacuum.c b763b6457bd058d2072ef9364832351fd8d11e8abf70cbb349657360f7d55c40
-F src/vdbe.c 8a6eb02823b424b273614bae41579392a5c495424592b60423dd2c443a583df0
-F src/vdbe.h 9676348d342bd04e21e384c63b57224171ce84fac77853357334ef94c4d33cf4
-F src/vdbeInt.h bf294a0c8fc4cc80779e74b04b8bd82c6e1197b3137cefe0b16cdf002fc7dfd6
-F src/vdbeapi.c 38c252a202d70b56cfb734460bc888ddbd581afec1a10cd4d6c894c9e0b5baea
-F src/vdbeaux.c f0706ad786b8a6c5bc7ea622f3916c2ba2b883abc872d0b4911c4f021945c0e5
-F src/vdbeblob.c 255be187436da38b01f276c02e6a08103489bbe2a7c6c21537b7aecbe0e1f797
-F src/vdbemem.c df568ef0187e4be2788c35174f6d9b8566ab9475f9aff2d73907ed05aa5684b2
+F src/vdbe.c b98d86de7f0e6c02fb14e0e1ae8feab6aa84669d389771a848e23f59eb70dcad
+F src/vdbe.h 3d26d5c7660c5c7bd33ffb0d8784615072d8b23c81f8110870efe2631136bc89
+F src/vdbeInt.h 078b1c15b26587b54c1c1879d0d2f4dec812b9de4c337fed9faf73fbcc3bf091
+F src/vdbeapi.c 82fe278a7c71b653235c6f9fb5de0b5de589908dfcb011ba2a782e8becf06f86
+F src/vdbeaux.c 541d3d232714455960eab4ed10b34cb48b4bcd565d7539ef31092f5e73648e6b
+F src/vdbeblob.c 9166b6eb7054e5da82e35255892fb1ed551355a4716452539e8e3ac14f25fbe3
+F src/vdbemem.c 4af21a948820259ced96e3d46d70f9af347afa2deb7cb60a8b3981d5748e4279
F src/vdbesort.c d0a3c7056c081703c8b6d91ad60f17da5e062a5c64bf568ed0fa1b5f4cae311f
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
-F src/vtab.c 316cd48e9320660db3047cd306cd056e4361180cebb4d0f10a39244e10c11422
+F src/vtab.c 828221bdbeaaa6d62126ee6d07fd4ec0d09dcaea846f87ad01944d8b7e548859
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 6da5a05c124bad1e530cf83bafa07d28afdda20c28b276de49948ef8295d9e84
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
-F src/where.c 9ad3dea8003a8913da6a4ca8322e2fe30773f46e88a0d4fbf9db13bdb999efa2
-F src/whereInt.h 1e36ec50392f7cc3d93d1152d4338064cd522b87156a0739388b7e273735f0ca
-F src/wherecode.c 0c3d3199a2b769a5e2bb70feb5003dc85b3d86842ecaf903a47f2b4205ca5dab
-F src/whereexpr.c 0f93a29cabd3a338d09a1f5c6770620a1ac51ec1157f3229502a7e7767c60b6f
+F src/where.c 09dc313e7223ca1217c39c7026b00f16ff449a8323511a762fcba7863a00f4cd
+F src/whereInt.h d20cddddb1d61b18d5cb1fcfa9b77fbeebbc4afe44d996e603452a23b3009ee1
+F src/wherecode.c 5baa06f0daae7d38aca1d4814030b82ad4f127fe6bad18f0644776a474f6088b
+F src/whereexpr.c 2415c8eee5ff89a8b709d7d83d71c1ff986cd720d0520057e1d8a5371339012a
F src/window.c 2bf01f9941a64fbcead61a0e3cb5db3fca5094b30d2ff0d23274c2a81d2e2385
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@@ -924,7 +927,7 @@ F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728cb39
-F test/autoindex1.test 714cac6e60beeb5a26ed346dd46505ba60b5a5597e9122c9ed3a55f89a922aa4
+F test/autoindex1.test 65931519206bbec71948b11e125af0656435a0937973fe5fed70d776a712911f
F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
F test/autoindex3.test ca502c8050166ac6107a7b4fe4e951f4d3270a23a958af02b14f1b962b83c4b6
F test/autoindex4.test 3c2105e9172920e26f950ba3c5823e4972190e022c1e6f260ba476b0af24c593
@@ -987,7 +990,7 @@ F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9
F test/capi2.test 4ee545824adc3eb33bf57ef89f77440b28188ec3da72e5425ff0fcdba32e8d5a
-F test/capi3.test 4892b5e53d2a6941edc9d204a0ab174dd66e8689282d9a15e4384561c3965945
+F test/capi3.test ab90c548969613315605c555a8623f6b56e00e28d451c46a17ef73683c422c70
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
F test/capi3c.test 31d3a6778f2d06f2d9222bd7660c41a516d1518a059b069e96ebbeadb5a490f7
F test/capi3d.test 8b778794af891b0dca3d900bd345fbc8ebd2aa2aae425a9dccdd10d5233dfbde
@@ -1066,7 +1069,7 @@ F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c47
F test/cursorhint.test 05cf0febe5c5f8a31f199401fd1c9322249e753950d55f26f9d5aca61408a270
F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
-F test/date.test c8ff835023f2107b57ce7a45c92265d51c98a23fc93231e998f12d850831aad6
+F test/date.test 8911c3d9fb0e496e92e0259697f431a00707222d2b3438ce1105d1790a3c0d51
F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1
F test/date3.test a1b77abf05c6772fe5ca2337cac1398892f2a41e62bce7e6be0f4a08a0e64ae5
F test/date4.test 75dc8401e8c0639a228cd26a6eaa4ff5ea8ccda912b9853d1c9462c476670e17
@@ -1076,8 +1079,8 @@ F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
F test/dbfuzz001.test 6c9a4622029d69dc38926f115864b055cb2f39badd25ec22cbfb130c8ba8e9c3
F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
F test/dbfuzz2.c 4b3c12de4d98b1b2d908ab03d217d4619e47c8b23d5e67f8a6f2b1bdee7cae23
-F test/dbpage.test fce29035c7566fd7835ec0f19422cb4b9c6944ce0e1b936ff8452443f92e887d
-F test/dbpagefault.test 35f06cfb2ef100a9b19d25754e8141b9cba9b7daabd4c60fa5af93fcce884435
+F test/dbpage.test 63fab1eb026bada121107e53436fa749bbf83281dc9dea17af422f7a5c0f289f
+F test/dbpagefault.test ea39de2ca86041a9c6df1135645180a76d0a8da93ac159e2fafe38e39636530b
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
F test/decimal.test ef731887b43ee32ef86e1c8fddb61a40789f988332c029c601dcf2c319277e9e
@@ -1152,7 +1155,7 @@ F test/fkey2.test 1063d65e5923c054cfb8f0555a92a3ae0fa8c067275a33ee1715bd856cdb30
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
F test/fkey5.test 6727452e163a427147e84e739da18713da553d79f9783559b04fdcd36d5c7421
-F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
+F test/fkey6.test ebd11efb00b9c70b57f4c6b6184445145c96e320329bd90a175036570c5b25ca
F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d031
F test/fkey8.test 51deda7f1a1448bca95875e4a6e1a3a75b4bd7215e924e845bd60de60e4d84bf
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
@@ -1274,7 +1277,7 @@ F test/fuzz3.test 70ba57260364b83e964707b9d4b5625284239768ab907dd387c740c0370ce3
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
-F test/fuzzcheck.c 89b71d92b150a532e945e489d6e0721a4b15353c9255e079c198ed2a1958018b
+F test/fuzzcheck.c 6fc952750a69168dd5fea38b9d35cb38475bfda15c8acfd156ac09cd03ddbd3e
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
@@ -1282,7 +1285,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
F test/fuzzdata6.db b8725a5f5cf7a3b7241a9038e57ca7e7cc8c3f4d86b44bd770617bda245ab2b0
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
-F test/fuzzdata8.db 4a53b6d077c6a5c23b609d8d3ac66996fa55ba3f8d02f9b6efdd0214a767a35a
+F test/fuzzdata8.db c6f9cb7d2b808fb10894afe53ef00f51e73e43baa7aabdba7e9af4713fc5b186
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
@@ -1304,7 +1307,7 @@ F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test bb767ec1cfd1730256f0a83219f0acda36bc251b63f8b8bb7d8c7cff17875a4f
F test/in5.test 4fd79c70dfa0681313e8cdca07f5ff0400bdc0e20f808a5c59eaef1e4b48082a
F test/in6.test f5f40d6816a8bb7c784424b58a10ac38efb76ab29127a2c17399e0cbeeda0e4b
-F test/in7.test 5050b648510d88bd27ff6b40991a45e1cc277c20e258162e81650e01069a56bb
+F test/in7.test d9efdee00b074a60c6343993b2eda78bc369ab080dad864513c73f8aca89d566
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
F test/incrblob2.test a494c9e848560039a23974b9119cfc2cf3ad3bd15cc2694ee6367ae537ef8f1f
F test/incrblob3.test 67621a04b3084113bf38ce03797d70eca012d9d8f948193b8f655df577b0da6f
@@ -1398,7 +1401,7 @@ F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/lemon-test01.y 70110eff607ab137ccc851edb2bc7e14a6d4f246b5d2d25f82a60b69d87a9ff2
F test/like.test b3ea2ba3558199aa8f25a42ddeb54772e234fab50868c9f066047acdbda8fc58
F test/like2.test d3be15fefee3e02fc88942a9b98f26c5339bbdef7783c90023c092c4955fe3d3
-F test/like3.test a76e5938fadbe6d32807284c796bafd869974a961057bc5fc5a28e06de98745c
+F test/like3.test b21284df226d6028feeb4dcc56ad9d32673d82c14a63f15f25471292c36491e7
F test/limit.test 350f5d03c29e7dff9a2cde016f84f8d368d40bcd02fa2b2a52fa10c4bf3cbfaf
F test/limit2.test 9409b033284642a859fafc95f29a5a6a557bd57c1f0d7c3f554bd64ed69df77e
F test/literal.test a65dca9fef86e51b8e45544268e37abbd4bb94ba35fd65f6fdcab2f288cd8f79
@@ -1532,7 +1535,7 @@ F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b76
F test/pragma.test 11cb9310c42f921918f7f563e3c0b6e70f9f9c3a6a1cf12af8fccb6c574f3882
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 92a46bbea12322dd94a404f49edcfbfc913a2c98115f0d030a7459bb4712ef31
-F test/pragma4.test 336b99c2a9fd35af3cc6da94f794b4cba09bbdb18f0ecbd3f734bb6bb8e1c15c
+F test/pragma4.test 396ef9bff1fb966d41721545ad4b12bfc26aae315f5fe51d9b917828d49e6f8e
F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d9102
F test/pragma6.test c5ec577ba087954b4dfa619a3cbe97b155b60a0af487527abe89b10fc17e6512
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
@@ -1676,7 +1679,9 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
-F test/speedtest1.c cc503febbb8559d541a67d7a33d3d7bb8a2c8cbbfc89eb336e2e2bd6ad6a63ee
+F test/speedtest.md ee958457ae1b729d9715ae33c0320600000bf1d9ddea1a88dcf79f56729d6fad
+F test/speedtest.tcl 926d1e168f4a14e6fb68c5dc174de743536b547f365264bd5bac533b3621a4a0 x
+F test/speedtest1.c 132cd5ba064f48910bb4b68337442b0ef419218c8de9e9855f66d98015286ddb
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
@@ -1684,7 +1689,7 @@ F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae
F test/sqldiff1.test 1b7ab4f312442c5cc6b3a5f299fa8ca051416d1dd173cb1126fd51bf64f2c3fb
F test/sqllimits1.test 408131e4975d61868711c83f101a56d4602313cc5cae88d3eee81c1da364fd89
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
-F test/starschema1.test a84205f97fe278a015ac39546c86b97228d22043af28f3a2ef809e8d5637ce1d
+F test/starschema1.test f5388cd32527ab18d3f98f9e3402ec780f6a186e04e0d9c8531d7568ee734e11
F test/startup.c 1beb5ca66fcc0fce95c3444db9d1674f90fc605499a574ae2434dcfc10d22805
F test/stat.test 123212a20ceb496893d5254a5f6c76442ce549fdc08d1702d8288a2bbaac8408
F test/statfault.test 064f43379e4992b5221b7d9ac887c313b3191f85cce605d78e416fc4045da64e
@@ -1724,7 +1729,7 @@ F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl 2f900e8c912fbbaf381e69a92258fa6023ad0b4c8907e426bebbb4585da23c61
F test/testrunner.tcl 90ed8b6c2b26dc1f6af08aeb04670a5df86172f3d9828d8af000f972afa50061 x
-F test/testrunner_data.tcl 1497914126bcf5749aa9b86268bd7636b027f7dcfac8746e7bcb89b97267a81c
+F test/testrunner_data.tcl f64589ddd05abc2be4d6ab7573fb1cebb27a1034a092d95da684187dd455cd41
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1888,7 +1893,7 @@ F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
F test/tpch01.test 4479008f85f6f8f25f7ab2cb305d665752b4727fa28a8df3d8e0ad46520c62ff
F test/trace.test a659a9862957f4789e37a92b3bf6d2caf5c86b02cdeefc41e850ae53acf6992a
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
-F test/trace3.test 4f418ed30d15d9d17dcf13a17f0bd99a92e3038e038798e35db7525f82f4c281
+F test/trace3.test 2deeac66359c9f007f0fc9fb6336994a5d68fc1a65129f322a9e9546fd537d0a
F test/trans.test 45f6f9ab6f66a7b5744f1caac06b558f95da62501916906cf55586a896f9f439
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
@@ -2023,7 +2028,7 @@ F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cf
F test/walseh1.test bae700eb99519b6d5cd3f893c04759accc5a59c391d4189fe4dd6995a533442b
F test/walsetlk.test 9c5b92f9a20252540fedf9ffa6ee3d1b8af08ea4b80d0144d9b88e6c0c1de80d
F test/walsetlk2.test 5ae8662a28c013e8df2ce975f9e3577a7f239aeb4622bb8d4d0ca8e16c0c132e
-F test/walsetlk3.test 520633cb23561e960d3100b23f9da692f0cce2ffd650d72e2d06163e6c2d228b
+F test/walsetlk3.test 7ac01cb6ca9640081fbb5c59170172b85fbaf9e7a8a1e678a38e21df5d55721e
F test/walshared.test 42e3808582504878af237ea02c42ca793e8a0efaa19df7df26ac573370dbc7a3
F test/walslow.test 0c51843836c9dcf40a5ac05aa781bfb977b396ee2c872d92bd48b79d5dd9aa23
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
@@ -2089,7 +2094,7 @@ F test/with2.test 181674a6cc86a601ca2ac052741cdfad5b529e07e870435d2f6cdb92d589ff
F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
-F test/with6.test 9ff3503c3ff7cd459dc4852a02aaefa998dccace53f4142a0eb726174ad5984a
+F test/with6.test 281e4861b5e517f6c3c2f08517a520c1e2ee7c11966545d3901f258a4fe8ef76
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
F test/without_rowid1.test a5210b8770dc4736bca4e74bc96588f43025ad03ad6a80f885afd36d9890e217
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
@@ -2111,7 +2116,7 @@ F tool/GetTclKit.bat d84033c6a93dfe735d247f48ba00292a1cc284dcf69963e5e672444e045
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
F tool/build-all-msvc.bat c817b716e0edeecaf265a6775b63e5f45c34a6544f1d4114a222701ed5ac79ab x
F tool/build-shell.sh 369c4b171cc877ad974fef691e4da782b4c1e99fe8f4361316c735f64d49280f
-F tool/buildtclext.tcl 5e1f1aa843e635c8b7480c7d1ec1f149a5e52136ae2fca1226304053a1a60587
+F tool/buildtclext.tcl 20726b6b73c7911baa8519a9467b4062104339a5ce57947819884525c56d79e3
F tool/cg_anno.tcl c1f875f5a4c9caca3d59937b16aff716f8b1883935f1b4c9ae23124705bc8099 x
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
F tool/cktclsh.sh 6075eef9c6b9ba4b38fef2ca2a66d25f2311bd3c610498d18a9b01f861629cca
@@ -2120,7 +2125,7 @@ F tool/custom.txt 24ed55e71c5edae0067ba159bbf09240d58b160331f7716e95816cd3aa0ba5
F tool/dbhash.c 5da0c61032d23d74f2ab84ffc5740f0e8abec94f2c45c0b4306be7eb3ae96df0
F tool/dbtotxt.c ca48d34eaca6d6b6e4bd6a7be2b72caf34475869054240244c60fa7e69a518d6
F tool/dbtotxt.md c9a57af8739957ef36d2cfad5c4b1443ff3688ed33e4901ee200c8b651f43f3c
-F tool/emcc.sh.in 1f3226166bad1765c0bf42fac3d29037704c2078eb22562f9ddfbe73bff023b0
+F tool/emcc.sh.in 41a049468c8155433e37e656ba5bae063a000768b1d627025f277732c4e7c4a4
F tool/enlargedb.c 3e8b2612b985cfa7e3e8800031ee191b43ae80de96abb5abbd5eada62651ee21
F tool/extract-sqlite3h.tcl 069ceab0cee26cba99952bfa08c0b23e35941c837acabe143f0c355d96c9e2eb x
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
@@ -2140,7 +2145,8 @@ F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c c34e5944318415de513d29a6098df247a9618c96d83c38d4abd88641fe46e669
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176
-F tool/mkautoconfamal.sh cbdcf993fa83dccbef7fb77b39cdeb31ef9f77d9d88c9e343b58d35ca3898a6a
+F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f005910876a
+F tool/mkautoconfamal.sh 14d2144043c6455958012f92324f4ce7c90a261b5daa2f2c7509498468475f8d
F tool/mkccode.tcl 210159febe0ef0ecbc53c79833500663ceaba0115b2b374405818dc835b5f84b x
F tool/mkctimec.tcl ef6a67ec82e5b6fc19152a4c79f237227b18bf67ff16d155bac7adb94355d9cf x
F tool/mkkeywordhash.c 6b0be901c47f9ad42215fc995eb2f4384ac49213b1fba395102ec3e999acf559
@@ -2149,18 +2155,19 @@ F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61
F tool/mkopcodeh.tcl 2b4e6967a670ef21bf53a164964c35c6163277d002a4c6f56fa231d68c88d023
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
F tool/mkpragmatab.tcl 32e359ccb21011958a821955254bd7a5fa7915d01a8c16fed91ffc8b40cb4adf
-F tool/mkshellc.tcl 2bc29c201933ae72a16a79070fe80aded80c24ea487ecd2f8df20c2973c87bfc
+F tool/mkshellc.tcl 9ce74de0fa904a2c56a96f8d8b5261246bacb0eaa8d7e184f9e18ff94145ebbc
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
-F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
-F tool/mksqlite3c.tcl 9e88a30981280e33489fe4782f4ab1e5349ba1866603fba7f1a948d5599b9124
-F tool/mksqlite3h.tcl 7a4648fef5efb33308d575c7775eb242855d71d5bf89065df3f006b9a634a0a1
+F tool/mksqlite3c-noext.tcl 351c55256213154cabb051a3c870ef9f4487de905015141ae50dc7578a901b84
+F tool/mksqlite3c.tcl ba13086555b3cb835eba5e47a9250300ab85304d23fd1081abd3f29d8ab71a2b
+F tool/mksqlite3h.tcl b05b85c32295bad3fe64807729693d1f19faed3c464c5faac6c53bb6b972ac2f
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
+F tool/mksrczip.tcl 81efd9974dbb36005383f2cd655520057a2ae5aa85ac2441a80c7c28f803ac52
F tool/mktoolzip.tcl 34b4e92be544f820e2cc26f143f7d5aec511e826ec394cc82969a5dcf7c7a27c
F tool/mkvsix.tcl 67b40996a50f985a573278eea32fc5a5eb6110bdf14d33f1d8086e48c69e540a
F tool/offsets.c 8ed2b344d33f06e71366a9b93ccedaa38c096cc1dbd4c3c26ad08c6115285845
F tool/omittest-msvc.tcl d6b8f501ac1d7798c4126065030f89812379012cad98a1735d6d7221492abc08
-F tool/omittest.tcl 5ca5e4e01716d5f35b48b00fd351d929f01fbb98169a5a3cd00baf3d2e2019a9
+F tool/omittest.tcl bec70ef0e16255c8d9eb06ecd7edf823c07a60a836186cdbce3528fb34b67995
F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a
F tool/pagesig.c f98909b4168d9cac11a2de7f031adea0e2f3131faa7515a72807c03ec58eafeb
F tool/replace.tcl 511c61acfe563dfb58675efb4628bb158a13d48ff8322123ac447e9d25a82d9a
@@ -2182,7 +2189,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d40618 x
-F tool/split-sqlite3c.tcl 5aa60643afca558bc732b1444ae81a522326f91e1dc5665b369c54f09e20de60
+F tool/split-sqlite3c.tcl 07e18a1d8cc3f6b3a4a1f3528e63c9b29a5c8a7bca0b8d394b231da464ce1247
F tool/sqldiff.c 2a0987d183027c795ced13d6749061c1d2f38e24eddb428f56fa64c3a8f51e4b
F tool/sqlite3_analyzer.c.in fc7735c499d226a49d843d8209b2543e4e5229eeb71a674c331323a2217b65b4
F tool/sqlite3_rsync.c 9a1cca2ab1271c59b37a6493c15dc1bcd0ab9149197a9125926bc08dd26b83fb
@@ -2192,7 +2199,7 @@ F tool/src-verify.c d00f93263aa2fa6ba0cba0106d95458e6effb94fdb5fc634f56834f90c05
F tool/srcck1.c 371de5363b70154012955544f86fdee8f6e5326f
F tool/srctree-check.tcl 1f1f505835a4beca64c1751a7ebec5c41a1ddf22b1e80481345b95059eef6583
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
-F tool/stripccomments.c 20b8aabc4694d0d4af5566e42da1f1a03aff057689370326e9269a9ddcffdc37
+F tool/stripccomments.c dfe9cc03cf87728ac9836be30763f8aa52b82caca0780b3d3f3572e4643b01d3
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
F tool/symbols.sh 1612bd947750e21e7b47befad5f6b3825b06cce0705441f903bf35ced65ae9b9
F tool/tclConfigShToAutoDef.sh 44ec55046d86a3febb2cb3e099399b41794e80e9cd138eee7b9b016f819e882b x
@@ -2204,8 +2211,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 7eb5accb7cf937fc967dcd86da0af813fb18a2697348bd231fbefd3c09b930ab
-R a7261f9e35c03d513b32b9d4fcb3d611
+P d2d6a000fb9bf8097e0ce9979685408d183be3ab785ceeb11ec1f97a81a83e41 75535f2355b3b2e83dd57f4c30340af98c8dbcfe6ff1e9be17d23bd30d7d766c
+R 4f8d4a49a69f37717318dd9062d1384e
U dan
-Z c73a12f9f64486e78d8e69c08a89db7b
+Z 6f5c2c68e6ed575542ad7a68cf45ae3a
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 27fe52162..315c9000b 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-d2d6a000fb9bf8097e0ce9979685408d183be3ab785ceeb11ec1f97a81a83e41
+e5ec5bb9f4dc3e02db7ab0e49686f47617af75d3f7d4ab23288a1aea4a693e59
diff --git a/src/alter.c b/src/alter.c
index ff2075758..5f706b513 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -632,10 +632,8 @@ void sqlite3AlterRenameColumn(
** altered. Set iCol to be the index of the column being renamed */
zOld = sqlite3NameFromToken(db, pOld);
if( !zOld ) goto exit_rename_column;
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break;
- }
- if( iCol==pTab->nCol ){
+ iCol = sqlite3ColumnIndex(pTab, zOld);
+ if( iCol<0 ){
sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld);
goto exit_rename_column;
}
diff --git a/src/analyze.c b/src/analyze.c
index 9213c202b..799d43924 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -215,7 +215,8 @@ static void openStatTable(
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
);
- aRoot[i] = (u32)pParse->regRoot;
+ assert( pParse->isCreate || pParse->nErr );
+ aRoot[i] = (u32)pParse->u1.cr.regRoot;
aCreateTbl[i] = OPFLAG_P2ISREG;
}
}else{
diff --git a/src/attach.c b/src/attach.c
index 3ade237b5..0812040de 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -175,6 +175,12 @@ static void attachFunc(
sqlite3_free(zErr);
return;
}
+ if( (db->flags & SQLITE_AttachWrite)==0 ){
+ flags &= ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE);
+ flags |= SQLITE_OPEN_READONLY;
+ }else if( (db->flags & SQLITE_AttachCreate)==0 ){
+ flags &= ~SQLITE_OPEN_CREATE;
+ }
assert( pVfs );
flags |= SQLITE_OPEN_MAIN_DB;
rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
diff --git a/src/build.c b/src/build.c
index a5deb54fc..8f64d5ec3 100644
--- a/src/build.c
+++ b/src/build.c
@@ -168,10 +168,12 @@ void sqlite3FinishCoding(Parse *pParse){
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
if( v ){
if( pParse->bReturning ){
- Returning *pReturning = pParse->u1.pReturning;
+ Returning *pReturning;
int addrRewind;
int reg;
+ assert( !pParse->isCreate );
+ pReturning = pParse->u1.d.pReturning;
if( pReturning->nRetCol ){
sqlite3VdbeAddOp0(v, OP_FkCheck);
addrRewind =
@@ -247,7 +249,9 @@ void sqlite3FinishCoding(Parse *pParse){
}
if( pParse->bReturning ){
- Returning *pRet = pParse->u1.pReturning;
+ Returning *pRet;
+ assert( !pParse->isCreate );
+ pRet = pParse->u1.d.pReturning;
if( pRet->nRetCol ){
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
}
@@ -1319,8 +1323,9 @@ void sqlite3StartTable(
/* If the file format and encoding in the database have not been set,
** set them now.
*/
- reg1 = pParse->regRowid = ++pParse->nMem;
- reg2 = pParse->regRoot = ++pParse->nMem;
+ assert( pParse->isCreate );
+ reg1 = pParse->u1.cr.regRowid = ++pParse->nMem;
+ reg2 = pParse->u1.cr.regRoot = ++pParse->nMem;
reg3 = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
sqlite3VdbeUsesBtree(v, iDb);
@@ -1335,8 +1340,8 @@ void sqlite3StartTable(
** The record created does not contain anything yet. It will be replaced
** by the real entry in code generated at sqlite3EndTable().
**
- ** The rowid for the new entry is left in register pParse->regRowid.
- ** The root page number of the new table is left in reg pParse->regRoot.
+ ** The rowid for the new entry is left in register pParse->u1.cr.regRowid.
+ ** The root page of the new table is left in reg pParse->u1.cr.regRoot.
** The rowid and root page number values are needed by the code that
** sqlite3EndTable will generate.
*/
@@ -1347,7 +1352,7 @@ void sqlite3StartTable(
#endif
{
assert( !pParse->bReturning );
- pParse->u1.addrCrTab =
+ pParse->u1.cr.addrCrTab =
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
}
sqlite3OpenSchemaTable(pParse, iDb);
@@ -1425,7 +1430,8 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){
sqlite3ExprListDelete(db, pList);
return;
}
- pParse->u1.pReturning = pRet;
+ assert( !pParse->isCreate );
+ pParse->u1.d.pReturning = pRet;
pRet->pParse = pParse;
pRet->pReturnEL = pList;
sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet);
@@ -1467,7 +1473,6 @@ void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
char *zType;
Column *pCol;
sqlite3 *db = pParse->db;
- u8 hName;
Column *aNew;
u8 eType = COLTYPE_CUSTOM;
u8 szEst = 1;
@@ -1521,13 +1526,10 @@ void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
memcpy(z, sName.z, sName.n);
z[sName.n] = 0;
sqlite3Dequote(z);
- hName = sqlite3StrIHash(z);
- for(i=0; i<p->nCol; i++){
- if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){
- sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
- sqlite3DbFree(db, z);
- return;
- }
+ if( p->nCol && sqlite3ColumnIndex(p, z)>=0 ){
+ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
+ sqlite3DbFree(db, z);
+ return;
}
aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0]));
if( aNew==0 ){
@@ -1538,7 +1540,7 @@ void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
pCol = &p->aCol[p->nCol];
memset(pCol, 0, sizeof(p->aCol[0]));
pCol->zCnName = z;
- pCol->hName = hName;
+ pCol->hName = sqlite3StrIHash(z);
sqlite3ColumnPropertiesFromName(p, pCol);
if( sType.n==0 ){
@@ -1562,9 +1564,14 @@ void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
pCol->affinity = sqlite3AffinityType(zType, pCol);
pCol->colFlags |= COLFLAG_HASTYPE;
}
+ if( p->nCol<=0xff ){
+ u8 h = pCol->hName % sizeof(p->aHx);
+ p->aHx[h] = p->nCol;
+ }
p->nCol++;
p->nNVCol++;
- pParse->constraintName.n = 0;
+ assert( pParse->isCreate );
+ pParse->u1.cr.constraintName.n = 0;
}
/*
@@ -1828,15 +1835,11 @@ void sqlite3AddPrimaryKey(
assert( pCExpr!=0 );
sqlite3StringToId(pCExpr);
if( pCExpr->op==TK_ID ){
- const char *zCName;
assert( !ExprHasProperty(pCExpr, EP_IntValue) );
- zCName = pCExpr->u.zToken;
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){
- pCol = &pTab->aCol[iCol];
- makeColumnPartOfPrimaryKey(pParse, pCol);
- break;
- }
+ iCol = sqlite3ColumnIndex(pTab, pCExpr->u.zToken);
+ if( iCol>=0 ){
+ pCol = &pTab->aCol[iCol];
+ makeColumnPartOfPrimaryKey(pParse, pCol);
}
}
}
@@ -1888,8 +1891,10 @@ void sqlite3AddCheckConstraint(
&& !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt)
){
pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
- if( pParse->constraintName.n ){
- sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
+ assert( pParse->isCreate );
+ if( pParse->u1.cr.constraintName.n ){
+ sqlite3ExprListSetName(pParse, pTab->pCheck,
+ &pParse->u1.cr.constraintName, 1);
}else{
Token t;
for(zStart++; sqlite3Isspace(zStart[0]); zStart++){}
@@ -2339,9 +2344,9 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
** into BTREE_BLOBKEY.
*/
assert( !pParse->bReturning );
- if( pParse->u1.addrCrTab ){
+ if( pParse->u1.cr.addrCrTab ){
assert( v );
- sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY);
+ sqlite3VdbeChangeP3(v, pParse->u1.cr.addrCrTab, BTREE_BLOBKEY);
}
/* Locate the PRIMARY KEY index. Or, if this table was originally
@@ -2781,7 +2786,7 @@ void sqlite3EndTable(
/* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
** statement to populate the new table. The root-page number for the
- ** new table is in register pParse->regRoot.
+ ** new table is in register pParse->u1.cr.regRoot.
**
** Once the SELECT has been coded by sqlite3Select(), it is in a
** suitable state to query for the column names and types to be used
@@ -2812,7 +2817,8 @@ void sqlite3EndTable(
regRec = ++pParse->nMem;
regRowid = ++pParse->nMem;
sqlite3MayAbort(pParse);
- sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb);
+ assert( pParse->isCreate );
+ sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->u1.cr.regRoot, iDb);
sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
@@ -2857,6 +2863,7 @@ void sqlite3EndTable(
** schema table. We just need to update that slot with all
** the information we've collected.
*/
+ assert( pParse->isCreate );
sqlite3NestedParse(pParse,
"UPDATE %Q." LEGACY_SCHEMA_TABLE
" SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q"
@@ -2865,9 +2872,9 @@ void sqlite3EndTable(
zType,
p->zName,
p->zName,
- pParse->regRoot,
+ pParse->u1.cr.regRoot,
zStmt,
- pParse->regRowid
+ pParse->u1.cr.regRowid
);
sqlite3DbFree(db, zStmt);
sqlite3ChangeCookie(pParse, iDb);
@@ -4691,7 +4698,6 @@ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
int i;
assert( db!=0 );
if( pList==0 ) return;
- assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
for(i=0; i<pList->nId; i++){
sqlite3DbFree(db, pList->a[i].zName);
}
diff --git a/src/callback.c b/src/callback.c
index c36d51a4e..6fe21a295 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -302,12 +302,18 @@ static int matchQuality(
u8 enc /* Desired text encoding */
){
int match;
- assert( p->nArg>=-1 );
+ assert( p->nArg>=(-4) && p->nArg!=(-2) );
+ assert( nArg>=(-2) );
/* Wrong number of arguments means "no match" */
if( p->nArg!=nArg ){
- if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
+ if( nArg==(-2) ) return p->xSFunc==0 ? 0 : FUNC_PERFECT_MATCH;
if( p->nArg>=0 ) return 0;
+ /* Special p->nArg values available to built-in functions only:
+ ** -3 1 or more arguments required
+ ** -4 2 or more arguments required
+ */
+ if( p->nArg<(-2) && nArg<(-2-p->nArg) ) return 0;
}
/* Give a better score to a function with a specific number of arguments
diff --git a/src/date.c b/src/date.c
index 8c48a81fa..de2736637 100644
--- a/src/date.c
+++ b/src/date.c
@@ -222,6 +222,9 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
zDate++;
}
ms /= rScale;
+ /* Truncate to avoid problems with sub-milliseconds
+ ** rounding. https://sqlite.org/forum/forumpost/766a2c9231 */
+ if( ms>0.999 ) ms = 0.999;
}
}else{
s = 0;
@@ -1429,7 +1432,7 @@ static void strftimeFunc(
}
case 'f': { /* Fractional seconds. (Non-standard) */
double s = x.s;
- if( s>59.999 ) s = 59.999;
+ if( NEVER(s>59.999) ) s = 59.999;
sqlite3_str_appendf(&sRes, "%06.3f", s);
break;
}
diff --git a/src/dbpage.c b/src/dbpage.c
index 74f345570..eb5ab33fe 100644
--- a/src/dbpage.c
+++ b/src/dbpage.c
@@ -317,6 +317,24 @@ static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
return SQLITE_OK;
}
+/*
+** Open write transactions. Since we do not know in advance which database
+** files will be written by the sqlite_dbpage virtual table, start a write
+** transaction on them all.
+**
+** Return SQLITE_OK if successful, or an SQLite error code otherwise.
+*/
+static int dbpageBeginTrans(DbpageTable *pTab){
+ sqlite3 *db = pTab->db;
+ int rc = SQLITE_OK;
+ int i;
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
+ }
+ return rc;
+}
+
static int dbpageUpdate(
sqlite3_vtab *pVtab,
int argc,
@@ -384,6 +402,12 @@ static int dbpageUpdate(
goto update_fail;
}
}
+
+ if( dbpageBeginTrans(pTab)!=SQLITE_OK ){
+ zErr = "failed to open transaction";
+ goto update_fail;
+ }
+
pPager = sqlite3BtreePager(pBt);
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
@@ -400,23 +424,14 @@ static int dbpageUpdate(
return rc;
update_fail:
+ pTab->pgnoTrunc = 0;
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
return SQLITE_ERROR;
}
-/* Since we do not know in advance which database files will be
-** written by the sqlite_dbpage virtual table, start a write transaction
-** on them all.
-*/
static int dbpageBegin(sqlite3_vtab *pVtab){
DbpageTable *pTab = (DbpageTable *)pVtab;
- sqlite3 *db = pTab->db;
- int i;
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0);
- }
pTab->pgnoTrunc = 0;
return SQLITE_OK;
}
@@ -452,7 +467,7 @@ static int dbpageRollbackTo(sqlite3_vtab *pVtab, int notUsed1){
*/
int sqlite3DbpageRegister(sqlite3 *db){
static sqlite3_module dbpage_module = {
- 0, /* iVersion */
+ 2, /* iVersion */
dbpageConnect, /* xCreate */
dbpageConnect, /* xConnect */
dbpageBestIndex, /* xBestIndex */
diff --git a/src/expr.c b/src/expr.c
index 86c966683..3011fcd9a 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1849,7 +1849,6 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){
}
pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);
pItem->fg = pOldItem->fg;
- pItem->fg.done = 0;
pItem->u = pOldItem->u;
}
return pNew;
@@ -1932,16 +1931,13 @@ IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
int i;
assert( db!=0 );
if( p==0 ) return 0;
- assert( p->eU4!=EU4_EXPR );
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) );
if( pNew==0 ) return 0;
pNew->nId = p->nId;
- pNew->eU4 = p->eU4;
for(i=0; i<p->nId; i++){
struct IdList_item *pNewItem = &pNew->a[i];
const struct IdList_item *pOldItem = &p->a[i];
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
- pNewItem->u4 = pOldItem->u4;
}
return pNew;
}
@@ -2969,13 +2965,7 @@ const char *sqlite3RowidAlias(Table *pTab){
int ii;
assert( VisibleRowid(pTab) );
for(ii=0; ii<ArraySize(azOpt); ii++){
- int iCol;
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break;
- }
- if( iCol==pTab->nCol ){
- return azOpt[ii];
- }
+ if( sqlite3ColumnIndex(pTab, azOpt[ii])<0 ) return azOpt[ii];
}
return 0;
}
@@ -3285,6 +3275,7 @@ int sqlite3FindInIndex(
if( aiMap ) aiMap[i] = j;
}
+ assert( nExpr>0 && nExpr<BMS );
assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) );
if( colUsed==(MASKBIT(nExpr)-1) ){
/* If we reach this point, that means the index pIdx is usable */
@@ -3464,6 +3455,7 @@ static int findCompatibleInRhsSubrtn(
assert( pOp->opcode==OP_BeginSubrtn );
pSig = pOp->p4.pSubrtnSig;
assert( pSig!=0 );
+ if( !pSig->bComplete ) continue;
if( pNewSig->selId!=pSig->selId ) continue;
if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue;
pExpr->y.sub.iAddr = pSig->iAddr;
@@ -3510,6 +3502,7 @@ void sqlite3CodeRhsOfIN(
KeyInfo *pKeyInfo = 0; /* Key information */
int nVal; /* Size of vector pLeft */
Vdbe *v; /* The prepared statement under construction */
+ SubrtnSig *pSig = 0; /* Signature for this subroutine */
v = pParse->pVdbe;
assert( v!=0 );
@@ -3530,7 +3523,6 @@ void sqlite3CodeRhsOfIN(
** Compute a signature for the RHS of the IN operator to facility
** finding and reusing prior instances of the same IN operator.
*/
- SubrtnSig *pSig = 0;
assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 );
if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){
pSig = sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0]));
@@ -3573,6 +3565,7 @@ void sqlite3CodeRhsOfIN(
pExpr->y.sub.iAddr =
sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1;
if( pSig ){
+ pSig->bComplete = 0;
pSig->iAddr = pExpr->y.sub.iAddr;
pSig->regReturn = pExpr->y.sub.regReturn;
pSig->iTable = iTab;
@@ -3708,6 +3701,7 @@ void sqlite3CodeRhsOfIN(
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
+ if( pSig ) pSig->bComplete = 1;
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
}
diff --git a/src/func.c b/src/func.c
index a4b72ecc4..52462b468 100644
--- a/src/func.c
+++ b/src/func.c
@@ -354,14 +354,8 @@ static void substrFunc(
int len;
int p0type;
i64 p1, p2;
- int negP2 = 0;
assert( argc==3 || argc==2 );
- if( sqlite3_value_type(argv[1])==SQLITE_NULL
- || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL)
- ){
- return;
- }
p0type = sqlite3_value_type(argv[0]);
p1 = sqlite3_value_int64(argv[1]);
if( p0type==SQLITE_BLOB ){
@@ -379,28 +373,31 @@ static void substrFunc(
}
}
}
-#ifdef SQLITE_SUBSTR_COMPATIBILITY
- /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
- ** as substr(X,1,N) - it returns the first N characters of X. This
- ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
- ** from 2009-02-02 for compatibility of applications that exploited the
- ** old buggy behavior. */
- if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
-#endif
if( argc==3 ){
p2 = sqlite3_value_int64(argv[2]);
- if( p2<0 ){
- p2 = -p2;
- negP2 = 1;
- }
+ if( p2==0 && sqlite3_value_type(argv[2])==SQLITE_NULL ) return;
}else{
p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH];
}
+ if( p1==0 ){
+#ifdef SQLITE_SUBSTR_COMPATIBILITY
+ /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
+ ** as substr(X,1,N) - it returns the first N characters of X. This
+ ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
+ ** from 2009-02-02 for compatibility of applications that exploited the
+ ** old buggy behavior. */
+ p1 = 1; /* <rdar://problem/6778339> */
+#endif
+ if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return;
+ }
if( p1<0 ){
p1 += len;
if( p1<0 ){
- p2 += p1;
- if( p2<0 ) p2 = 0;
+ if( p2<0 ){
+ p2 = 0;
+ }else{
+ p2 += p1;
+ }
p1 = 0;
}
}else if( p1>0 ){
@@ -408,12 +405,13 @@ static void substrFunc(
}else if( p2>0 ){
p2--;
}
- if( negP2 ){
- p1 -= p2;
- if( p1<0 ){
- p2 += p1;
- p1 = 0;
+ if( p2<0 ){
+ if( p2<-p1 ){
+ p2 = p1;
+ }else{
+ p2 = -p2;
}
+ p1 -= p2;
}
assert( p1>=0 && p2>=0 );
if( p0type!=SQLITE_BLOB ){
@@ -1870,7 +1868,10 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
assert( p->cnt>0 );
p->cnt--;
if( !p->approx ){
- p->iSum -= sqlite3_value_int64(argv[0]);
+ if( sqlite3SubInt64(&p->iSum, sqlite3_value_int64(argv[0])) ){
+ p->ovrfl = 1;
+ p->approx = 1;
+ }
}else if( type==SQLITE_INTEGER ){
i64 iVal = sqlite3_value_int64(argv[0]);
if( iVal!=SMALLEST_INT64 ){
@@ -2696,12 +2697,10 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(rtrim, 2, 2, 0, trimFunc ),
FUNCTION(trim, 1, 3, 0, trimFunc ),
FUNCTION(trim, 2, 3, 0, trimFunc ),
- FUNCTION(min, -1, 0, 1, minmaxFunc ),
- FUNCTION(min, 0, 0, 1, 0 ),
+ FUNCTION(min, -3, 0, 1, minmaxFunc ),
WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
- FUNCTION(max, -1, 1, 1, minmaxFunc ),
- FUNCTION(max, 0, 1, 1, 0 ),
+ FUNCTION(max, -3, 1, 1, minmaxFunc ),
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
@@ -2728,11 +2727,8 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION(unhex, 1, 0, 0, unhexFunc ),
FUNCTION(unhex, 2, 0, 0, unhexFunc ),
- FUNCTION(concat, -1, 0, 0, concatFunc ),
- FUNCTION(concat, 0, 0, 0, 0 ),
- FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ),
- FUNCTION(concat_ws, 0, 0, 0, 0 ),
- FUNCTION(concat_ws, 1, 0, 0, 0 ),
+ FUNCTION(concat, -3, 0, 0, concatFunc ),
+ FUNCTION(concat_ws, -4, 0, 0, concatwsFunc ),
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
@@ -2776,8 +2772,6 @@ void sqlite3RegisterBuiltinFunctions(void){
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
FUNCTION(unknown, -1, 0, 0, unknownFunc ),
#endif
- FUNCTION(coalesce, 1, 0, 0, 0 ),
- FUNCTION(coalesce, 0, 0, 0, 0 ),
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
MFUNCTION(ceil, 1, xCeil, ceilingFunc ),
MFUNCTION(ceiling, 1, xCeil, ceilingFunc ),
@@ -2815,11 +2809,9 @@ void sqlite3RegisterBuiltinFunctions(void){
MFUNCTION(pi, 0, 0, piFunc ),
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
FUNCTION(sign, 1, 0, 0, signFunc ),
- INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
- INLINE_FUNC(iif, 2, INLINEFUNC_iif, 0 ),
- INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
- INLINE_FUNC(if, 2, INLINEFUNC_iif, 0 ),
- INLINE_FUNC(if, 3, INLINEFUNC_iif, 0 ),
+ INLINE_FUNC(coalesce, -4, INLINEFUNC_coalesce, 0 ),
+ INLINE_FUNC(iif, -4, INLINEFUNC_iif, 0 ),
+ INLINE_FUNC(if, -4, INLINEFUNC_iif, 0 ),
};
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
diff --git a/src/hash.c b/src/hash.c
index 8ec043f11..8cc6c0966 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -54,12 +54,19 @@ void sqlite3HashClear(Hash *pH){
*/
static unsigned int strHash(const char *z){
unsigned int h = 0;
- unsigned char c;
- while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/
+ while( z[0] ){ /*OPTIMIZATION-IF-TRUE*/
/* Knuth multiplicative hashing. (Sorting & Searching, p. 510).
** 0x9e3779b1 is 2654435761 which is the closest prime number to
- ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
- h += sqlite3UpperToLower[c];
+ ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2.
+ **
+ ** Only bits 0xdf for ASCII and bits 0xbf for EBCDIC each octet are
+ ** hashed since the omitted bits determine the upper/lower case difference.
+ */
+#ifdef SQLITE_EBCDIC
+ h += 0xbf & (unsigned char)*(z++);
+#else
+ h += 0xdf & (unsigned char)*(z++);
+#endif
h *= 0x9e3779b1;
}
return h;
@@ -132,9 +139,8 @@ static int rehash(Hash *pH, unsigned int new_size){
pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);
memset(new_ht, 0, new_size*sizeof(struct _ht));
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
- unsigned int h = strHash(elem->pKey) % new_size;
next_elem = elem->next;
- insertElement(pH, &new_ht[h], elem);
+ insertElement(pH, &new_ht[elem->h % new_size], elem);
}
return 1;
}
@@ -152,23 +158,22 @@ static HashElem *findElementWithHash(
HashElem *elem; /* Used to loop thru the element list */
unsigned int count; /* Number of elements left to test */
unsigned int h; /* The computed hash */
- static HashElem nullElement = { 0, 0, 0, 0 };
+ static HashElem nullElement = { 0, 0, 0, 0, 0 };
+ h = strHash(pKey);
if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
struct _ht *pEntry;
- h = strHash(pKey) % pH->htsize;
- pEntry = &pH->ht[h];
+ pEntry = &pH->ht[h % pH->htsize];
elem = pEntry->chain;
count = pEntry->count;
}else{
- h = 0;
elem = pH->first;
count = pH->count;
}
if( pHash ) *pHash = h;
while( count ){
assert( elem!=0 );
- if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
+ if( h==elem->h && sqlite3StrICmp(elem->pKey,pKey)==0 ){
return elem;
}
elem = elem->next;
@@ -180,10 +185,9 @@ static HashElem *findElementWithHash(
/* Remove a single entry from the hash table given a pointer to that
** element and a hash on the element's key.
*/
-static void removeElementGivenHash(
+static void removeElement(
Hash *pH, /* The pH containing "elem" */
- HashElem* elem, /* The element to be removed from the pH */
- unsigned int h /* Hash value for the element */
+ HashElem *elem /* The element to be removed from the pH */
){
struct _ht *pEntry;
if( elem->prev ){
@@ -195,7 +199,7 @@ static void removeElementGivenHash(
elem->next->prev = elem->prev;
}
if( pH->ht ){
- pEntry = &pH->ht[h];
+ pEntry = &pH->ht[elem->h % pH->htsize];
if( pEntry->chain==elem ){
pEntry->chain = elem->next;
}
@@ -246,7 +250,7 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
if( elem->data ){
void *old_data = elem->data;
if( data==0 ){
- removeElementGivenHash(pH,elem,h);
+ removeElement(pH,elem);
}else{
elem->data = data;
elem->pKey = pKey;
@@ -257,14 +261,12 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );
if( new_elem==0 ) return data;
new_elem->pKey = pKey;
+ new_elem->h = h;
new_elem->data = data;
pH->count++;
- if( pH->count>=10 && pH->count > 2*pH->htsize ){
- if( rehash(pH, pH->count*2) ){
- assert( pH->htsize>0 );
- h = strHash(pKey) % pH->htsize;
- }
+ if( pH->count>=5 && pH->count > 2*pH->htsize ){
+ rehash(pH, pH->count*3);
}
- insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem);
+ insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem);
return 0;
}
diff --git a/src/hash.h b/src/hash.h
index 3f491e45c..cff65d6e5 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -60,6 +60,7 @@ struct HashElem {
HashElem *next, *prev; /* Next and previous elements in the table */
void *data; /* Data associated with this element */
const char *pKey; /* Key associated with this element */
+ unsigned int h; /* hash for pKey */
};
/*
diff --git a/src/insert.c b/src/insert.c
index d380281be..c1ca1897e 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -927,6 +927,7 @@ void sqlite3Insert(
int regRowid; /* registers holding insert rowid */
int regData; /* register holding first column to insert */
int *aRegIdx = 0; /* One register allocated to each index */
+ int *aTabColMap = 0; /* Mapping from pTab columns to pCol entries */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to insert into a view */
@@ -1071,31 +1072,25 @@ void sqlite3Insert(
*/
bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
if( pColumn ){
- assert( pColumn->eU4!=EU4_EXPR );
- pColumn->eU4 = EU4_IDX;
+ aTabColMap = sqlite3DbMallocZero(db, pTab->nCol*sizeof(int));
+ if( aTabColMap==0 ) goto insert_cleanup;
for(i=0; i<pColumn->nId; i++){
- pColumn->a[i].u4.idx = -1;
- }
- for(i=0; i<pColumn->nId; i++){
- for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){
- pColumn->a[i].u4.idx = j;
- if( i!=j ) bIdListInOrder = 0;
- if( j==pTab->iPKey ){
- ipkColumn = i; assert( !withoutRowid );
- }
+ j = sqlite3ColumnIndex(pTab, pColumn->a[i].zName);
+ if( j>=0 ){
+ if( aTabColMap[j]==0 ) aTabColMap[j] = i+1;
+ if( i!=j ) bIdListInOrder = 0;
+ if( j==pTab->iPKey ){
+ ipkColumn = i; assert( !withoutRowid );
+ }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
- if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
- sqlite3ErrorMsg(pParse,
- "cannot INSERT into generated column \"%s\"",
- pTab->aCol[j].zCnName);
- goto insert_cleanup;
- }
-#endif
- break;
+ if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
+ sqlite3ErrorMsg(pParse,
+ "cannot INSERT into generated column \"%s\"",
+ pTab->aCol[j].zCnName);
+ goto insert_cleanup;
}
- }
- if( j>=pTab->nCol ){
+#endif
+ }else{
if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){
ipkColumn = i;
bIdListInOrder = 0;
@@ -1393,7 +1388,7 @@ void sqlite3Insert(
continue;
}else if( pColumn==0 ){
/* Hidden columns that are not explicitly named in the INSERT
- ** get there default value */
+ ** get their default value */
sqlite3ExprCodeFactorable(pParse,
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
iRegStore);
@@ -1401,9 +1396,9 @@ void sqlite3Insert(
}
}
if( pColumn ){
- assert( pColumn->eU4==EU4_IDX );
- for(j=0; j<pColumn->nId && pColumn->a[j].u4.idx!=i; j++){}
- if( j>=pColumn->nId ){
+ j = aTabColMap[i];
+ assert( j>=0 && j<=pColumn->nId );
+ if( j==0 ){
/* A column not named in the insert column list gets its
** default value */
sqlite3ExprCodeFactorable(pParse,
@@ -1411,7 +1406,7 @@ void sqlite3Insert(
iRegStore);
continue;
}
- k = j;
+ k = j - 1;
}else if( nColumn==0 ){
/* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */
sqlite3ExprCodeFactorable(pParse,
@@ -1656,7 +1651,10 @@ insert_cleanup:
sqlite3ExprListDelete(db, pList);
sqlite3UpsertDelete(db, pUpsert);
sqlite3SelectDelete(db, pSelect);
- sqlite3IdListDelete(db, pColumn);
+ if( pColumn ){
+ sqlite3IdListDelete(db, pColumn);
+ sqlite3DbFree(db, aTabColMap);
+ }
if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx);
}
diff --git a/src/json.c b/src/json.c
index a0a075e66..47a9c875e 100644
--- a/src/json.c
+++ b/src/json.c
@@ -2054,10 +2054,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
u8 x;
u32 sz;
u32 n;
- if( NEVER(i>pParse->nBlob) ){
- *pSz = 0;
- return 0;
- }
+ assert( i<=pParse->nBlob );
x = pParse->aBlob[i]>>4;
if( x<=11 ){
sz = x;
@@ -2101,8 +2098,8 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
if( (i64)i+sz+n > pParse->nBlob
&& (i64)i+sz+n > pParse->nBlob-pParse->delta
){
- sz = 0;
- n = 0;
+ *pSz = 0;
+ return 0;
}
*pSz = sz;
return n;
@@ -2199,9 +2196,12 @@ static u32 jsonTranslateBlobToText(
}
case JSONB_TEXT:
case JSONB_TEXTJ: {
- jsonAppendChar(pOut, '"');
- jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
- jsonAppendChar(pOut, '"');
+ if( pOut->nUsed+sz+2<=pOut->nAlloc || jsonStringGrow(pOut, sz+2)==0 ){
+ pOut->zBuf[pOut->nUsed] = '"';
+ memcpy(pOut->zBuf+pOut->nUsed+1,(const char*)&pParse->aBlob[i+n],sz);
+ pOut->zBuf[pOut->nUsed+sz+1] = '"';
+ pOut->nUsed += sz+2;
+ }
break;
}
case JSONB_TEXT5: {
diff --git a/src/main.c b/src/main.c
index 8cd0303c4..e2d272157 100644
--- a/src/main.c
+++ b/src/main.c
@@ -959,7 +959,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
default: {
static const struct {
int op; /* The opcode */
- u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */
+ u64 mask; /* Mask of the bit in sqlite3.flags to set/clear */
} aFlagOp[] = {
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
@@ -980,6 +980,9 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
{ SQLITE_DBCONFIG_STMT_SCANSTATUS, SQLITE_StmtScanStatus },
{ SQLITE_DBCONFIG_REVERSE_SCANORDER, SQLITE_ReverseOrder },
+ { SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE, SQLITE_AttachCreate },
+ { SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE, SQLITE_AttachWrite },
+ { SQLITE_DBCONFIG_ENABLE_COMMENTS, SQLITE_Comments },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -1831,8 +1834,10 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
** Set the setlk timeout value.
*/
int sqlite3_setlk_timeout(sqlite3 *db, int ms, int flags){
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
int iDb;
int bBOC = ((flags & SQLITE_SETLK_BLOCK_ON_CONNECT) ? 1 : 0);
+#endif
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
@@ -3353,6 +3358,9 @@ static int openDatabase(
| SQLITE_EnableTrigger
| SQLITE_EnableView
| SQLITE_CacheSpill
+ | SQLITE_AttachCreate
+ | SQLITE_AttachWrite
+ | SQLITE_Comments
#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0
| SQLITE_TrustedSchema
#endif
@@ -3969,13 +3977,10 @@ int sqlite3_table_column_metadata(
if( zColumnName==0 ){
/* Query for existence of table only */
}else{
- for(iCol=0; iCol<pTab->nCol; iCol++){
+ iCol = sqlite3ColumnIndex(pTab, zColumnName);
+ if( iCol>=0 ){
pCol = &pTab->aCol[iCol];
- if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){
- break;
- }
- }
- if( iCol==pTab->nCol ){
+ }else{
if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){
iCol = pTab->iPKey;
pCol = iCol>=0 ? &pTab->aCol[iCol] : 0;
diff --git a/src/os_unix.c b/src/os_unix.c
index 7f92c5234..02fe7c819 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -1665,7 +1665,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
if( pInode->bProcessLock==0 ){
struct flock lock;
- assert( pInode->nLock==0 );
+ /* assert( pInode->nLock==0 ); <-- Not true if unix-excl READONLY used */
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
diff --git a/src/pager.c b/src/pager.c
index e2dbbeae3..ecec892b4 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -808,7 +808,7 @@ int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
if( pPager->pWal ){
u32 iRead = 0;
(void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
- return iRead==0; /* Condition (4) */
+ if( iRead ) return 0; /* Case (4) */
}
#endif
assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 );
diff --git a/src/parse.y b/src/parse.y
index b8d904d12..76c9a8e4e 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -63,6 +63,11 @@
#include "sqliteInt.h"
/*
+** Verify that the pParse->isCreate field is set
+*/
+#define ASSERT_IS_CREATE assert(pParse->isCreate)
+
+/*
** Disable all error recovery processing in the parser push-down
** automaton.
*/
@@ -125,6 +130,10 @@ static void parserSyntaxError(Parse *pParse, Token *p){
static void disableLookaside(Parse *pParse){
sqlite3 *db = pParse->db;
pParse->disableLookaside++;
+#ifdef SQLITE_DEBUG
+ pParse->isCreate = 1;
+#endif
+ memset(&pParse->u1.cr, 0, sizeof(pParse->u1.cr));
DisableLookaside;
}
@@ -197,7 +206,9 @@ cmd ::= create_table create_table_args.
create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
}
-createkw(A) ::= CREATE(A). {disableLookaside(pParse);}
+createkw(A) ::= CREATE(A). {
+ disableLookaside(pParse);
+}
%type ifnotexists {int}
ifnotexists(A) ::= . {A = 0;}
@@ -373,7 +384,7 @@ scantok(A) ::= . {
//
carglist ::= carglist ccons.
carglist ::= .
-ccons ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
+ccons ::= CONSTRAINT nm(X). {ASSERT_IS_CREATE; pParse->u1.cr.constraintName = X;}
ccons ::= DEFAULT scantok(A) term(X).
{sqlite3AddDefaultValue(pParse,X,A.z,&A.z[A.n]);}
ccons ::= DEFAULT LP(A) expr(X) RP(Z).
@@ -448,9 +459,9 @@ conslist_opt(A) ::= . {A.n = 0; A.z = 0;}
conslist_opt(A) ::= COMMA(A) conslist.
conslist ::= conslist tconscomma tcons.
conslist ::= tcons.
-tconscomma ::= COMMA. {pParse->constraintName.n = 0;}
+tconscomma ::= COMMA. {ASSERT_IS_CREATE; pParse->u1.cr.constraintName.n = 0;}
tconscomma ::= .
-tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
+tcons ::= CONSTRAINT nm(X). {ASSERT_IS_CREATE; pParse->u1.cr.constraintName = X;}
tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R).
{sqlite3AddPrimaryKey(pParse,X,R,I,0);}
tcons ::= UNIQUE LP sortlist(X) RP onconf(R).
@@ -1659,6 +1670,10 @@ trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z)
ON fullname(E) foreach_clause when_clause(G). {
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
A = (Z.n==0?B:Z); /*A-overwrites-T*/
+#ifdef SQLITE_DEBUG
+ assert( pParse->isCreate ); /* Set by createkw reduce action */
+ pParse->isCreate = 0; /* But, should not be set for CREATE TRIGGER */
+#endif
}
%type trigger_time {int}
@@ -1882,7 +1897,8 @@ wqlist(A) ::= wqlist(A) COMMA wqitem(X). {
// These must be at the end of this file. Specifically, the rules that
// introduce tokens WINDOW, OVER and FILTER must appear last. This causes
// the integer values assigned to these tokens to be larger than all other
-// tokens that may be output by the tokenizer except TK_SPACE and TK_ILLEGAL.
+// tokens that may be output by the tokenizer except TK_SPACE, TK_COMMENT,
+// and TK_ILLEGAL.
//
%ifndef SQLITE_OMIT_WINDOWFUNC
%type windowdefn_list {Window*}
@@ -2059,9 +2075,9 @@ term(A) ::= QNUMBER(X). {
}
/*
-** The TK_SPACE and TK_ILLEGAL tokens must be the last two tokens. The
-** parser depends on this. Those tokens are not used in any grammar rule.
-** They are only used by the tokenizer. Declare them last so that they
-** are guaranteed to be the last two tokens
+** The TK_SPACE, TK_COMMENT, and TK_ILLEGAL tokens must be the last three
+** tokens. The parser depends on this. Those tokens are not used in any
+** grammar rule. They are only used by the tokenizer. Declare them last
+** so that they are guaranteed to be the last three.
*/
-%token SPACE ILLEGAL.
+%token SPACE COMMENT ILLEGAL.
diff --git a/src/resolve.c b/src/resolve.c
index d6a5144af..54ce4fb1e 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -294,7 +294,6 @@ static int lookupName(
Schema *pSchema = 0; /* Schema of the expression */
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
Table *pTab = 0; /* Table holding the row */
- Column *pCol; /* A column of pTab */
ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */
const char *zCol = pRight->u.zToken;
@@ -345,7 +344,6 @@ static int lookupName(
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
- u8 hCol;
pTab = pItem->pSTab;
assert( pTab!=0 && pTab->zName!=0 );
assert( pTab->nCol>0 || pParse->nErr );
@@ -433,43 +431,38 @@ static int lookupName(
sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
}
}
- hCol = sqlite3StrIHash(zCol);
- for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
- if( pCol->hName==hCol
- && sqlite3StrICmp(pCol->zCnName, zCol)==0
- ){
- if( cnt>0 ){
- if( pItem->fg.isUsing==0
- || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
- ){
- /* Two or more tables have the same column name which is
- ** not joined by USING. This is an error. Signal as much
- ** by clearing pFJMatch and letting cnt go above 1. */
- sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else
- if( (pItem->fg.jointype & JT_RIGHT)==0 ){
- /* An INNER or LEFT JOIN. Use the left-most table */
- continue;
- }else
- if( (pItem->fg.jointype & JT_LEFT)==0 ){
- /* A RIGHT JOIN. Use the right-most table */
- cnt = 0;
- sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else{
- /* For a FULL JOIN, we must construct a coalesce() func */
- extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
- }
- }
- cnt++;
- pMatch = pItem;
- /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
- pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
- if( pItem->fg.isNestedFrom ){
- sqlite3SrcItemColumnUsed(pItem, j);
+ j = sqlite3ColumnIndex(pTab, zCol);
+ if( j>=0 ){
+ if( cnt>0 ){
+ if( pItem->fg.isUsing==0
+ || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
+ ){
+ /* Two or more tables have the same column name which is
+ ** not joined by USING. This is an error. Signal as much
+ ** by clearing pFJMatch and letting cnt go above 1. */
+ sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else
+ if( (pItem->fg.jointype & JT_RIGHT)==0 ){
+ /* An INNER or LEFT JOIN. Use the left-most table */
+ continue;
+ }else
+ if( (pItem->fg.jointype & JT_LEFT)==0 ){
+ /* A RIGHT JOIN. Use the right-most table */
+ cnt = 0;
+ sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else{
+ /* For a FULL JOIN, we must construct a coalesce() func */
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
}
- break;
+ }
+ cnt++;
+ pMatch = pItem;
+ /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
+ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
+ if( pItem->fg.isNestedFrom ){
+ sqlite3SrcItemColumnUsed(pItem, j);
}
}
if( 0==cnt && VisibleRowid(pTab) ){
@@ -559,23 +552,18 @@ static int lookupName(
if( pTab ){
int iCol;
- u8 hCol = sqlite3StrIHash(zCol);
pSchema = pTab->pSchema;
cntTab++;
- for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){
- if( pCol->hName==hCol
- && sqlite3StrICmp(pCol->zCnName, zCol)==0
- ){
- if( iCol==pTab->iPKey ){
- iCol = -1;
- }
- break;
+ iCol = sqlite3ColumnIndex(pTab, zCol);
+ if( iCol>=0 ){
+ if( pTab->iPKey==iCol ) iCol = -1;
+ }else{
+ if( sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
+ iCol = -1;
+ }else{
+ iCol = pTab->nCol;
}
}
- if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
- /* IMP: R-51414-32910 */
- iCol = -1;
- }
if( iCol<pTab->nCol ){
cnt++;
pMatch = 0;
diff --git a/src/select.c b/src/select.c
index cf25c8e67..e47a9b6be 100644
--- a/src/select.c
+++ b/src/select.c
@@ -319,10 +319,33 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
*/
int sqlite3ColumnIndex(Table *pTab, const char *zCol){
int i;
- u8 h = sqlite3StrIHash(zCol);
- Column *pCol;
- for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){
- if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i;
+ u8 h;
+ const Column *aCol;
+ int nCol;
+
+ h = sqlite3StrIHash(zCol);
+ aCol = pTab->aCol;
+ nCol = pTab->nCol;
+
+ /* See if the aHx gives us a lucky match */
+ i = pTab->aHx[h % sizeof(pTab->aHx)];
+ assert( i<nCol );
+ if( aCol[i].hName==h
+ && sqlite3StrICmp(aCol[i].zCnName, zCol)==0
+ ){
+ return i;
+ }
+
+ /* No lucky match from the hash table. Do a full search. */
+ i = 0;
+ while( 1 /*exit-by-break*/ ){
+ if( aCol[i].hName==h
+ && sqlite3StrICmp(aCol[i].zCnName, zCol)==0
+ ){
+ return i;
+ }
+ i++;
+ if( i>=nCol ) break;
}
return -1;
}
diff --git a/src/shell.c.in b/src/shell.c.in
index cad8c92c5..fcc9316b0 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -7337,7 +7337,7 @@ static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
break;
case AR_SWITCH_APPEND:
pAr->bAppend = 1;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case AR_SWITCH_FILE:
pAr->zFile = zArg;
break;
@@ -8725,6 +8725,9 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zName;
int op;
} aDbConfig[] = {
+ { "attach_create", SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE },
+ { "attach_write", SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE },
+ { "comments", SQLITE_DBCONFIG_ENABLE_COMMENTS },
{ "defensive", SQLITE_DBCONFIG_DEFENSIVE },
{ "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
{ "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
@@ -10079,6 +10082,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( zFile==0 ){
zFile = sqlite3_mprintf("stdout");
}
+ shell_check_oom(zFile);
if( bOnce ){
p->outCount = 2;
}else{
@@ -10121,6 +10125,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#else
FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
if( pfPipe==0 ){
+ assert( stderr!=NULL );
sqlite3_fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
rc = 1;
}else{
@@ -10133,7 +10138,8 @@ static int do_meta_command(char *zLine, ShellState *p){
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);
+ assert( stderr!=NULL );
+ sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
}
rc = 1;
} else {
@@ -10237,6 +10243,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
}
}
+ bind_prepared_stmt(p, pStmt);
sqlite3_step(pStmt);
sqlite3_finalize(pStmt);
}else
@@ -11471,6 +11478,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{ 0x04000000, 1, "NullUnusedCols" },
{ 0x08000000, 1, "OnePass" },
{ 0x10000000, 1, "OrderBySubq" },
+ { 0x20000000, 1, "StarQuery" },
{ 0xffffffff, 0, "All" },
};
unsigned int curOpt;
@@ -12025,7 +12033,7 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
break;
case '[':
cin = ']';
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case '`': case '\'': case '"':
cWait = cin;
qss = QSS_HasDark | cWait;
@@ -12060,7 +12068,7 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
++zLine;
continue;
}
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case ']':
CONTINUE_PROMPT_AWAITC(pst, 0);
qss = QSS_SETV(qss, 0);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index d053eb7d7..bf1974a86 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2217,7 +2217,15 @@ struct sqlite3_mem_methods {
** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
-** can be passed as the second argument to the [sqlite3_db_config()] interface.
+** can be passed as the second parameter to the [sqlite3_db_config()] interface.
+**
+** The [sqlite3_db_config()] interface is a var-args functions. It takes a
+** variable number of parameters, though always at least two. The number of
+** parameters passed into sqlite3_db_config() depends on which of these
+** constants is given as the second parameter. This documentation page
+** refers to parameters beyond the second as "arguments". Thus, when this
+** page says "the N-th argument" it means "the N-th parameter past the
+** configuration option" or "the (N+2)-th parameter to sqlite3_db_config()".
**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
@@ -2229,8 +2237,14 @@ struct sqlite3_mem_methods {
** <dl>
** [[SQLITE_DBCONFIG_LOOKASIDE]]
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
-** <dd> ^This option takes three additional arguments that determine the
-** [lookaside memory allocator] configuration for the [database connection].
+** <dd> The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the
+** configuration of the lookaside memory allocator within a database
+** connection.
+** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are <i>not</i>
+** in the [DBCONFIG arguments|usual format].
+** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two,
+** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE
+** should have a total of five parameters.
** ^The first argument (the third parameter to [sqlite3_db_config()] is a
** pointer to a memory buffer to use for lookaside memory.
** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
@@ -2253,7 +2267,8 @@ struct sqlite3_mem_methods {
** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
** <dd> ^This option is used to enable or disable the enforcement of
-** [foreign key constraints]. There should be two additional arguments.
+** [foreign key constraints]. This is the same setting that is
+** enabled or disabled by the [PRAGMA foreign_keys] statement.
** The first argument is an integer which is 0 to disable FK enforcement,
** positive to enable FK enforcement or negative to leave FK enforcement
** unchanged. The second parameter is a pointer to an integer into which
@@ -2275,13 +2290,13 @@ struct sqlite3_mem_methods {
** <p>Originally this option disabled all triggers. ^(However, since
** SQLite version 3.35.0, TEMP triggers are still allowed even if
** this option is off. So, in other words, this option now only disables
-** triggers in the main database schema or in the schemas of ATTACH-ed
+** triggers in the main database schema or in the schemas of [ATTACH]-ed
** databases.)^ </dd>
**
** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
** <dd> ^This option is used to enable or disable [CREATE VIEW | views].
-** There should be two additional arguments.
+** There must be two additional arguments.
** The first argument is an integer which is 0 to disable views,
** positive to enable views or negative to leave the setting unchanged.
** The second parameter is a pointer to an integer into which
@@ -2300,7 +2315,7 @@ struct sqlite3_mem_methods {
** <dd> ^This option is used to enable or disable the
** [fts3_tokenizer()] function which is part of the
** [FTS3] full-text search engine extension.
-** There should be two additional arguments.
+** There must be two additional arguments.
** The first argument is an integer which is 0 to disable fts3_tokenizer() or
** positive to enable fts3_tokenizer() or negative to leave the setting
** unchanged.
@@ -2315,7 +2330,7 @@ struct sqlite3_mem_methods {
** interface independently of the [load_extension()] SQL function.
** The [sqlite3_enable_load_extension()] API enables or disables both the
** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
-** There should be two additional arguments.
+** There must be two additional arguments.
** When the first argument to this interface is 1, then only the C-API is
** enabled and the SQL function remains disabled. If the first argument to
** this interface is 0, then both the C-API and the SQL function are disabled.
@@ -2329,23 +2344,30 @@ struct sqlite3_mem_methods {
**
** [[SQLITE_DBCONFIG_MAINDBNAME]] <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
** <dd> ^This option is used to change the name of the "main" database
-** schema. ^The sole argument is a pointer to a constant UTF8 string
-** which will become the new schema name in place of "main". ^SQLite
-** does not make a copy of the new main schema name string, so the application
-** must ensure that the argument passed into this DBCONFIG option is unchanged
-** until after the database connection closes.
+** schema. This option does not follow the
+** [DBCONFIG arguments|usual SQLITE_DBCONFIG argument format].
+** This option takes exactly one additional argument so that the
+** [sqlite3_db_config()] call has a total of three parameters. The
+** extra argument must be a pointer to a constant UTF8 string which
+** will become the new schema name in place of "main". ^SQLite does
+** not make a copy of the new main schema name string, so the application
+** must ensure that the argument passed into SQLITE_DBCONFIG MAINDBNAME
+** is unchanged until after the database connection closes.
** </dd>
**
** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]]
** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
-** <dd> Usually, when a database in wal mode is closed or detached from a
-** database handle, SQLite checks if this will mean that there are now no
-** connections at all to the database. If so, it performs a checkpoint
-** operation before closing the connection. This option may be used to
-** override this behavior. The first parameter passed to this operation
-** is an integer - positive to disable checkpoints-on-close, or zero (the
-** default) to enable them, and negative to leave the setting unchanged.
-** The second parameter is a pointer to an integer
+** <dd> Usually, when a database in [WAL mode] is closed or detached from a
+** database handle, SQLite checks if if there are other connections to the
+** same database, and if there are no other database connection (if the
+** connection being closed is the last open connection to the database),
+** then SQLite performs a [checkpoint] before closing the connection and
+** deletes the WAL file. The SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE option can
+** be used to override that behavior. The first argument passed to this
+** operation (the third parameter to [sqlite3_db_config()]) is an integer
+** which is positive to disable checkpoints-on-close, or zero (the default)
+** to enable them, and negative to leave the setting unchanged.
+** The second argument (the fourth parameter) is a pointer to an integer
** into which is written 0 or 1 to indicate whether checkpoints-on-close
** have been disabled - 0 if they are not disabled, 1 if they are.
** </dd>
@@ -2506,7 +2528,7 @@ struct sqlite3_mem_methods {
** statistics. For statistics to be collected, the flag must be set on
** the database handle both when the SQL statement is prepared and when it
** is stepped. The flag is set (collection of statistics is enabled)
-** by default. This option takes two arguments: an integer and a pointer to
+** by default. <p>This option takes two arguments: an integer and a pointer to
** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
** leave unchanged the statement scanstatus option. If the second argument
** is not NULL, then the value of the statement scanstatus setting after
@@ -2520,7 +2542,7 @@ struct sqlite3_mem_methods {
** in which tables and indexes are scanned so that the scans start at the end
** and work toward the beginning rather than starting at the beginning and
** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
-** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** same as setting [PRAGMA reverse_unordered_selects]. <p>This option takes
** two arguments which are an integer and a pointer to an integer. The first
** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
** reverse scan order flag, respectively. If the second argument is not NULL,
@@ -2529,7 +2551,76 @@ struct sqlite3_mem_methods {
** first argument.
** </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]]
+** <dt>SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE option enables or disables
+** the ability of the [ATTACH DATABASE] SQL command to create a new database
+** file if the database filed named in the ATTACH command does not already
+** exist. This ability of ATTACH to create a new database is enabled by
+** default. Applications can disable or reenable the ability for ATTACH to
+** create new database files using this DBCONFIG option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the attach-create flag, respectively. If the second
+** argument is not NULL, then 0 or 1 is written into the integer that the
+** second argument points to depending on if the attach-create flag is set
+** after processing the first argument.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE]]
+** <dt>SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE option enables or disables the
+** ability of the [ATTACH DATABASE] SQL command to open a database for writing.
+** This capability is enabled by default. Applications can disable or
+** reenable this capability using the current DBCONFIG option. If the
+** the this capability is disabled, the [ATTACH] command will still work,
+** but the database will be opened read-only. If this option is disabled,
+** then the ability to create a new database using [ATTACH] is also disabled,
+** regardless of the value of the [SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]
+** option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the ability to ATTACH another database for writing,
+** respectively. If the second argument is not NULL, then 0 or 1 is written
+** into the integer to which the second argument points, depending on whether
+** the ability to ATTACH a read/write database is enabled or disabled
+** after processing the first argument.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_COMMENTS]]
+** <dt>SQLITE_DBCONFIG_ENABLE_COMMENTS</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_COMMENTS option enables or disables the
+** ability to include comments in SQL text. Comments are enabled by default.
+** An application can disable or reenable comments in SQL text using this
+** DBCONFIG option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the ability to use comments in SQL text,
+** respectively. If the second argument is not NULL, then 0 or 1 is written
+** into the integer that the second argument points to depending on if
+** comments are allowed in SQL text after processing the first argument.
+** </dd>
+**
** </dl>
+**
+** [[DBCONFIG arguments]] <h3>Arguments To SQLITE_DBCONFIG Options</h3>
+**
+** <p>Most of the SQLITE_DBCONFIG options take two arguments, so that the
+** overall call to [sqlite3_db_config()] has a total of four parameters.
+** The first argument (the third parameter to sqlite3_db_config()) is a integer.
+** The second argument is a pointer to an integer. If the first argument is 1,
+** then the option becomes enabled. If the first integer argument is 0, then the
+** option is disabled. If the first argument is -1, then the option setting
+** is unchanged. The second argument, the pointer to an integer, may be NULL.
+** If the second argument is not NULL, then a value of 0 or 1 is written into
+** the integer to which the second argument points, depending on whether the
+** setting is disabled or enabled after applying any changes specified by
+** the first argument.
+**
+** <p>While most SQLITE_DBCONFIG options use the argument format
+** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME]
+** and [SQLITE_DBCONFIG_LOOKASIDE] options are different. See the
+** documentation of those exceptional options for details.
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
@@ -2551,7 +2642,10 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1022 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -10792,8 +10886,9 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
/*
** CAPI3REF: Serialize a database
**
-** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory
-** that is a serialization of the S database on [database connection] D.
+** The sqlite3_serialize(D,S,P,F) interface returns a pointer to
+** memory that is a serialization of the S database on
+** [database connection] D. If S is a NULL pointer, the main database is used.
** If P is not a NULL pointer, then the size of the database in bytes
** is written into *P.
**
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index f56625cef..336c3a583 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -843,6 +843,11 @@ typedef INT16_TYPE i16; /* 2-byte signed integer */
typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
typedef INT8_TYPE i8; /* 1-byte signed integer */
+/* A bitfield type for use inside of structures. Always follow with :N where
+** N is the number of bits.
+*/
+typedef unsigned bft; /* Bit Field Type */
+
/*
** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value
** that can be stored in a u32 without loss of data. The value
@@ -881,6 +886,8 @@ typedef u64 tRowcnt;
** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
*/
typedef INT16_TYPE LogEst;
+#define LOGEST_MIN (-32768)
+#define LOGEST_MAX (32767)
/*
** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer
@@ -1151,7 +1158,7 @@ extern u32 sqlite3WhereTrace;
** 0xFFFF---- Low-level debug messages
**
** 0x00000001 Code generation
-** 0x00000002 Solver
+** 0x00000002 Solver (Use 0x40000 for less detail)
** 0x00000004 Solver costs
** 0x00000008 WhereLoop inserts
**
@@ -1170,6 +1177,8 @@ extern u32 sqlite3WhereTrace;
**
** 0x00010000 Show more detail when printing WHERE terms
** 0x00020000 Show WHERE terms returned from whereScanNext()
+** 0x00040000 Solver overview messages
+** 0x00080000 Star-query heuristic
*/
@@ -1834,6 +1843,9 @@ struct sqlite3 {
#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */
#define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */
+#define SQLITE_AttachCreate HI(0x00010) /* ATTACH allowed to create new dbs */
+#define SQLITE_AttachWrite HI(0x00020) /* ATTACH allowed to open for write */
+#define SQLITE_Comments HI(0x00040) /* Enable SQL comments */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
@@ -1893,6 +1905,7 @@ struct sqlite3 {
#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */
#define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */
+#define SQLITE_StarQuery 0x20000000 /* Heurists for star queries */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -2422,6 +2435,7 @@ struct Table {
} u;
Trigger *pTrigger; /* List of triggers on this object */
Schema *pSchema; /* Schema that contains this table */
+ u8 aHx[16]; /* Column aHt[K%sizeof(aHt)] might have hash K */
};
/*
@@ -3222,13 +3236,8 @@ struct ExprList {
*/
struct IdList {
int nId; /* Number of identifiers on the list */
- u8 eU4; /* Which element of a.u4 is valid */
struct IdList_item {
char *zName; /* Name of the identifier */
- union {
- int idx; /* Index in some Table.aCol[] of a column named zName */
- Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */
- } u4;
} a[1];
};
@@ -3824,25 +3833,32 @@ struct Parse {
char *zErrMsg; /* An error message */
Vdbe *pVdbe; /* An engine for executing database bytecode */
int rc; /* Return code from execution */
- u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
- u8 checkSchema; /* Causes schema cookie check after an error */
+ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u8 nested; /* Number of nested calls to the parser/code generator */
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
u8 mayAbort; /* True if statement may throw an ABORT exception */
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
- u8 okConstFactor; /* OK to factor out constants */
u8 disableLookaside; /* Number of times lookaside has been disabled */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
- u8 bHasWith; /* True if statement contains WITH */
u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */
+ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
+ u8 bReturning; /* Coding a RETURNING trigger */
+ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
+ u8 disableTriggers; /* True to disable triggers */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
#endif
#ifdef SQLITE_DEBUG
u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */
+ u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER)
+ ** and ALTER TABLE ADD COLUMN. */
#endif
+ bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */
+ bft bHasWith :1; /* True if statement contains WITH */
+ bft okConstFactor :1; /* OK to factor out constants */
+ bft checkSchema :1; /* Causes schema cookie check after an error */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
@@ -3857,12 +3873,9 @@ struct Parse {
ExprList *pConstExpr;/* Constant expressions */
IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */
- Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
- int regRowid; /* Register holding rowid of CREATE TABLE entry */
- int regRoot; /* Register holding root page number for new objects */
- int nMaxArg; /* Max args passed to user function by sub-program */
+ int nMaxArg; /* Max args to xUpdate and xFilter vtab methods */
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
@@ -3876,17 +3889,6 @@ struct Parse {
Table *pTriggerTab; /* Table triggers are being coded for */
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */
- union {
- int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
- Returning *pReturning; /* The RETURNING clause */
- } u1;
- u32 oldmask; /* Mask of old.* columns referenced */
- u32 newmask; /* Mask of new.* columns referenced */
- LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
- u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
- u8 bReturning; /* Coding a RETURNING trigger */
- u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
- u8 disableTriggers; /* True to disable triggers */
/**************************************************************************
** Fields above must be initialized to zero. The fields that follow,
@@ -3898,6 +3900,19 @@ struct Parse {
int aTempReg[8]; /* Holding area for temporary registers */
Parse *pOuterParse; /* Outer Parse object when nested */
Token sNameToken; /* Token with unqualified schema object name */
+ u32 oldmask; /* Mask of old.* columns referenced */
+ u32 newmask; /* Mask of new.* columns referenced */
+ union {
+ struct { /* These fields available when isCreate is true */
+ int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
+ int regRowid; /* Register holding rowid of CREATE TABLE entry */
+ int regRoot; /* Register holding root page for new objects */
+ Token constraintName; /* Name of the constraint currently being parsed */
+ } cr;
+ struct { /* These fields available to all other statements */
+ Returning *pReturning; /* The RETURNING clause */
+ } d;
+ } u1;
/************************************************************************
** Above is constant between recursions. Below is reset before and after
@@ -3915,9 +3930,7 @@ struct Parse {
int nVtabLock; /* Number of virtual tables to lock */
#endif
int nHeight; /* Expression tree height of current sub-select */
-#ifndef SQLITE_OMIT_EXPLAIN
int addrExplain; /* Address of current OP_Explain opcode */
-#endif
VList *pVList; /* Mapping between variable names and numbers */
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
const char *zTail; /* All SQL text past the last semicolon parsed */
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index f0b5c3e81..824e8c4d3 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -341,7 +341,7 @@ static int SQLITE_TCLAPI incrblobInput(
*/
static int SQLITE_TCLAPI incrblobOutput(
ClientData instanceData,
- CONST char *buf,
+ const char *buf,
int toWrite,
int *errorCodePtr
){
@@ -510,7 +510,7 @@ static int createIncrblobChannel(
** or {...} or ; to be seen anywhere. Most callback scripts consist
** of just a single procedure name and they meet this requirement.
*/
-static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
+static int safeToUseEvalObjv(Tcl_Obj *pCmd){
/* We could try to do something with Tcl_Parse(). But we will instead
** just do a search for forbidden characters. If any of the forbidden
** characters appear in pCmd, we will report the string as unsafe.
@@ -1097,7 +1097,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
/* Only return a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
eType = SQLITE_BLOB;
- }else if( (c=='b' && strcmp(zType,"boolean")==0)
+ }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)
){
@@ -1505,9 +1506,12 @@ static int dbPrepareAndBind(
sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
pPreStmt->apParm[iParm++] = pVar;
- }else if( c=='b' && strcmp(zType,"boolean")==0 ){
+ }else if( c=='b' && pVar->bytes==0
+ && (strcmp(zType,"booleanString")==0
+ || strcmp(zType,"boolean")==0)
+ ){
int nn;
- Tcl_GetIntFromObj(interp, pVar, &nn);
+ Tcl_GetBooleanFromObj(interp, pVar, &nn);
sqlite3_bind_int(pStmt, i, nn);
}else if( c=='d' && strcmp(zType,"double")==0 ){
double r;
@@ -1843,7 +1847,8 @@ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){
** are 8.6 or newer, the code still tests the Tcl version at runtime.
** This allows stubs-enabled builds to be used with older Tcl libraries.
*/
-#if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6)
+#if TCL_MAJOR_VERSION>8 || !defined(TCL_MINOR_VERSION) \
+ || TCL_MINOR_VERSION>=6
# define SQLITE_TCL_NRE 1
static int DbUseNre(void){
int major, minor;
@@ -1959,7 +1964,7 @@ static void DbHookCmd(
}
if( pArg ){
assert( !(*ppHook) );
- if( Tcl_GetCharLength(pArg)>0 ){
+ if( Tcl_GetString(pArg)[0] ){
*ppHook = pArg;
Tcl_IncrRefCount(*ppHook);
}
@@ -2988,7 +2993,7 @@ deserialize_error:
}
pFunc->pScript = pScript;
Tcl_IncrRefCount(pScript);
- pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
+ pFunc->useEvalObjv = safeToUseEvalObjv(pScript);
pFunc->eType = eType;
rc = sqlite3_create_function(pDb->db, zName, nArg, flags,
pFunc, tclSqlFunc, 0, 0);
@@ -4016,7 +4021,9 @@ EXTERN int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
EXTERN int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}
-/* Also variants with a lowercase "s" */
+/* Also variants with a lowercase "s". I'm told that these are
+** deprecated in Tcl9, but they continue to be included for backwards
+** compatibility. */
EXTERN int sqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
EXTERN int sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
diff --git a/src/test1.c b/src/test1.c
index a0ca93d10..e45a05fe4 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -600,6 +600,7 @@ static int SQLITE_TCLAPI test_get_table_printf(
}
sqlite3_free(zSql);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
+ Tcl_ResetResult(interp);
Tcl_AppendElement(interp, zBuf);
if( rc==SQLITE_OK ){
if( argc==4 ){
@@ -5680,9 +5681,11 @@ static int SQLITE_TCLAPI test_stmt_utf8(
sqlite3_stmt *pStmt;
int col;
const char *(*xFunc)(sqlite3_stmt*, int);
+ const unsigned char *(*xFuncU)(sqlite3_stmt*, int);
const char *zRet;
xFunc = (const char *(*)(sqlite3_stmt*, int))clientData;
+ xFuncU = (const unsigned char*(*)(sqlite3_stmt*,int))xFunc;
if( objc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]), " STMT column", 0);
@@ -5691,7 +5694,11 @@ static int SQLITE_TCLAPI test_stmt_utf8(
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
- zRet = xFunc(pStmt, col);
+ if( xFunc==sqlite3_column_name || xFunc==sqlite3_column_decltype ){
+ zRet = xFunc(pStmt, col);
+ }else{
+ zRet = (const char*)xFuncU(pStmt, col);
+ }
if( zRet ){
Tcl_SetResult(interp, (char *)zRet, 0);
}
@@ -7588,12 +7595,16 @@ static int SQLITE_TCLAPI test_wal_autocheckpoint(
/*
** tclcmd: test_sqlite3_log ?SCRIPT?
+**
+** Caution: If you register a log callback, you must deregister it (by
+** invoking test_sqlite3_log with no arguments) prior to closing the
+** Tcl interpreter or else a memory error will occur.
*/
static struct LogCallback {
Tcl_Interp *pInterp;
Tcl_Obj *pObj;
} logcallback = {0, 0};
-static void xLogcallback(void *unused, int err, char *zMsg){
+static void xLogcallback(void *unused, int err, const char *zMsg){
Tcl_Obj *pNew = Tcl_DuplicateObj(logcallback.pObj);
Tcl_IncrRefCount(pNew);
Tcl_ListObjAppendElement(
@@ -7619,7 +7630,7 @@ static int SQLITE_TCLAPI test_sqlite3_log(
logcallback.pInterp = 0;
sqlite3_config(SQLITE_CONFIG_LOG, (void*)0, (void*)0);
}
- if( objc>1 ){
+ if( objc>1 && Tcl_GetString(objv[1])[0]!=0 ){
logcallback.pObj = objv[1];
Tcl_IncrRefCount(logcallback.pObj);
logcallback.pInterp = interp;
@@ -8655,7 +8666,6 @@ static int SQLITE_TCLAPI test_decode_hexdb(
const char *zIn = 0;
unsigned char *a = 0;
int n = 0;
- int lineno = 0;
int i, iNext;
int iOffset = 0;
int j, k;
@@ -8667,7 +8677,6 @@ static int SQLITE_TCLAPI test_decode_hexdb(
}
zIn = Tcl_GetString(objv[1]);
for(i=0; zIn[i]; i=iNext){
- lineno++;
for(iNext=i; zIn[iNext] && zIn[iNext]!='\n'; iNext++){}
if( zIn[iNext]=='\n' ) iNext++;
while( zIn[i]==' ' || zIn[i]=='\t' ){ i++; }
diff --git a/src/test_intarray.c b/src/test_intarray.c
index 16c1df2e9..9e4629467 100644
--- a/src/test_intarray.c
+++ b/src/test_intarray.c
@@ -61,7 +61,8 @@ struct intarray_cursor {
/*
** Free an sqlite3_intarray object.
*/
-static void intarrayFree(sqlite3_intarray *p){
+static void intarrayFree(void *pX){
+ sqlite3_intarray *p = (sqlite3_intarray*)pX;
if( p->xFree ){
p->xFree(p->a);
}
diff --git a/src/test_malloc.c b/src/test_malloc.c
index 21faa0d29..8d6c4fa50 100644
--- a/src/test_malloc.c
+++ b/src/test_malloc.c
@@ -41,8 +41,9 @@ static struct MemFault {
** fire on any simulated malloc() failure.
*/
static void sqlite3Fault(void){
- static int cnt = 0;
+ static u64 cnt = 0;
cnt++;
+ if( cnt>((u64)1<<63) ) abort();
}
/*
@@ -52,8 +53,9 @@ static void sqlite3Fault(void){
** This routine only runs on the first such failure.
*/
static void sqlite3FirstFault(void){
- static int cnt2 = 0;
+ static u64 cnt2 = 0;
cnt2++;
+ if( cnt2>((u64)1<<63) ) abort();
}
/*
diff --git a/src/tokenize.c b/src/tokenize.c
index b49b2aa16..fe300ca52 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -288,7 +288,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
case CC_MINUS: {
if( z[1]=='-' ){
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
- *tokenType = TK_SPACE; /* IMP: R-22934-25134 */
+ *tokenType = TK_COMMENT;
return i;
}else if( z[1]=='>' ){
*tokenType = TK_PTR;
@@ -324,7 +324,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
if( c ) i++;
- *tokenType = TK_SPACE; /* IMP: R-22934-25134 */
+ *tokenType = TK_COMMENT;
return i;
}
case CC_PERCENT: {
@@ -653,12 +653,12 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
if( tokenType>=TK_WINDOW ){
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|| tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
- || tokenType==TK_QNUMBER
+ || tokenType==TK_QNUMBER || tokenType==TK_COMMENT
);
#else
if( tokenType>=TK_SPACE ){
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL
- || tokenType==TK_QNUMBER
+ || tokenType==TK_QNUMBER || tokenType==TK_COMMENT
);
#endif /* SQLITE_OMIT_WINDOWFUNC */
if( AtomicLoad(&db->u1.isInterrupted) ){
@@ -692,6 +692,9 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
+ }else if( tokenType==TK_COMMENT && (db->flags & SQLITE_Comments)!=0 ){
+ zSql += n;
+ continue;
}else if( tokenType!=TK_QNUMBER ){
Token x;
x.z = zSql;
@@ -798,6 +801,7 @@ char *sqlite3Normalize(
n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType);
if( NEVER(n<=0) ) break;
switch( tokenType ){
+ case TK_COMMENT:
case TK_SPACE: {
break;
}
diff --git a/src/treeview.c b/src/treeview.c
index 30592d35b..832965924 100644
--- a/src/treeview.c
+++ b/src/treeview.c
@@ -215,7 +215,10 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
sqlite3_str_appendf(&x, " DDL");
}
if( pItem->fg.isCte ){
- sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
+ static const char *aMat[] = {",MAT", "", ",NO-MAT"};
+ sqlite3_str_appendf(&x, " CteUse=%d%s",
+ pItem->u2.pCteUse->nUse,
+ aMat[pItem->u2.pCteUse->eM10d]);
}
if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
sqlite3_str_appendf(&x, " isOn");
@@ -246,9 +249,6 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
}
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
- sqlite3TreeViewPush(&pView, 0);
- sqlite3TreeViewLine(pView, "SUBQUERY");
- sqlite3TreeViewPop(&pView);
sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0);
}
if( pItem->fg.isTabFunc ){
@@ -978,21 +978,7 @@ void sqlite3TreeViewBareIdList(
if( zName==0 ) zName = "(null)";
sqlite3TreeViewPush(&pView, moreToFollow);
sqlite3TreeViewLine(pView, 0);
- if( pList->eU4==EU4_NONE ){
- fprintf(stdout, "%s\n", zName);
- }else if( pList->eU4==EU4_IDX ){
- fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx);
- }else{
- assert( pList->eU4==EU4_EXPR );
- if( pList->a[i].u4.pExpr==0 ){
- fprintf(stdout, "%s (pExpr=NULL)\n", zName);
- }else{
- fprintf(stdout, "%s\n", zName);
- sqlite3TreeViewPush(&pView, i<pList->nId-1);
- sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0);
- sqlite3TreeViewPop(&pView);
- }
- }
+ fprintf(stdout, "%s\n", zName);
sqlite3TreeViewPop(&pView);
}
}
diff --git a/src/trigger.c b/src/trigger.c
index e306a2e66..604c3ab42 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -70,7 +70,8 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
assert( pParse->db->pVtabCtx==0 );
#endif
assert( pParse->bReturning );
- assert( &(pParse->u1.pReturning->retTrig) == pTrig );
+ assert( !pParse->isCreate );
+ assert( &(pParse->u1.d.pReturning->retTrig) == pTrig );
pTrig->table = pTab->zName;
pTrig->pTabSchema = pTab->pSchema;
pTrig->pNext = pList;
@@ -1047,7 +1048,8 @@ static void codeReturningTrigger(
return;
}
assert( db->pParse==pParse );
- pReturning = pParse->u1.pReturning;
+ assert( !pParse->isCreate );
+ pReturning = pParse->u1.d.pReturning;
if( pTrigger != &(pReturning->retTrig) ){
/* This RETURNING trigger is for a different statement */
return;
@@ -1277,6 +1279,8 @@ static TriggerPrg *codeRowTrigger(
sSubParse.eTriggerOp = pTrigger->op;
sSubParse.nQueryLoop = pParse->nQueryLoop;
sSubParse.prepFlags = pParse->prepFlags;
+ sSubParse.oldmask = 0;
+ sSubParse.newmask = 0;
v = sqlite3GetVdbe(&sSubParse);
if( v ){
diff --git a/src/update.c b/src/update.c
index a8e7f7780..979afea1f 100644
--- a/src/update.c
+++ b/src/update.c
@@ -465,38 +465,32 @@ void sqlite3Update(
*/
chngRowid = chngPk = 0;
for(i=0; i<pChanges->nExpr; i++){
- u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName);
/* If this is an UPDATE with a FROM clause, do not resolve expressions
** here. The call to sqlite3Select() below will do that. */
if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
goto update_cleanup;
}
- for(j=0; j<pTab->nCol; j++){
- if( pTab->aCol[j].hName==hCol
- && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0
- ){
- if( j==pTab->iPKey ){
- chngRowid = 1;
- pRowidExpr = pChanges->a[i].pExpr;
- iRowidExpr = i;
- }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
- chngPk = 1;
- }
+ j = sqlite3ColumnIndex(pTab, pChanges->a[i].zEName);
+ if( j>=0 ){
+ if( j==pTab->iPKey ){
+ chngRowid = 1;
+ pRowidExpr = pChanges->a[i].pExpr;
+ iRowidExpr = i;
+ }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
+ chngPk = 1;
+ }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
- else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){
- testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL );
- testcase( pTab->aCol[j].colFlags & COLFLAG_STORED );
- sqlite3ErrorMsg(pParse,
- "cannot UPDATE generated column \"%s\"",
- pTab->aCol[j].zCnName);
- goto update_cleanup;
- }
-#endif
- aXRef[j] = i;
- break;
+ else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){
+ testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL );
+ testcase( pTab->aCol[j].colFlags & COLFLAG_STORED );
+ sqlite3ErrorMsg(pParse,
+ "cannot UPDATE generated column \"%s\"",
+ pTab->aCol[j].zCnName);
+ goto update_cleanup;
}
- }
- if( j>=pTab->nCol ){
+#endif
+ aXRef[j] = i;
+ }else{
if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){
j = -1;
chngRowid = 1;
diff --git a/src/util.c b/src/util.c
index ecce460e0..703ef0a23 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1130,7 +1130,11 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
}
p->z = &p->zBuf[i+1];
assert( i+p->n < sizeof(p->zBuf) );
- while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
+ assert( p->n>0 );
+ while( p->z[p->n-1]=='0' ){
+ p->n--;
+ assert( p->n>0 );
+ }
}
/*
diff --git a/src/vdbe.c b/src/vdbe.c
index 558970ed9..ec871c5a6 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -607,6 +607,7 @@ static void registerTrace(int iReg, Mem *p){
printf("R[%d] = ", iReg);
memTracePrint(p);
if( p->pScopyFrom ){
+ assert( p->pScopyFrom->bScopy );
printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg]));
}
printf("\n");
@@ -1590,6 +1591,7 @@ case OP_Move: {
{ int i;
for(i=1; i<p->nMem; i++){
if( aMem[i].pScopyFrom==pIn1 ){
+ assert( aMem[i].bScopy );
aMem[i].pScopyFrom = pOut;
}
}
@@ -1662,6 +1664,7 @@ case OP_SCopy: { /* out2 */
#ifdef SQLITE_DEBUG
pOut->pScopyFrom = pIn1;
pOut->mScopyFlags = pIn1->flags;
+ pIn1->bScopy = 1;
#endif
break;
}
@@ -8360,6 +8363,7 @@ case OP_VFilter: { /* jump, ncycle */
/* Invoke the xFilter method */
apArg = p->apArg;
+ assert( nArg<=p->napArg );
for(i = 0; i<nArg; i++){
apArg[i] = &pArgc[i+1];
}
@@ -8570,6 +8574,7 @@ case OP_VUpdate: {
u8 vtabOnConflict = db->vtabOnConflict;
apArg = p->apArg;
pX = &aMem[pOp->p3];
+ assert( nArg<=p->napArg );
for(i=0; i<nArg; i++){
assert( memIsValid(pX) );
memAboutToChange(p, pX);
diff --git a/src/vdbe.h b/src/vdbe.h
index 71aae29a0..476f1b4ea 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -40,6 +40,7 @@ typedef struct SubrtnSig SubrtnSig;
*/
struct SubrtnSig {
int selId; /* SELECT-id for the SELECT statement on the RHS */
+ u8 bComplete; /* True if fully coded and available for reusable */
char *zAff; /* Affinity of the overall IN expression */
int iTable; /* Ephemeral table generated by the subroutine */
int iAddr; /* Subroutine entry address */
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 2cb4f8c2a..12af82726 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -244,6 +244,7 @@ struct sqlite3_value {
#ifdef SQLITE_DEBUG
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
u16 mScopyFlags; /* flags value immediately after the shallow copy */
+ u8 bScopy; /* The pScopyFrom of some other Mem *might* point here */
#endif
};
@@ -397,10 +398,6 @@ struct sqlite3_context {
sqlite3_value *argv[1]; /* Argument set */
};
-/* A bitfield type for use inside of structures. Always follow with :N where
-** N is the number of bits.
-*/
-typedef unsigned bft; /* Bit Field Type */
/* The ScanStatus object holds a single value for the
** sqlite3_stmt_scanstatus() interface.
@@ -461,7 +458,7 @@ struct Vdbe {
i64 nStmtDefCons; /* Number of def. constraints when stmt started */
i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
Mem *aMem; /* The memory locations */
- Mem **apArg; /* Arguments to currently executing user function */
+ Mem **apArg; /* Arguments xUpdate and xFilter vtab methods */
VdbeCursor **apCsr; /* One element of this array for each open cursor */
Mem *aVar; /* Values for the OP_Variable opcode. */
@@ -481,6 +478,7 @@ struct Vdbe {
#ifdef SQLITE_DEBUG
int rcApp; /* errcode set by sqlite3_result_error_code() */
u32 nWrite; /* Number of write operations that have occurred */
+ int napArg; /* Size of the apArg[] array */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u16 nResAlloc; /* Column slots allocated to aColName[] */
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index e33cb2e4d..0dc09d501 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -63,7 +63,6 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
sqlite3_int64 iNow;
sqlite3_int64 iElapse;
assert( p->startTime>0 );
- assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 );
assert( db->init.busy==0 );
assert( p->zSql!=0 );
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
@@ -783,7 +782,7 @@ static int sqlite3Step(Vdbe *p){
}
assert( db->nVdbeWrite>0 || db->autoCommit==0
- || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
+ || ((db->nDeferredCons + db->nDeferredImmCons)==0)
);
#ifndef SQLITE_OMIT_TRACE
@@ -1294,6 +1293,7 @@ static const Mem *columnNullValue(void){
#ifdef SQLITE_DEBUG
/* .pScopyFrom = */ (Mem*)0,
/* .mScopyFlags= */ 0,
+ /* .bScopy = */ 0,
#endif
};
return &nullMem;
@@ -2176,6 +2176,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
PreUpdate *p;
Mem *pMem;
int rc = SQLITE_OK;
+ int iStore = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( db==0 || ppValue==0 ){
@@ -2190,9 +2191,11 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
goto preupdate_old_out;
}
if( p->pPk ){
- iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ iStore = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ }else{
+ iStore = sqlite3TableColumnToStorage(p->pTab, iIdx);
}
- if( iIdx>=p->pCsr->nField || iIdx<0 ){
+ if( iStore>=p->pCsr->nField || iStore<0 ){
rc = SQLITE_RANGE;
goto preupdate_old_out;
}
@@ -2223,8 +2226,8 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
p->aRecord = aRec;
}
- pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
- if( iIdx>=p->pUnpacked->nField ){
+ pMem = *ppValue = &p->pUnpacked->aMem[iStore];
+ if( iStore>=p->pUnpacked->nField ){
/* This occurs when the table has been extended using ALTER TABLE
** ADD COLUMN. The value to return is the default value of the column. */
Column *pCol = &p->pTab->aCol[iIdx];
@@ -2328,6 +2331,7 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
PreUpdate *p;
int rc = SQLITE_OK;
Mem *pMem;
+ int iStore = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( db==0 || ppValue==0 ){
@@ -2340,9 +2344,12 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
goto preupdate_new_out;
}
if( p->pPk && p->op!=SQLITE_UPDATE ){
- iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ iStore = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ }else{
+ iStore = sqlite3TableColumnToStorage(p->pTab, iIdx);
}
- if( iIdx>=p->pCsr->nField || iIdx<0 ){
+
+ if( iStore>=p->pCsr->nField || iStore<0 ){
rc = SQLITE_RANGE;
goto preupdate_new_out;
}
@@ -2362,14 +2369,14 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
}
p->pNewUnpacked = pUnpack;
}
- pMem = &pUnpack->aMem[iIdx];
+ pMem = &pUnpack->aMem[iStore];
if( iIdx==p->pTab->iPKey ){
sqlite3VdbeMemSetInt64(pMem, p->iKey2);
- }else if( iIdx>=pUnpack->nField ){
+ }else if( iStore>=pUnpack->nField ){
pMem = (sqlite3_value *)columnNullValue();
}
}else{
- /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
+ /* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required
** value. Make a copy of the cell contents and return a pointer to it.
** It is not safe to return a pointer to the memory cell itself as the
** caller may modify the value text encoding.
@@ -2382,13 +2389,13 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
goto preupdate_new_out;
}
}
- assert( iIdx>=0 && iIdx<p->pCsr->nField );
- pMem = &p->aNew[iIdx];
+ assert( iStore>=0 && iStore<p->pCsr->nField );
+ pMem = &p->aNew[iStore];
if( pMem->flags==0 ){
if( iIdx==p->pTab->iPKey ){
sqlite3VdbeMemSetInt64(pMem, p->iKey2);
}else{
- rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
+ rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iStore]);
if( rc!=SQLITE_OK ) goto preupdate_new_out;
}
}
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 4414f7a2e..cf661eb9c 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -856,8 +856,8 @@ void sqlite3VdbeAssertAbortable(Vdbe *p){
** (1) For each jump instruction with a negative P2 value (a label)
** resolve the P2 value to an actual address.
**
-** (2) Compute the maximum number of arguments used by any SQL function
-** and store that value in *pMaxFuncArgs.
+** (2) Compute the maximum number of arguments used by the xUpdate/xFilter
+** methods of any virtual table and store that value in *pMaxVtabArgs.
**
** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately
** indicate what the prepared statement actually does.
@@ -870,8 +870,8 @@ void sqlite3VdbeAssertAbortable(Vdbe *p){
** script numbers the opcodes correctly. Changes to this routine must be
** coordinated with changes to mkopcodeh.tcl.
*/
-static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
- int nMaxArgs = *pMaxFuncArgs;
+static void resolveP2Values(Vdbe *p, int *pMaxVtabArgs){
+ int nMaxVtabArgs = *pMaxVtabArgs;
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
@@ -916,15 +916,19 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
- if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
+ if( pOp->p2>nMaxVtabArgs ) nMaxVtabArgs = pOp->p2;
break;
}
case OP_VFilter: {
int n;
+ /* The instruction immediately prior to VFilter will be an
+ ** OP_Integer that sets the "argc" value for the VFilter. See
+ ** the code where OP_VFilter is generated at tag-20250207a. */
assert( (pOp - p->aOp) >= 3 );
assert( pOp[-1].opcode==OP_Integer );
+ assert( pOp[-1].p2==pOp->p3+1 );
n = pOp[-1].p1;
- if( n>nMaxArgs ) nMaxArgs = n;
+ if( n>nMaxVtabArgs ) nMaxVtabArgs = n;
/* Fall through into the default case */
/* no break */ deliberate_fall_through
}
@@ -965,7 +969,7 @@ resolve_p2_values_loop_exit:
pParse->aLabel = 0;
}
pParse->nLabel = 0;
- *pMaxFuncArgs = nMaxArgs;
+ *pMaxVtabArgs = nMaxVtabArgs;
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
}
@@ -2144,6 +2148,7 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
** will be initialized before use.
*/
static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
+ assert( db!=0 );
if( N>0 ){
do{
p->flags = flags;
@@ -2151,6 +2156,7 @@ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
p->szMalloc = 0;
#ifdef SQLITE_DEBUG
p->pScopyFrom = 0;
+ p->bScopy = 0;
#endif
p++;
}while( (--N)>0 );
@@ -2169,6 +2175,7 @@ static void releaseMemArray(Mem *p, int N){
if( p && N ){
Mem *pEnd = &p[N];
sqlite3 *db = p->db;
+ assert( db!=0 );
if( db->pnBytesFreed ){
do{
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
@@ -2640,7 +2647,7 @@ void sqlite3VdbeMakeReady(
int nVar; /* Number of parameters */
int nMem; /* Number of VM memory registers */
int nCursor; /* Number of cursors required */
- int nArg; /* Number of arguments in subprograms */
+ int nArg; /* Max number args to xFilter or xUpdate */
int n; /* Loop counter */
struct ReusableSpace x; /* Reusable bulk memory */
@@ -2649,6 +2656,7 @@ void sqlite3VdbeMakeReady(
assert( pParse!=0 );
assert( p->eVdbeState==VDBE_INIT_STATE );
assert( pParse==p->pParse );
+ assert( pParse->db==p->db );
p->pVList = pParse->pVList;
pParse->pVList = 0;
db = p->db;
@@ -2711,6 +2719,9 @@ void sqlite3VdbeMakeReady(
p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
}
}
+#ifdef SQLITE_DEBUG
+ p->napArg = nArg;
+#endif
if( db->mallocFailed ){
p->nVar = 0;
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index 6cb36da37..79698d0af 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -192,12 +192,8 @@ int sqlite3_blob_open(
pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
/* Now search pTab for the exact column. */
- for(iCol=0; iCol<pTab->nCol; iCol++) {
- if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){
- break;
- }
- }
- if( iCol==pTab->nCol ){
+ iCol = sqlite3ColumnIndex(pTab, zColumn);
+ if( iCol<0 ){
sqlite3DbFree(db, zErr);
zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);
rc = SQLITE_ERROR;
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 0fc6b68f5..61298d10f 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -327,7 +327,7 @@ void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){
return;
}
if( pMem->enc!=SQLITE_UTF8 ) return;
- if( NEVER(pMem->z==0) ) return;
+ assert( pMem->z!=0 );
if( pMem->flags & MEM_Dyn ){
if( pMem->xDel==sqlite3_free
&& sqlite3_msize(pMem->z) >= (u64)(pMem->n+1)
@@ -1046,27 +1046,30 @@ int sqlite3VdbeMemTooBig(Mem *p){
void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
int i;
Mem *pX;
- for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){
- if( pX->pScopyFrom==pMem ){
- u16 mFlags;
- if( pVdbe->db->flags & SQLITE_VdbeTrace ){
- sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n",
- (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem));
+ if( pMem->bScopy ){
+ for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){
+ if( pX->pScopyFrom==pMem ){
+ u16 mFlags;
+ if( pVdbe->db->flags & SQLITE_VdbeTrace ){
+ sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n",
+ (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem));
+ }
+ /* If pX is marked as a shallow copy of pMem, then try to verify that
+ ** no significant changes have been made to pX since the OP_SCopy.
+ ** A significant change would indicated a missed call to this
+ ** function for pX. Minor changes, such as adding or removing a
+ ** dual type, are allowed, as long as the underlying value is the
+ ** same. */
+ mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
+ assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i );
+
+ /* pMem is the register that is changing. But also mark pX as
+ ** undefined so that we can quickly detect the shallow-copy error */
+ pX->flags = MEM_Undefined;
+ pX->pScopyFrom = 0;
}
- /* If pX is marked as a shallow copy of pMem, then try to verify that
- ** no significant changes have been made to pX since the OP_SCopy.
- ** A significant change would indicated a missed call to this
- ** function for pX. Minor changes, such as adding or removing a
- ** dual type, are allowed, as long as the underlying value is the
- ** same. */
- mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
- assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i );
-
- /* pMem is the register that is changing. But also mark pX as
- ** undefined so that we can quickly detect the shallow-copy error */
- pX->flags = MEM_Undefined;
- pX->pScopyFrom = 0;
}
+ pMem->bScopy = 0;
}
pMem->pScopyFrom = 0;
}
diff --git a/src/vtab.c b/src/vtab.c
index 76ad3613e..e40f60873 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -479,11 +479,12 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
** schema table. We just need to update that slot with all
** the information we've collected.
**
- ** The VM register number pParse->regRowid holds the rowid of an
+ ** The VM register number pParse->u1.cr.regRowid holds the rowid of an
** entry in the sqlite_schema table that was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( pParse->isCreate );
sqlite3NestedParse(pParse,
"UPDATE %Q." LEGACY_SCHEMA_TABLE " "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
@@ -492,7 +493,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
pTab->zName,
pTab->zName,
zStmt,
- pParse->regRowid
+ pParse->u1.cr.regRowid
);
v = sqlite3GetVdbe(pParse);
sqlite3ChangeCookie(pParse, iDb);
@@ -830,7 +831,9 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
z = (const unsigned char*)zCreateTable;
for(i=0; aKeyword[i]; i++){
int tokenType = 0;
- do{ z += sqlite3GetToken(z, &tokenType); }while( tokenType==TK_SPACE );
+ do{
+ z += sqlite3GetToken(z, &tokenType);
+ }while( tokenType==TK_SPACE || tokenType==TK_COMMENT );
if( tokenType!=aKeyword[i] ){
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "syntax error");
return SQLITE_ERROR;
diff --git a/src/where.c b/src/where.c
index c9698699b..5cb52b8ad 100644
--- a/src/where.c
+++ b/src/where.c
@@ -860,6 +860,11 @@ static int constraintCompatibleWithOuterJoin(
** more than 20, then return false.
**
** 3. If no disqualifying conditions above are found, return true.
+**
+** 2025-01-03: I experimented with a new rule that returns false if the
+** the datatype of the column is "BOOLEAN". This did not improve
+** performance on any queries at hand, but it did burn CPU cycles, so the
+** idea was not committed.
*/
static SQLITE_NOINLINE int columnIsGoodIndexCandidate(
const Table *pTab,
@@ -944,7 +949,7 @@ static void explainAutomaticIndex(
sqlite3_str *pStr = sqlite3_str_new(pParse->db);
sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName);
assert( pIdx->nColumn>1 );
- assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID );
+ assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID || !HasRowid(pTab) );
for(ii=0; ii<(pIdx->nColumn-1); ii++){
const char *zName = 0;
int iCol = pIdx->aiColumn[ii];
@@ -1075,6 +1080,19 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
}else{
extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
}
+ if( !HasRowid(pTable) ){
+ /* For WITHOUT ROWID tables, ensure that all PRIMARY KEY columns are
+ ** either in the idxCols mask or in the extraCols mask */
+ for(i=0; i<pTable->nCol; i++){
+ if( (pTable->aCol[i].colFlags & COLFLAG_PRIMKEY)==0 ) continue;
+ if( i>=BMS-1 ){
+ extraCols |= MASKBIT(BMS-1);
+ break;
+ }
+ if( idxCols & MASKBIT(i) ) continue;
+ extraCols |= MASKBIT(i);
+ }
+ }
mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
@@ -1086,7 +1104,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
}
/* Construct the Index object to describe this index */
- pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed);
+ pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable),
+ 0, &zNotUsed);
if( pIdx==0 ) goto end_auto_index_create;
pLoop->u.btree.pIndex = pIdx;
pIdx->zName = "auto-index";
@@ -1142,8 +1161,10 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
}
}
assert( n==nKeyCol );
- pIdx->aiColumn[n] = XN_ROWID;
- pIdx->azColl[n] = sqlite3StrBINARY;
+ if( HasRowid(pTable) ){
+ pIdx->aiColumn[n] = XN_ROWID;
+ pIdx->azColl[n] = sqlite3StrBINARY;
+ }
/* Create the automatic index */
explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp);
@@ -2410,8 +2431,9 @@ void sqlite3WhereClausePrint(WhereClause *pWC){
** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31
*/
void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
+ WhereInfo *pWInfo;
if( pWC ){
- WhereInfo *pWInfo = pWC->pWInfo;
+ pWInfo = pWC->pWInfo;
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
Table *pTab = pItem->pSTab;
@@ -2421,6 +2443,7 @@ void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
sqlite3DebugPrintf(" %12s",
pItem->zAlias ? pItem->zAlias : pTab->zName);
}else{
+ pWInfo = 0;
sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d",
p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab);
}
@@ -2452,7 +2475,12 @@ void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
}else{
sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm);
}
- sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
+ if( pWInfo && pWInfo->bStarUsed && p->rStarDelta!=0 ){
+ sqlite3DebugPrintf(" cost %d,%d,%d delta=%d\n",
+ p->rSetup, p->rRun, p->nOut, p->rStarDelta);
+ }else{
+ sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
+ }
if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){
int i;
for(i=0; i<p->nLTerm; i++){
@@ -3918,7 +3946,6 @@ static int whereLoopAddBtree(
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
&& !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */
&& !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
- && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */
&& !pSrc->fg.isCorrelated /* Not a correlated subquery */
&& !pSrc->fg.isRecursive /* Not a recursive common table expression. */
&& (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */
@@ -5421,68 +5448,201 @@ static LogEst whereSortingCost(
** 18 for star queries
** 12 otherwise
**
-** For the purposes of SQLite, a star-query is defined as a query
-** with a large central table that is joined against four or more
-** smaller tables. The central table is called the "fact" table.
-** The smaller tables that get joined are "dimension tables".
+** For the purposes of this heuristic, a star-query is defined as a query
+** with a large central table that is joined using an INNER JOIN,
+** not CROSS or OUTER JOINs, against four or more smaller tables.
+** The central table is called the "fact" table. The smaller tables
+** that get joined are "dimension tables". Also, any table that is
+** self-joined cannot be a dimension table; we assume that dimension
+** tables may only be joined against fact tables.
**
** SIDE EFFECT: (and really the whole point of this subroutine)
**
-** If pWInfo describes a star-query, then the cost on WhereLoops for the
-** fact table is reduced. This heuristic helps keep fact tables in
-** outer loops. Without this heuristic, paths with fact tables in outer
-** loops tend to get pruned by the mxChoice limit on the number of paths,
-** resulting in poor query plans. The total amount of heuristic cost
-** adjustment is stored in pWInfo->nOutStarDelta and the cost adjustment
-** for each WhereLoop is stored in its rStarDelta field.
+** If pWInfo describes a star-query, then the cost for SCANs of dimension
+** WhereLoops is increased to be slightly larger than the cost of a SCAN
+** in the fact table. Only SCAN costs are increased. SEARCH costs are
+** unchanged. This heuristic helps keep fact tables in outer loops. Without
+** this heuristic, paths with fact tables in outer loops tend to get pruned
+** by the mxChoice limit on the number of paths, resulting in poor query
+** plans. See the starschema1.test test module for examples of queries
+** that need this heuristic to find good query plans.
+**
+** This heuristic can be completely disabled, so that no query is
+** considered a star-query, using SQLITE_TESTCTRL_OPTIMIZATION to
+** disable the SQLITE_StarQuery optimization. In the CLI, the command
+** to do that is: ".testctrl opt -starquery".
+**
+** HISTORICAL NOTES:
+**
+** This optimization was first added on 2024-05-09 by check-in 38db9b5c83d.
+** The original optimization reduced the cost and output size estimate for
+** fact tables to help them move to outer loops. But months later (as people
+** started upgrading) performance regression reports started caming in,
+** including:
+**
+** forum post b18ef983e68d06d1 (2024-12-21)
+** forum post 0025389d0860af82 (2025-01-14)
+** forum post d87570a145599033 (2025-01-17)
+**
+** To address these, the criteria for a star-query was tightened to exclude
+** cases where the fact and dimensions are separated by an outer join, and
+** the affect of star-schema detection was changed to increase the rRun cost
+** on just full table scans of dimension tables, rather than reducing costs
+** in the all access methods of the fact table.
*/
-static int computeMxChoice(WhereInfo *pWInfo, LogEst nRowEst){
+static int computeMxChoice(WhereInfo *pWInfo){
int nLoop = pWInfo->nLevel; /* Number of terms in the join */
- if( nRowEst==0 && nLoop>=5 ){
- /* Check to see if we are dealing with a star schema and if so, reduce
- ** the cost of fact tables relative to dimension tables, as a heuristic
- ** to help keep the fact tables in outer loops.
+ WhereLoop *pWLoop; /* For looping over WhereLoops */
+
+#ifdef SQLITE_DEBUG
+ /* The star-query detection code below makes use of the following
+ ** properties of the WhereLoop list, so verify them before
+ ** continuing:
+ ** (1) .maskSelf is the bitmask corresponding to .iTab
+ ** (2) The WhereLoop list is in ascending .iTab order
+ */
+ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
+ assert( pWLoop->maskSelf==MASKBIT(pWLoop->iTab) );
+ assert( pWLoop->pNextLoop==0 || pWLoop->iTab<=pWLoop->pNextLoop->iTab );
+ }
+#endif /* SQLITE_DEBUG */
+
+ if( nLoop>=5
+ && !pWInfo->bStarDone
+ && OptimizationEnabled(pWInfo->pParse->db, SQLITE_StarQuery)
+ ){
+ SrcItem *aFromTabs; /* All terms of the FROM clause */
+ int iFromIdx; /* Term of FROM clause is the candidate fact-table */
+ Bitmask m; /* Bitmask for candidate fact-table */
+ Bitmask mSelfJoin = 0; /* Tables that cannot be dimension tables */
+ WhereLoop *pStart; /* Where to start searching for dimension-tables */
+
+ pWInfo->bStarDone = 1; /* Only do this computation once */
+
+ /* Look for fact tables with four or more dimensions where the
+ ** dimension tables are not separately from the fact tables by an outer
+ ** or cross join. Adjust cost weights if found.
*/
- int iLoop; /* Counter over join terms */
- Bitmask m; /* Bitmask for current loop */
- assert( pWInfo->nOutStarDelta==0 );
- for(iLoop=0, m=1; iLoop<nLoop; iLoop++, m<<=1){
- WhereLoop *pWLoop; /* For looping over WhereLoops */
+ assert( !pWInfo->bStarUsed );
+ aFromTabs = pWInfo->pTabList->a;
+ pStart = pWInfo->pLoops;
+ for(iFromIdx=0, m=1; iFromIdx<nLoop; iFromIdx++, m<<=1){
int nDep = 0; /* Number of dimension tables */
- LogEst rDelta; /* Heuristic cost adjustment */
+ LogEst mxRun; /* Maximum SCAN cost of a fact table */
Bitmask mSeen = 0; /* Mask of dimension tables */
- for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
- if( (pWLoop->prereq & m)!=0 && (pWLoop->maskSelf & mSeen)==0 ){
- nDep++;
- mSeen |= pWLoop->maskSelf;
+ SrcItem *pFactTab; /* The candidate fact table */
+
+ pFactTab = aFromTabs + iFromIdx;
+ if( (pFactTab->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){
+ /* If the candidate fact-table is the right table of an outer join
+ ** restrict the search for dimension-tables to be tables to the right
+ ** of the fact-table. */
+ if( iFromIdx+4 > nLoop ) break; /* Impossible to reach nDep>=4 */
+ while( pStart && pStart->iTab<=iFromIdx ){
+ pStart = pStart->pNextLoop;
}
}
- if( nDep<=3 ) continue;
- rDelta = 15*(nDep-3);
-#ifdef WHERETRACE_ENABLED /* 0x4 */
- if( sqlite3WhereTrace&0x4 ){
- SrcItem *pItem = pWInfo->pTabList->a + iLoop;
- sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n",
- pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName,
- nDep, rDelta);
+ for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( (aFromTabs[pWLoop->iTab].fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){
+ /* Fact-tables and dimension-tables cannot be separated by an
+ ** outer join (at least for the definition of fact- and dimension-
+ ** used by this heuristic). */
+ break;
+ }
+ if( (pWLoop->prereq & m)!=0 /* pWInfo depends on iFromIdx */
+ && (pWLoop->maskSelf & mSeen)==0 /* pWInfo not already a dependency */
+ && (pWLoop->maskSelf & mSelfJoin)==0 /* Not a self-join */
+ ){
+ if( aFromTabs[pWLoop->iTab].pSTab==pFactTab->pSTab ){
+ mSelfJoin |= m;
+ }else{
+ nDep++;
+ mSeen |= pWLoop->maskSelf;
+ }
+ }
}
-#endif
- if( pWInfo->nOutStarDelta==0 ){
+ if( nDep<=3 ) continue;
+
+ /* If we reach this point, it means that pFactTab is a fact table
+ ** with four or more dimensions connected by inner joins. Proceed
+ ** to make cost adjustments. */
+
+#ifdef WHERETRACE_ENABLED
+ /* Make sure rStarDelta values are initialized */
+ if( !pWInfo->bStarUsed ){
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
pWLoop->rStarDelta = 0;
}
}
- pWInfo->nOutStarDelta += rDelta;
+#endif
+ pWInfo->bStarUsed = 1;
+
+ /* Compute the maximum cost of any WhereLoop for the
+ ** fact table plus one epsilon */
+ mxRun = LOGEST_MIN;
+ for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( pWLoop->iTab<iFromIdx ) continue;
+ if( pWLoop->iTab>iFromIdx ) break;
+ if( pWLoop->rRun>mxRun ) mxRun = pWLoop->rRun;
+ }
+ if( ALWAYS(mxRun<LOGEST_MAX) ) mxRun++;
+
+ /* Increase the cost of table scans for dimension tables to be
+ ** slightly more than the maximum cost of the fact table */
+ for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( (pWLoop->maskSelf & mSeen)==0 ) continue;
+ if( pWLoop->nLTerm ) continue;
+ if( pWLoop->rRun<mxRun ){
+#ifdef WHERETRACE_ENABLED /* 0x80000 */
+ if( sqlite3WhereTrace & 0x80000 ){
+ SrcItem *pDim = aFromTabs + pWLoop->iTab;
+ sqlite3DebugPrintf(
+ "Increase SCAN cost of dimension %s(%d) of fact %s(%d) to %d\n",
+ pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab,
+ pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName,
+ iFromIdx, mxRun
+ );
+ }
+ pWLoop->rStarDelta = mxRun - pWLoop->rRun;
+#endif /* WHERETRACE_ENABLED */
+ pWLoop->rRun = mxRun;
+ }
+ }
+ }
+#ifdef WHERETRACE_ENABLED /* 0x80000 */
+ if( (sqlite3WhereTrace & 0x80000)!=0 && pWInfo->bStarUsed ){
+ sqlite3DebugPrintf("WhereLoops changed by star-query heuristic:\n");
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
- if( pWLoop->maskSelf==m ){
- pWLoop->rRun -= rDelta;
- pWLoop->nOut -= rDelta;
- pWLoop->rStarDelta = rDelta;
+ if( pWLoop->rStarDelta ){
+ sqlite3WhereLoopPrint(pWLoop, &pWInfo->sWC);
}
}
- }
+ }
+#endif
}
- return pWInfo->nOutStarDelta>0 ? 18 : 12;
+ return pWInfo->bStarUsed ? 18 : 12;
+}
+
+/*
+** Two WhereLoop objects, pCandidate and pBaseline, are known to have the
+** same cost. Look deep into each to see if pCandidate is even slightly
+** better than pBaseline. Return false if it is, if pCandidate is is preferred.
+** Return true if pBaseline is preferred or if we cannot tell the difference.
+**
+** Result Meaning
+** -------- ----------------------------------------------------------
+** true We cannot tell the difference in pCandidate and pBaseline
+** false pCandidate seems like a better choice than pBaseline
+*/
+static SQLITE_NOINLINE int whereLoopIsNoBetter(
+ const WhereLoop *pCandidate,
+ const WhereLoop *pBaseline
+){
+ if( (pCandidate->wsFlags & WHERE_INDEXED)==0 ) return 1;
+ if( (pBaseline->wsFlags & WHERE_INDEXED)==0 ) return 1;
+ if( pCandidate->u.btree.pIndex->szIdxRow <
+ pBaseline->u.btree.pIndex->szIdxRow ) return 0;
+ return 1;
}
/*
@@ -5506,7 +5666,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int mxI = 0; /* Index of next entry to replace */
int nOrderBy; /* Number of ORDER BY clause terms */
LogEst mxCost = 0; /* Maximum cost of a set of paths */
- LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */
+ LogEst mxUnsort = 0; /* Maximum unsorted cost of a set of path */
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
WherePath *aFrom; /* All nFrom paths at the previous level */
WherePath *aTo; /* The nTo best paths at the current level */
@@ -5535,8 +5695,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
mxChoice = 1;
}else if( nLoop==2 ){
mxChoice = 5;
+ }else if( pParse->nErr ){
+ mxChoice = 1;
}else{
- mxChoice = computeMxChoice(pWInfo, nRowEst);
+ mxChoice = computeMxChoice(pWInfo);
}
assert( nLoop<=pWInfo->pTabList->nSrc );
@@ -5603,7 +5765,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
- LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
+ LogEst rUnsort; /* Unsorted cost of (pFrom+pWLoop) */
i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */
Bitmask maskNew; /* Mask of src visited by (..) */
Bitmask revMask; /* Mask of rev-order loops for (..) */
@@ -5621,11 +5783,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
- rUnsorted = pWLoop->rRun + pFrom->nRow;
+ rUnsort = pWLoop->rRun + pFrom->nRow;
if( pWLoop->rSetup ){
- rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup, rUnsorted);
+ rUnsort = sqlite3LogEstAdd(pWLoop->rSetup, rUnsort);
}
- rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
+ rUnsort = sqlite3LogEstAdd(rUnsort, pFrom->rUnsort);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
isOrdered = pFrom->isOrdered;
@@ -5647,15 +5809,15 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** extra encouragement to the query planner to select a plan
** where the rows emerge in the correct order without any sorting
** required. */
- rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3;
+ rCost = sqlite3LogEstAdd(rUnsort, aSortCost[isOrdered]) + 3;
WHERETRACE(0x002,
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
- rUnsorted, rCost));
+ rUnsort, rCost));
}else{
- rCost = rUnsorted;
- rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
+ rCost = rUnsort;
+ rUnsort -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
/* Check to see if pWLoop should be added to the set of
@@ -5681,7 +5843,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( jj>=nTo ){
/* None of the existing best-so-far paths match the candidate. */
if( nTo>=mxChoice
- && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted))
+ && (rCost>mxCost || (rCost==mxCost && rUnsort>=mxUnsort))
){
/* The current candidate is no better than any of the mxChoice
** paths currently in the best-so-far buffer. So discard
@@ -5689,7 +5851,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
@@ -5708,7 +5870,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
@@ -5719,24 +5881,23 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** pTo or if the candidate should be skipped.
**
** The conditional is an expanded vector comparison equivalent to:
- ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted)
+ ** (pTo->rCost,pTo->nRow,pTo->rUnsort) <= (rCost,nOut,rUnsort)
*/
- if( pTo->rCost<rCost
- || (pTo->rCost==rCost
- && (pTo->nRow<nOut
- || (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted)
- )
- )
+ if( (pTo->rCost<rCost)
+ || (pTo->rCost==rCost && pTo->nRow<nOut)
+ || (pTo->rCost==rCost && pTo->nRow==nOut && pTo->rUnsort<rUnsort)
+ || (pTo->rCost==rCost && pTo->nRow==nOut && pTo->rUnsort==rUnsort
+ && whereLoopIsNoBetter(pWLoop, pTo->aLoop[iLoop]) )
){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Skip %s cost=%-3d,%3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort,
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsort, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
/* Discard the candidate path from further consideration */
@@ -5750,11 +5911,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Update %s cost=%-3d,%3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort,
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsort, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
}
@@ -5763,20 +5924,20 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pTo->revLoop = revMask;
pTo->nRow = nOut;
pTo->rCost = rCost;
- pTo->rUnsorted = rUnsorted;
+ pTo->rUnsort = rUnsort;
pTo->isOrdered = isOrdered;
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
pTo->aLoop[iLoop] = pWLoop;
if( nTo>=mxChoice ){
mxI = 0;
mxCost = aTo[0].rCost;
- mxUnsorted = aTo[0].nRow;
+ mxUnsort = aTo[0].nRow;
for(jj=1, pTo=&aTo[1]; jj<mxChoice; jj++, pTo++){
if( pTo->rCost>mxCost
- || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted)
+ || (pTo->rCost==mxCost && pTo->rUnsort>mxUnsort)
){
mxCost = pTo->rCost;
- mxUnsorted = pTo->rUnsorted;
+ mxUnsort = pTo->rUnsort;
mxI = jj;
}
}
@@ -5788,8 +5949,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( sqlite3WhereTrace & 0x02 ){
LogEst rMin, rFloor = 0;
int nDone = 0;
+ int nProgress;
sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
- while( nDone<nTo ){
+ do{
+ nProgress = 0;
rMin = 0x7fff;
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
if( pTo->rCost>rFloor && pTo->rCost<rMin ) rMin = pTo->rCost;
@@ -5805,10 +5968,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
sqlite3DebugPrintf("\n");
}
nDone++;
+ nProgress++;
}
}
rFloor = rMin;
- }
+ }while( nDone<nTo && nProgress>0 );
}
#endif
@@ -5902,7 +6066,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
}
- pWInfo->nRowOut = pFrom->nRow + pWInfo->nOutStarDelta;
+ pWInfo->nRowOut = pFrom->nRow;
+#ifdef WHERETRACE_ENABLED
+ pWInfo->rTotalCost = pFrom->rCost;
+#endif
/* Free temporary memory and return success */
sqlite3StackFreeNN(pParse->db, pSpace);
@@ -6300,7 +6467,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
}
}
nSearch += pLoop->nOut;
- if( pWInfo->nOutStarDelta ) nSearch += pLoop->rStarDelta;
}
}
@@ -6783,7 +6949,8 @@ WhereInfo *sqlite3WhereBegin(
assert( db->mallocFailed==0 );
#ifdef WHERETRACE_ENABLED
if( sqlite3WhereTrace ){
- sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
+ sqlite3DebugPrintf("---- Solution cost=%d, nRow=%d",
+ pWInfo->rTotalCost, pWInfo->nRowOut);
if( pWInfo->nOBSat>0 ){
sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
}
diff --git a/src/whereInt.h b/src/whereInt.h
index f262b0eeb..8ba8a7072 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -162,8 +162,10 @@ struct WhereLoop {
/**** whereLoopXfer() copies fields above ***********************/
# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot)
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
+#ifdef WHERETRACE_ENABLED
LogEst rStarDelta; /* Cost delta due to star-schema heuristic. Not
- ** initialized unless pWInfo->nOutStarDelta>0 */
+ ** initialized unless pWInfo->bStarUsed */
+#endif
WhereTerm **aLTerm; /* WhereTerms used */
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */
@@ -212,7 +214,7 @@ struct WherePath {
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
- LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */
+ LogEst rUnsort; /* Total cost of this path ignoring sorting costs */
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
};
@@ -485,9 +487,13 @@ struct WhereInfo {
unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */
unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */
unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */
- unsigned sorted :1; /* True if really sorted (not just grouped) */
- LogEst nOutStarDelta; /* Artifical nOut reduction for star-query */
+ unsigned sorted :1; /* True if really sorted (not just grouped) */
+ unsigned bStarDone :1; /* True if check for star-query is complete */
+ unsigned bStarUsed :1; /* True if star-query heuristic is used */
LogEst nRowOut; /* Estimated number of output rows */
+#ifdef WHERETRACE_ENABLED
+ LogEst rTotalCost; /* Total cost of the solution */
+#endif
int iTop; /* The very beginning of the WHERE loop */
int iEndWhere; /* End of the WHERE clause itself */
WhereLoop *pLoops; /* List of all WhereLoop objects */
diff --git a/src/wherecode.c b/src/wherecode.c
index 045653aac..1a0cdc6d7 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -1608,6 +1608,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
+ /* The instruction immediately prior to OP_VFilter must be an OP_Integer
+ ** that sets the "argc" value for xVFilter. This is necessary for
+ ** resolveP2() to work correctly. See tag-20250207a. */
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
pLoop->u.vtab.idxStr,
pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 2b6eb6a78..4a24dadd2 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -219,12 +219,12 @@ static int isLikeOrGlob(
z = (u8*)pRight->u.zToken;
}
if( z ){
- /* 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. */
+ /* Count the number of prefix bytes prior to the first wildcard,
+ ** U+fffd character, or malformed utf-8. 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++;
@@ -232,7 +232,9 @@ static int isLikeOrGlob(
cnt++;
}else if( c>=0x80 ){
const u8 *z2 = z+cnt-1;
- if( sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){
+ if( c==0xff || sqlite3Utf8Read(&z2)==0xfffd /* bad utf-8 */
+ || ENC(db)==SQLITE_UTF16LE
+ ){
cnt--;
break;
}else{
@@ -1384,9 +1386,8 @@ static void exprAnalyze(
}
if( !db->mallocFailed ){
- u8 c, *pC; /* Last character before the first wildcard */
+ u8 *pC; /* Last character before the first wildcard */
pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
- c = *pC;
if( noCase ){
/* The point is to increment the last character before the first
** wildcard. But if we increment '@', that will push it into the
@@ -1394,10 +1395,17 @@ static void exprAnalyze(
** inequality. To avoid this, make sure to also run the full
** LIKE on all candidate expressions by clearing the isComplete flag
*/
- if( c=='A'-1 ) isComplete = 0;
- c = sqlite3UpperToLower[c];
+ if( *pC=='A'-1 ) isComplete = 0;
+ *pC = sqlite3UpperToLower[*pC];
+ }
+
+ /* Increment the value of the last utf8 character in the prefix. */
+ while( *pC==0xBF && pC>(u8*)pStr2->u.zToken ){
+ *pC = 0x80;
+ pC--;
}
- *pC = c + 1;
+ assert( *pC!=0xFF ); /* isLikeOrGlob() guarantees this */
+ (*pC)++;
}
zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY;
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
diff --git a/test/autoindex1.test b/test/autoindex1.test
index b294a2721..1c8ce007f 100644
--- a/test/autoindex1.test
+++ b/test/autoindex1.test
@@ -563,4 +563,32 @@ do_execsql_test autoindex-1120 {
SELECT * FROM t1 LEFT JOIN t2 ON (t2.c=+t1.a) LEFT JOIN t3 ON (t2.d IS NULL);
} {1 1 1 2 {} {}}
+# 2025-01-18
+# Added support for automatic indexes on WITHOUT ROWID tables.
+#
+reset_db
+do_execsql_test autoindex-1200 {
+ CREATE TABLE t1(a INT, b INT, x INT, PRIMARY KEY(a,b)) WITHOUT ROWID;
+ INSERT INTO t1 VALUES(1,2,90),(1,3,91),(1,4,92);
+ CREATE TABLE t2a(c INTEGER PRIMARY KEY, i1 INT);
+ CREATE TABLE t2b(i1 INTEGER PRIMARY KEY, d INT);
+ CREATE VIEW t2(c,d) AS SELECT c, d FROM t2a NATURAL JOIN t2b;
+ INSERT INTO t2a VALUES(3,93),(4,94),(5,95),(6,96),(7,97);
+ INSERT INTO t2b VALUES(91,11),(92,22),(93,33),(94,44),(95,55);
+ CREATE TABLE dual(dummy TEXT);
+ INSERT INTO dual(dummy) VALUES('x');
+}
+db null NULL
+do_execsql_test autoindex-1210 {
+ SELECT t1.*, t2.* FROM t2 LEFT OUTER JOIN t1 ON b=c ORDER BY +b;
+} {
+ NULL NULL NULL 5 55
+ 1 3 91 3 33
+ 1 4 92 4 44
+}
+do_execsql_test autoindex-1211 {
+ EXPLAIN QUERY PLAN
+ SELECT t1.*, t2.* FROM t2 LEFT OUTER JOIN t1 ON b=c ORDER BY +b;
+} {/SEARCH t1 USING AUTOMATIC COVERING INDEX/}
+
finish_test
diff --git a/test/capi3.test b/test/capi3.test
index e65f90e3a..6319d8284 100644
--- a/test/capi3.test
+++ b/test/capi3.test
@@ -689,7 +689,9 @@ do_test capi3-6.3 {
sqlite3_finalize $STMT
} {SQLITE_OK}
-if {[clang_sanitize_address]==0} {
+if {0 && [clang_sanitize_address]==0} {
+ # This use-after-free occasionally causes segfaults during ordinary
+ # builds. Let's just disable it completely.
do_test capi3-6.4-misuse {
db cache flush
sqlite3_close $DB
diff --git a/test/date.test b/test/date.test
index d22b652b4..2042880a9 100644
--- a/test/date.test
+++ b/test/date.test
@@ -651,5 +651,13 @@ datetest 19.51 {date('2000-08-31','+0022-06-00','floor')} {2023-02-28}
datetest 19.52 {date('2000-08-31','+0023-06-00','ceiling')} {2024-03-02}
datetest 19.53 {date('2000-08-31','+0022-06-00','ceiling')} {2023-03-03}
+# 2025-01-21
+# https://sqlite.org/forum/forumpost/766a2c9231
+#
+datetest 20.1 {datetime('2024-12-31 23:59:59.9990')} {2024-12-31 23:59:59}
+datetest 20.2 {datetime('2024-12-31 23:59:59.9999999999999')} \
+ {2024-12-31 23:59:59}
+datetest 20.3 {datetime('2024-12-31 23:59:59.9995')} {2024-12-31 23:59:59}
+datetest 20.4 {datetime('2024-12-31 23:59:58.9995')} {2024-12-31 23:59:58}
finish_test
diff --git a/test/dbpage.test b/test/dbpage.test
index 0646a70b0..8039e0e1b 100644
--- a/test/dbpage.test
+++ b/test/dbpage.test
@@ -108,4 +108,148 @@ do_execsql_test 300 {
SELECT * FROM sqlite_temp_schema, sqlite_dbpage;
} {}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 400 {
+ ATTACH ':memory:' AS aux1;
+ BEGIN;
+ CREATE VIRTUAL TABLE aux1.t1 USING sqlite_dbpage;
+ INSERT INTO t1 VALUES(17, NULL);
+ COMMIT;
+}
+
+#-------------------------------------------------------------------------
+reset_db
+forcedelete test.db2
+sqlite3 db2 test.db2
+db2 eval {
+ PRAGMA auto_vacuum=NONE;
+ CREATE TABLE t1(x, y);
+}
+
+do_execsql_test 500 {
+ PRAGMA auto_vacuum=NONE;
+ CREATE TABLE x1(a);
+ INSERT INTO x1 VALUES( hex(randomblob(2000)) );
+ INSERT INTO x1 VALUES( hex(randomblob(2000)) );
+ INSERT INTO x1 VALUES( hex(randomblob(2000)) );
+ INSERT INTO x1 VALUES( hex(randomblob(2000)) );
+ PRAGMA page_count;
+} {18}
+
+do_test 510 {
+ db eval BEGIN
+ db2 eval { PRAGMA page_count } {
+ db eval {
+ INSERT INTO sqlite_dbpage values($page_count, NULL);
+ }
+ }
+ db2 eval { SELECT pgno, data FROM sqlite_dbpage } {
+ db eval {
+ INSERT INTO sqlite_dbpage values($pgno, $data);
+ }
+ }
+
+ db eval COMMIT
+} {}
+
+db close
+sqlite3 db test.db
+
+do_execsql_test 520 {
+ PRAGMA page_count;
+ SELECT * FROM t1;
+} {2}
+
+db2 close
+
+#-------------------------------------------------------------------------
+reset_db
+forcedelete test.db2
+do_execsql_test 610 {
+ ATTACH 'test.db2' AS aux;
+ CREATE TABLE t1(x);
+ CREATE TABLE t2(y);
+ INSERT INTO t1 VALUES(1234);
+ CREATE TABLE aux.x1(z);
+}
+
+set pgno [db one {SELECT max(rootpage) FROM sqlite_schema}]
+sqlite3 db2 test.db2
+db2 eval {
+ BEGIN;
+ SELECT * FROM x1;
+}
+
+do_catchsql_test 620 {
+ UPDATE sqlite_dbpage SET data = (
+ SELECT data FROM sqlite_dbpage WHERE pgno=$pgno-1
+ ) WHERE pgno = $pgno;
+} {1 {database is locked}}
+
+db2 eval {
+ COMMIT;
+}
+
+do_catchsql_test 630 {
+ UPDATE sqlite_dbpage SET data = (
+ SELECT data FROM sqlite_dbpage WHERE pgno=$pgno-1
+ ) WHERE pgno = $pgno;
+} {0 {}}
+
+db close
+sqlite3 db test.db
+
+do_execsql_test 640 {
+ SELECT * FROM t2;
+} {1234}
+
+db2 close
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 700 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES( hex(randomblob(1000)) );
+ INSERT INTO t1 VALUES( hex(randomblob(1000)) );
+ INSERT INTO t1 VALUES( hex(randomblob(1000)) );
+}
+
+forcedelete test.db2
+sqlite3 db2 test.db2
+db2 eval {
+ CREATE TABLE y1(y);
+ INSERT INTO y1 VALUES( hex(randomblob(1000)) );
+}
+
+set max [db2 one {PRAGMA page_count}]
+
+do_test 710 {
+ execsql {
+ BEGIN;
+ }
+
+ for {set ii 1} {$ii <= $max} {incr ii} {
+ set data [db2 one {SELECT data FROM sqlite_dbpage WHERE pgno=$ii}]
+ execsql {
+ UPDATE sqlite_dbpage SET data=$data WHERE pgno=$ii
+ }
+ }
+
+ execsql {
+ SAVEPOINT abc;
+ INSERT INTO sqlite_dbpage VALUES(2, NULL);
+ ROLLBACK TO abc;
+ COMMIT;
+ }
+} {}
+
+db close
+sqlite3 db test.db
+
+do_execsql_test 720 {
+ PRAGMA integrity_check
+} {ok}
+
+
finish_test
diff --git a/test/dbpagefault.test b/test/dbpagefault.test
index f27741cba..e5b246fc9 100644
--- a/test/dbpagefault.test
+++ b/test/dbpagefault.test
@@ -82,5 +82,31 @@ do_catchsql_test 3.2 {
# faultsim_test_result {0 {}}
#}
+reset_db
+forcedelete test.db2
+do_execsql_test 4.0 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES('one');
+ CREATE TABLE t2(x);
+ INSERT INTO t2 VALUES('two');
+ ATTACH 'test.db2' AS aux;
+ CREATE TABLE aux.x1(x);
+}
+
+set pgno [db one {SELECT max(rootpage) FROM sqlite_schema}]
+
+faultsim_save_and_close
+do_faultsim_test 4 -prep {
+ faultsim_restore_and_reopen
+ execsql { ATTACH 'test.db2' AS aux; }
+} -body {
+ execsql {
+ UPDATE sqlite_dbpage SET data = (
+ SELECT data FROM sqlite_dbpage WHERE pgno=($pgno-1)
+ ) WHERE pgno = $pgno;
+ }
+} -test {
+ faultsim_test_result {0 {}} {1 {unable to open a temporary database file for storing temporary tables}}
+}
finish_test
diff --git a/test/fkey6.test b/test/fkey6.test
index b658f20fe..72de926b5 100644
--- a/test/fkey6.test
+++ b/test/fkey6.test
@@ -225,5 +225,47 @@ do_execsql_test 3.3.4 {
SELECT * FROM p2;
} {0 one 1 deleted!}
+#-------------------------------------------------------------------------
+# Verify that, even with "PRAGMA defer_foreign_keys", a transaction cannot
+# be committed if there are outstanding foreign key violations.
+#
+reset_db
+do_execsql_test 4.0 {
+ CREATE TABLE p1(a INTEGER PRIMARY KEY, b UNIQUE);
+ CREATE TABLE c1(x REFERENCES p1(b));
+
+ INSERT INTO p1 VALUES(1, 'one'), (2, 'two'), (3, 'three');
+ INSERT INTO c1 VALUES('two');
+
+ PRAGMA foreign_keys = 1;
+ PRAGMA defer_foreign_keys = 1;
+}
+
+do_execsql_test 4.1 {
+ BEGIN;
+ DELETE FROM p1 WHERE a=2;
+}
+
+do_catchsql_test 4.2 {
+ COMMIT;
+} {1 {FOREIGN KEY constraint failed}}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 5.0 {
+ PRAGMA foreign_keys = 1;
+ CREATE TABLE p1(a INTEGER PRIMARY KEY, b);
+ CREATE TABLE c1(x REFERENCES p1 DEFERRABLE INITIALLY DEFERRED);
+}
+
+do_execsql_test 5.1 {
+ BEGIN;
+ INSERT INTO c1 VALUES(123);
+ PRAGMA defer_foreign_keys = 1;
+ INSERT INTO p1 VALUES(123, 'one two three');
+ COMMIT;
+}
+
finish_test
diff --git a/test/fuzzcheck.c b/test/fuzzcheck.c
index 9f339096b..84e3f3289 100644
--- a/test/fuzzcheck.c
+++ b/test/fuzzcheck.c
@@ -507,7 +507,8 @@ static void writefileFunc(
static void blobListLoadFromDb(
sqlite3 *db, /* Read from this database */
const char *zSql, /* Query used to extract the blobs */
- int onlyId, /* Only load where id is this value */
+ int firstId, /* First sqlid to load */
+ int lastId, /* Last sqlid to load */
int *pN, /* OUT: Write number of blobs loaded here */
Blob **ppList /* OUT: Write the head of the blob list here */
){
@@ -518,8 +519,9 @@ static void blobListLoadFromDb(
int rc;
char *z2;
- if( onlyId>0 ){
- z2 = sqlite3_mprintf("%s WHERE rowid=%d", zSql, onlyId);
+ if( firstId>0 ){
+ z2 = sqlite3_mprintf("%s WHERE rowid BETWEEN %d AND %d", zSql,
+ firstId, lastId);
}else{
z2 = sqlite3_mprintf("%s", zSql);
}
@@ -1836,7 +1838,8 @@ static void showHelp(void){
"each database, checking for crashes and memory leaks.\n"
"Options:\n"
" --cell-size-check Set the PRAGMA cell_size_check=ON\n"
-" --dbid N Use only the database where dbid=N\n"
+" --dbid M..N Use only the databases where dbid between M and N\n"
+" \"M..\" for M and afterwards. Just \"M\" for M only\n"
" --export-db DIR Write databases to files(s) in DIR. Works with --dbid\n"
" --export-sql DIR Write SQL to file(s) in DIR. Also works with --sqlid\n"
" --help Show this help text\n"
@@ -1861,7 +1864,8 @@ static void showHelp(void){
" --script Output CLI script instead of running tests\n"
" --skip N Skip the first N test cases\n"
" --spinner Use a spinner to show progress\n"
-" --sqlid N Use only SQL where sqlid=N\n"
+" --sqlid M..N Use only SQL where sqlid between M..N\n"
+" \"M..\" for M and afterwards. Just \"M\" for M only\n"
" --timeout N Maximum time for any one test in N millseconds\n"
" -v|--verbose Increased output. Repeat for more output.\n"
" --vdbe-debug Activate VDBE debugging.\n"
@@ -1883,8 +1887,10 @@ int main(int argc, char **argv){
Blob *pDb; /* For looping over template databases */
int i; /* Loop index for the argv[] loop */
int dbSqlOnly = 0; /* Only use scripts that are dbsqlfuzz */
- int onlySqlid = -1; /* --sqlid */
- int onlyDbid = -1; /* --dbid */
+ int firstSqlid = -1; /* First --sqlid range */
+ int lastSqlid = 0x7fffffff; /* Last --sqlid range */
+ int firstDbid = -1; /* --dbid */
+ int lastDbid = 0x7fffffff; /* --dbid end */
int nativeFlag = 0; /* --native-vfs */
int rebuildFlag = 0; /* --rebuild */
int vdbeLimitFlag = 0; /* --limit-vdbe */
@@ -1917,6 +1923,7 @@ int main(int argc, char **argv){
int bTimer = 0; /* Show elapse time for each test */
int nV; /* How much to increase verbosity with -vvvv */
sqlite3_int64 tmStart; /* Start of each test */
+ int iEstTime = 0; /* LPF for the time-to-go */
sqlite3_config(SQLITE_CONFIG_URI,1);
registerOomSimulator();
@@ -1941,8 +1948,18 @@ int main(int argc, char **argv){
cellSzCkFlag = 1;
}else
if( strcmp(z,"dbid")==0 ){
+ const char *zDotDot;
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
- onlyDbid = integerValue(argv[++i]);
+ i++;
+ zDotDot = strstr(argv[i], "..");
+ if( zDotDot ){
+ firstDbid = atoi(argv[i]);
+ if( zDotDot[2] ){
+ lastDbid = atoi(&zDotDot[2]);
+ }
+ }else{
+ lastDbid = firstDbid = integerValue(argv[i]);
+ }
}else
if( strcmp(z,"export-db")==0 ){
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
@@ -2042,8 +2059,19 @@ int main(int argc, char **argv){
bTimer = 1;
}else
if( strcmp(z,"sqlid")==0 ){
+ const char *zDotDot;
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
- onlySqlid = integerValue(argv[++i]);
+ i++;
+ zDotDot = strstr(argv[i], "..");
+ if( zDotDot ){
+ firstSqlid = atoi(argv[i]);
+ if( zDotDot[2] ){
+ lastSqlid = atoi(&zDotDot[2]);
+ }
+ }else{
+ firstSqlid = integerValue(argv[i]);
+ lastSqlid = firstSqlid;
+ }
}else
if( strcmp(z,"timeout")==0 ){
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
@@ -2291,13 +2319,14 @@ int main(int argc, char **argv){
const char *zExDb =
"SELECT writefile(printf('%s/db%06d.db',?1,dbid),dbcontent),"
" dbid, printf('%s/db%06d.db',?1,dbid), length(dbcontent)"
- " FROM db WHERE ?2<0 OR dbid=?2;";
+ " FROM db WHERE dbid BETWEEN ?2 AND ?3;";
rc = sqlite3_prepare_v2(db, zExDb, -1, &pStmt, 0);
if( rc ) fatalError("cannot prepare statement [%s]: %s",
zExDb, sqlite3_errmsg(db));
sqlite3_bind_text64(pStmt, 1, zExpDb, strlen(zExpDb),
SQLITE_STATIC, SQLITE_UTF8);
- sqlite3_bind_int(pStmt, 2, onlyDbid);
+ sqlite3_bind_int(pStmt, 2, firstDbid);
+ sqlite3_bind_int(pStmt, 3, lastDbid);
while( sqlite3_step(pStmt)==SQLITE_ROW ){
printf("write db-%d (%d bytes) into %s\n",
sqlite3_column_int(pStmt,1),
@@ -2310,13 +2339,14 @@ int main(int argc, char **argv){
const char *zExSql =
"SELECT writefile(printf('%s/sql%06d.txt',?1,sqlid),sqltext),"
" sqlid, printf('%s/sql%06d.txt',?1,sqlid), length(sqltext)"
- " FROM xsql WHERE ?2<0 OR sqlid=?2;";
+ " FROM xsql WHERE sqlid BETWEEN ?2 AND ?3;";
rc = sqlite3_prepare_v2(db, zExSql, -1, &pStmt, 0);
if( rc ) fatalError("cannot prepare statement [%s]: %s",
zExSql, sqlite3_errmsg(db));
sqlite3_bind_text64(pStmt, 1, zExpSql, strlen(zExpSql),
SQLITE_STATIC, SQLITE_UTF8);
- sqlite3_bind_int(pStmt, 2, onlySqlid);
+ sqlite3_bind_int(pStmt, 2, firstSqlid);
+ sqlite3_bind_int(pStmt, 3, lastSqlid);
while( sqlite3_step(pStmt)==SQLITE_ROW ){
printf("write sql-%d (%d bytes) into %s\n",
sqlite3_column_int(pStmt,1),
@@ -2332,11 +2362,11 @@ int main(int argc, char **argv){
/* Load all SQL script content and all initial database images from the
** source db
*/
- blobListLoadFromDb(db, "SELECT sqlid, sqltext FROM xsql", onlySqlid,
- &g.nSql, &g.pFirstSql);
+ blobListLoadFromDb(db, "SELECT sqlid, sqltext FROM xsql", firstSqlid,
+ lastSqlid, &g.nSql, &g.pFirstSql);
if( g.nSql==0 ) fatalError("need at least one SQL script");
- blobListLoadFromDb(db, "SELECT dbid, dbcontent FROM db", onlyDbid,
- &g.nDb, &g.pFirstDb);
+ blobListLoadFromDb(db, "SELECT dbid, dbcontent FROM db", firstDbid,
+ lastDbid, &g.nDb, &g.pFirstDb);
if( g.nDb==0 ){
g.pFirstDb = safe_realloc(0, sizeof(Blob));
memset(g.pFirstDb, 0, sizeof(Blob));
@@ -2416,9 +2446,29 @@ int main(int argc, char **argv){
if( bScript ){
/* No progress output */
}else if( bSpinner ){
- int nTotal =g.nSql;
+ int nTotal = g.nSql;
int idx = pSql->seq;
- printf("\r%s: %d/%d ", zDbName, idx, nTotal);
+ if( nSrcDb==1 && nTotal>idx && idx>=20 ){
+ int iToGo = (timeOfDay() - iBegin)*(nTotal-idx)/(idx*1000);
+ int hr, min, sec;
+ if( idx==20 ){
+ iEstTime = iToGo;
+ }else{
+ iEstTime = (iToGo + 7*iEstTime)/8;
+ }
+ hr = iEstTime/3600;
+ min = (iEstTime/60)%60;
+ sec = iEstTime%60;
+ if( hr>0 ){
+ printf("\r%s: %d/%d ETC %d:%02d:%02d ",
+ zDbName, idx, nTotal, hr, min, sec);
+ }else{
+ printf("\r%s: %d/%d ETC %02d:%02d ",
+ zDbName, idx, nTotal, min, sec);
+ }
+ }else{
+ printf("\r%s: %d/%d ", zDbName, idx, nTotal);
+ }
fflush(stdout);
}else if( verboseFlag>1 ){
printf("%s\n", g.zTestName);
@@ -2457,7 +2507,7 @@ int main(int argc, char **argv){
}else if( bSpinner ){
int nTotal = g.nDb*g.nSql;
int idx = pSql->seq*g.nDb + pDb->id - 1;
- printf("\r%s: %d/%d ", zDbName, idx, nTotal);
+ printf("\r%s: %d/%d ", zDbName, idx, nTotal);
fflush(stdout);
}else if( verboseFlag>1 ){
printf("%s\n", g.zTestName);
@@ -2560,7 +2610,7 @@ int main(int argc, char **argv){
/* No progress output */
}else if( bSpinner ){
int nTotal = g.nDb*g.nSql;
- printf("\r%s: %d/%d \n", zDbName, nTotal, nTotal);
+ printf("\r%s: %d/%d \n", zDbName, nTotal, nTotal);
}else if( !quietFlag && verboseFlag<2 ){
printf(" 100%% - %d tests\n", g.nDb*g.nSql);
}
diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db
index 3e3418007..469df2c68 100644
--- a/test/fuzzdata8.db
+++ b/test/fuzzdata8.db
Binary files differ
diff --git a/test/in7.test b/test/in7.test
index 4dc0821d1..763396140 100644
--- a/test/in7.test
+++ b/test/in7.test
@@ -219,4 +219,33 @@ do_execsql_test 3.8 {
SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) IN ((1, 2));
} {1 2}
+# 2025-01-30 Inifinite loop in byte-code discovered by dbsqlfuzz
+# having to do with SubrtnSig logic. The code was using a Subroutine
+# from within itself resulting in infinite recursion.
+#
+# This test will spin forever if the bug has not been fixed, or if
+# it reappears.
+#
+reset_db
+do_execsql_test 4.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t1 VALUES(1,x'1111');
+ CREATE TABLE t2(c);
+ CREATE TABLE t3(d);
+ CREATE TRIGGER t1tr UPDATE ON t1 BEGIN
+ UPDATE t1 SET b=x'2222' FROM t2;
+ UPDATE t1
+ SET b = (SELECT a IN (SELECT a
+ FROM t1
+ WHERE (b,a) IN (SELECT rowid, d
+ FROM t3
+ )
+ )
+ FROM t1 NATURAL RIGHT JOIN t1
+ );
+ END;
+ UPDATE t1 SET b=x'3333';
+ SELECT quote(b) FROM t1;
+} {X'3333'}
+
finish_test
diff --git a/test/like3.test b/test/like3.test
index a93e113d6..0b2857437 100644
--- a/test/like3.test
+++ b/test/like3.test
@@ -275,4 +275,84 @@ do_eqp_test like3-6.240 {
}
}
+#-------------------------------------------------------------------------
+
+ifcapable utf16 {
+ reset_db
+ do_execsql_test like3-7.0 {
+ PRAGMA encoding = 'UTF-16be';
+
+ CREATE TABLE Example(word TEXT NOT NULL);
+ CREATE INDEX Example_word on Example(word);
+
+ INSERT INTO Example VALUES(char(0x307F));
+ }
+
+ do_execsql_test like3-7.1 {
+ SELECT char(0x307F)=='み';
+ } {1}
+
+ do_execsql_test like3-7.1 {
+ SELECT * FROM Example WHERE word GLOB 'み*'
+ } {み}
+
+ do_execsql_test like3-7.2 {
+ SELECT * FROM Example WHERE word >= char(0x307F) AND word < char(0x3080);
+ } {み}
+}
+
+#-------------------------------------------------------------------------
+reset_db
+
+foreach enc {
+ UTF-8
+ UTF-16le
+ UTF-16be
+} {
+ foreach {tn expr} {
+ 1 "CAST (X'FF' AS TEXT)"
+ 2 "CAST (X'FFBF' AS TEXT)"
+ 3 "CAST (X'FFBFBF' AS TEXT)"
+ 4 "CAST (X'FFBFBFBF' AS TEXT)"
+
+ 5 "'abc' || CAST (X'FF' AS TEXT)"
+ 6 "'def' || CAST (X'FFBF' AS TEXT)"
+ 7 "'ghi' || CAST (X'FFBFBF' AS TEXT)"
+ 8 "'jkl' || CAST (X'FFBFBFBF' AS TEXT)"
+ } {
+ reset_db
+ execsql "PRAGMA encoding = '$enc'"
+ set tn utf[string range $enc 4 end].$tn
+ do_execsql_test like3-8.$tn.1 {
+ CREATE TABLE t1(x);
+ }
+
+ do_execsql_test like3-8.$tn.2 {
+ PRAGMA encoding
+ } $enc
+
+ do_execsql_test like3-8.$tn.3 "
+ INSERT INTO t1 VALUES( $expr )
+ "
+
+ do_execsql_test like3-8.$tn.4 {
+ SELECT typeof(x) FROM t1
+ } {text}
+
+ set x [db one {SELECT x || '%' FROM t1}]
+
+ do_execsql_test like3-8.$tn.5 {
+ SELECT rowid FROM t1 WHERE x LIKE $x
+ } 1
+
+ do_execsql_test like3-8.$tn.6 {
+ CREATE INDEX i1 ON t1(x);
+ }
+
+ do_execsql_test like3-8.$tn.7 {
+ SELECT rowid FROM t1 WHERE x LIKE $x
+ } 1
+ }
+}
+
finish_test
diff --git a/test/pragma4.test b/test/pragma4.test
index 0466960ca..2ba87c0c6 100644
--- a/test/pragma4.test
+++ b/test/pragma4.test
@@ -301,7 +301,7 @@ ifcapable vtab {
do_test 6.3 {
set ::log
} {}
- test_sqlite3_log {}
+ test_sqlite3_log
}
# 2024-05-08 https://sqlite.org/forum/forumpost/cf29a33e94
diff --git a/test/speedtest.md b/test/speedtest.md
new file mode 100644
index 000000000..135e562ae
--- /dev/null
+++ b/test/speedtest.md
@@ -0,0 +1,53 @@
+# Performance And Size Measurements
+
+This document shows a procedure for making performance and size
+comparisons between two versions of the SQLite Amalgamation "sqlite3.c".
+You will need:
+
+ * fossil
+ * valgrind
+ * tclsh
+ * A script or program named "open" that brings up *.txt files in an
+ editor for viewing. (Macs provide this by default. You'll need to
+ come up with your own on Linux and Windows.)
+ * An SQLite source tree
+
+The procedure described in this document is not the only way to make
+performance and size measurements. Use this as a guide and make
+adjustments as needed.
+
+## Establish the baseline measurement
+
+ * Begin at the root the SQLite source tree
+ * <b>mkdir -p ../speed</b> <br>
+ &uarr; Speed measurement output files will go into this directory.
+ You can actually put those files wherever you want. This is just a
+ suggestion. It might be good to keep these files outside of the
+ source tree so that "fossil clean" does not delete them.
+ * Obtain the baseline SQLite amalgamation. For the purpose of this
+ technical note, assume the baseline SQLite sources are in files
+ "../baseline/sqlite3.c" and "../baseline/sqlite3.h".
+ * <b>test/speedtest.tcl ../baseline/sqlite3.c ../speed/baseline.txt</b> <br>
+ &uarr; The performance measure will be written into ../speed/baseline.txt
+ and that file will be brought up in an editor for easy viewing. <br>
+ &uarr; The "sqlite3.h" will be taken from the directory that contains
+ the "sqlite3.c" amalgamation file.
+
+## Comparing the current checkout against the baseline
+
+ * <b>make sqlite3.c</b>
+ * <b>test/speedtest.tcl sqlite3.c ../speed/test.txt ../speed/baseline.txt</b> <br>
+ &uarr; Test results written into ../speed/test.txt and then
+ "fossil xdiff" is run to compare ../speed/baseline.txt against
+ the new test results.
+
+## When to do this
+
+Performance and size checks should be done prior to trunk check-ins.
+Sometimes a seemingly innocuous change can have large performance
+impacts. A large impact does not mean that the change cannot continue,
+but it is important to be aware of the impact.
+
+## Additional hints
+
+Use the --help option to test/speedtest.tcl to see other available options.
diff --git a/test/speedtest.tcl b/test/speedtest.tcl
new file mode 100755
index 000000000..1ad92d9ab
--- /dev/null
+++ b/test/speedtest.tcl
@@ -0,0 +1,304 @@
+#!/bin/sh
+# the next line restarts using tclsh \
+exec tclsh "$0" ${1+"$@"}
+#
+# This program runs performance testing on sqlite3.c. Usage:
+set usage {USAGE:
+
+ speedtest.tcl sqlite3.c x1.txt trunk.txt -Os -DSQLITE_ENABLE_STAT4
+ | | | `-----------------------'
+ File to test ----' | | |
+ | | `- options
+ Output filename --------' |
+ `--- optional prior output to diff
+
+Do a cache-grind performance analysis of the sqlite3.c file named and
+write the results into the output file. The ".txt" is appended to the
+output file (and diff-file) name if it is not already present. If the
+diff-file is specified then show a diff from the diff-file to the new
+output.
+
+Other options include:
+ CC=... Specify an alternative C compiler. Default is "gcc".
+ -D... -D and -O options are passed through to the C compiler.
+ --dryrun Show what would happen but don't do anything.
+ --help Show this help screen.
+ --lean "Lean" mode.
+ --lookaside N SZ Lookahead uses N slots of SZ bytes each.
+ --pagesize N Use N as the page size.
+ --quiet | -q "Quite". Put results in file but don't pop up editor
+ --size N Change the test size. 100 means 100%. Default: 5.
+ --testset TEST Specify the specific testset to use. The default
+ is "mix1". Other options include: "main", "json",
+ "cte", "orm", "fp", "rtree".
+}
+set srcfile {}
+set outfile {}
+set difffile {}
+set cflags {-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_THREADSAFE=0}
+set cc gcc
+set testset mix1
+set dryrun 0
+set quiet 0
+set speedtestflags {--shrink-memory --reprepare --stats --heap 40000000 64}
+lappend speedtestflags --journal wal --size 5
+
+for {set i 0} {$i<[llength $argv]} {incr i} {
+ set arg [lindex $argv $i]
+ if {[string index $arg 0]=="-"} {
+ switch -- $arg {
+ -pagesize -
+ --pagesize {
+ lappend speedtestflags --pagesize
+ incr i
+ lappend speedtestflags [lindex $argv $i]
+ }
+ -lookaside -
+ --lookaside {
+ lappend speedtestflags --lookaside
+ incr i
+ lappend speedtestflags [lindex $argv $i]
+ incr i
+ lappend speedtestflags [lindex $argv $i]
+ }
+ -lean -
+ --lean {
+ lappend cflags \
+ -DSQLITE_DEFAULT_MEMSTATUS=0 \
+ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
+ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 \
+ -DSQLITE_MAX_EXPR_DEPTH=1 \
+ -DSQLITE_OMIT_DECLTYPE \
+ -DSQLITE_OMIT_DEPRECATED \
+ -DSQLITE_OMIT_PROGRESS_CALLBACK \
+ -DSQLITE_OMIT_SHARED_CACHE \
+ -DSQLITE_USE_ALLOCA
+ }
+ -testset -
+ --testset {
+ incr i
+ set testset [lindex $argv $i]
+ }
+ -size -
+ --size {
+ incr i
+ set newsize [lindex $argv $i]
+ if {$newsize<1} {set newsize 1}
+ set speedtestflags \
+ [regsub {.-size \d+} $speedtestflags "-size $newsize"]
+ }
+ -n -
+ -dryrun -
+ --dryrun {
+ set dryrun 1
+ }
+ -? -
+ -help -
+ --help {
+ puts $usage
+ exit 0
+ }
+ -q -
+ -quiet -
+ --quiet {
+ set quiet 1
+ }
+ default {
+ lappend cflags $arg
+ }
+ }
+ continue
+ }
+ if {[string match CC=* $arg]} {
+ set cc [lrange $arg 3 end]
+ continue
+ }
+ if {[string match *.c $arg]} {
+ if {$srcfile!=""} {
+ puts stderr "multiple source files: $srcfile $arg"
+ exit 1
+ }
+ set srcfile $arg
+ continue
+ }
+ if {[lsearch {main cte rtree orm fp json parsenumber mix1} $arg]>=0} {
+ set testset $arg
+ continue
+ }
+ if {$outfile==""} {
+ set outfile $arg
+ continue
+ }
+ if {$difffile==""} {
+ set difffile $arg
+ continue
+ }
+ puts stderr "unknown option: \"$arg\". Use --help for more info."
+ exit 1
+}
+if {[lsearch -glob $cflags -O*]<0} {
+ lappend cflags -Os
+}
+if {[lsearch -glob $cflags -DSQLITE_ENABLE_MEMSYS*]<0} {
+ lappend cflags -DSQLITE_ENABLE_MEMSYS5
+}
+if {[lsearch -glob $cflags -DSQLITE_ENABLE_RTREE*]<0} {
+ lappend cflags -DSQLITE_ENABLE_RTREE
+}
+if {$srcfile==""} {
+ puts stderr "no sqlite3.c source file specified"
+ exit 1
+}
+if {![file readable $srcfile]} {
+ puts stderr "source file \"$srcfile\" does not exist"
+ exit 1
+}
+if {$outfile==""} {
+ puts stderr "no output file specified"
+ exit 1
+}
+if {![string match *.* [file tail $outfile]]} {
+ append outfile .txt
+}
+if {$difffile!=""} {
+ if {![file exists $difffile]} {
+ if {[file exists $difffile.txt]} {
+ append difffile .txt
+ } else {
+ puts stderr "No such file: \"$difffile\""
+ exit 1
+ }
+ }
+}
+
+set cccmd [list $cc -g]
+lappend cccmd -I[file dir $srcfile]
+lappend cccmd {*}[lsort $cflags]
+lappend cccmd [file dir $argv0]/speedtest1.c
+lappend cccmd $srcfile
+lappend cccmd -o speedtest1
+puts $cccmd
+if {!$dryrun} {
+ exec {*}$cccmd
+}
+lappend speedtestflags --testset $testset
+set stcmd [list valgrind --tool=cachegrind ./speedtest1 {*}$speedtestflags]
+lappend stcmd speedtest1.db
+lappend stcmd >valgrind-out.txt 2>valgrind-err.txt
+puts $stcmd
+if {!$dryrun} {
+ foreach file {speedtest1.db speedtest1.db-journal speedtest1.db-wal
+ speedtest1.db-shm} {
+ if {[file exists $file]} {file delete $file}
+ }
+ exec {*}$stcmd
+}
+
+set maxmtime 0
+set cgfile {}
+foreach cgout [glob -nocomplain cachegrind.out.*] {
+ if {[file mtime $cgout]>$maxmtime} {
+ set cgfile $cgout
+ set maxmtime [file mtime $cgfile]
+ }
+}
+if {$cgfile==""} {
+ puts "no cachegrind output"
+ exit 1
+}
+
+############# Process the cachegrind.out.# file ##########################
+set fd [open $outfile wb]
+set in [open "|cg_annotate --show=Ir --auto=yes --context=40 $cgfile" r]
+set dest !
+set out(!) {}
+set linenum 0
+set cntlines 0 ;# true to remember cycle counts on each line
+set seenSqlite3 0 ;# true if we have seen the sqlite3.c file
+while {![eof $in]} {
+ set line [string map {\t { }} [gets $in]]
+ if {[regexp {^-- Auto-annotated source: (.*)} $line all name]} {
+ set dest $name
+ if {[string match */sqlite3.c $dest]} {
+ set cntlines 1
+ set seenSqlite3 1
+ } else {
+ set cntlines 0
+ }
+ } elseif {[regexp {^-- line (\d+) ------} $line all ln]} {
+ set line [lreplace $line 2 2 {#}]
+ set linenum [expr {$ln-1}]
+ } elseif {[regexp {^The following files chosen for } $line]} {
+ set dest !
+ }
+ append out($dest) $line\n
+ if {$cntlines} {
+ incr linenum
+ if {[regexp {^ *([0-9,]+) } $line all x]} {
+ set x [string map {, {}} $x]
+ set cycles($linenum) $x
+ }
+ }
+}
+foreach x [lsort [array names out]] {
+ puts $fd $out($x)
+}
+# If the sqlite3.c file has been seen, then output a summary of the
+# cycle counts for each file that went into making up sqlite3.c
+#
+if {$seenSqlite3} {
+ close $in
+ set in [open sqlite3.c]
+ set linenum 0
+ set fn sqlite3.c
+ set pattern1 {^/\*+ Begin file ([^ ]+) \*}
+ set pattern2 {^/\*+ Continuing where we left off in ([^ ]+) \*}
+ while {![eof $in]} {
+ set line [gets $in]
+ incr linenum
+ if {[regexp $pattern1 $line all newfn]} {
+ set fn $newfn
+ } elseif {[regexp $pattern2 $line all newfn]} {
+ set fn $newfn
+ } elseif {[info exists cycles($linenum)]} {
+ incr fcycles($fn) $cycles($linenum)
+ }
+ }
+ close $in
+ puts $fd \
+ {**********************************************************************}
+ set lx {}
+ set sum 0
+ foreach {fn cnt} [array get fcycles] {
+ lappend lx [list $cnt $fn]
+ incr sum $cnt
+ }
+ puts $fd [format {%20s %14d %8.3f%%} TOTAL $sum 100]
+ foreach entry [lsort -index 0 -integer -decreasing $lx] {
+ foreach {cnt fn} $entry break
+ puts $fd [format {%20s %14d %8.3f%%} $fn $cnt [expr {$cnt*100.0/$sum}]]
+ }
+}
+puts $fd "Executable size:"
+close $fd
+exec size speedtest1 >>$outfile
+#
+# Processed cachegrind output should now be in the $outfile
+#############################################################################
+
+if {$quiet} {
+ # Skip this last part of popping up a GUI viewer
+} elseif {$difffile!=""} {
+ set fossilcmd {fossil xdiff --tk -c 20}
+ lappend fossilcmd $difffile
+ lappend fossilcmd $outfile
+ lappend fossilcmd &
+ puts $fossilcmd
+ if {!$dryrun} {
+ exec {*}$fossilcmd
+ }
+} else {
+ if {!$dryrun} {
+ exec open $outfile
+ }
+}
diff --git a/test/speedtest1.c b/test/speedtest1.c
index b0817858a..b49c70098 100644
--- a/test/speedtest1.c
+++ b/test/speedtest1.c
@@ -1,6 +1,28 @@
/*
** A program for performance testing.
**
+** To build this program against an historical version of SQLite for comparison
+** testing:
+**
+** Unix:
+**
+** ./configure --all
+** make clean speedtest1
+** mv speedtest1 speedtest1-current
+** cp $HISTORICAL_SQLITE3_C_H .
+** touch sqlite3.c sqlite3.h .target_source
+** make speedtest1
+** mv speedtest1 speedtest1-baseline
+**
+** Windows:
+**
+** nmake /f Makefile.msc clean speedtest1.exe
+** mv speedtest1.exe speedtest1-current.exe
+** cp $HISTORICAL_SQLITE_C_H .
+** touch sqlite3.c sqlite3.h .target_source
+** nmake /f Makefile.msc speedtest1.exe
+** mv speedtest1.exe speedtest1-baseline.exe
+**
** The available command-line options are described below:
*/
static const char zHelp[] =
@@ -42,7 +64,9 @@ static const char zHelp[] =
" --stats Show statistics at the end\n"
" --stmtscanstatus Activate SQLITE_DBCONFIG_STMT_SCANSTATUS\n"
" --temp N N from 0 to 9. 0: no temp table. 9: all temp tables\n"
- " --testset T Run test-set T (main, cte, rtree, orm, fp, debug)\n"
+ " --testset T Run test-set T (main, cte, rtree, orm, fp, json,\n"
+ " star, app, debug). Can be a comma-separated list\n"
+ " of values, with /SCALE suffixes or macro \"mix1\"\n"
" --trace Turn on SQL tracing\n"
" --threads N Use up to N threads for sorting\n"
" --utf16be Set text encoding to UTF-16BE\n"
@@ -88,6 +112,8 @@ struct HashContext {
/* All global state is held in this structure */
static struct Global {
sqlite3 *db; /* The open database connection */
+ const char *zDbName; /* Name of the database file */
+ const char *zVfs; /* --vfs NAME */
sqlite3_stmt *pStmt; /* Current SQL statement */
sqlite3_int64 iStart; /* Start-time for the current test */
sqlite3_int64 iTotal; /* Total time */
@@ -99,6 +125,7 @@ static struct Global {
int bMemShrink; /* Call sqlite3_db_release_memory() often */
int eTemp; /* 0: no TEMP. 9: always TEMP. */
int szTest; /* Scale factor for test iterations */
+ int szBase; /* Base size prior to testset scaling */
int nRepeat; /* Repeat selects this many times */
int doCheckpoint; /* Run PRAGMA wal_checkpoint after each trans */
int nReserve; /* Reserve bytes */
@@ -1432,6 +1459,561 @@ void testset_fp(void){
speedtest1_end_test();
}
+/*
+** A testset for star-schema queries.
+*/
+void testset_star(void){
+ int n;
+ int i;
+ n = g.szTest*50;
+ speedtest1_begin_test(100, "Create a fact table with %d entries", n);
+ speedtest1_exec(
+ "CREATE TABLE facttab("
+ " attr01 INT,"
+ " attr02 INT,"
+ " attr03 INT,"
+ " data01 TEXT,"
+ " attr04 INT,"
+ " attr05 INT,"
+ " attr06 INT,"
+ " attr07 INT,"
+ " attr08 INT,"
+ " factid INTEGER PRIMARY KEY,"
+ " data02 TEXT"
+ ");"
+ );
+ speedtest1_exec(
+ "WITH RECURSIVE counter(nnn) AS"
+ "(VALUES(1) UNION ALL SELECT nnn+1 FROM counter WHERE nnn<%d)"
+ "INSERT INTO facttab(attr01,attr02,attr03,attr04,attr05,"
+ "attr06,attr07,attr08,data01,data02)"
+ "SELECT random()%%12, random()%%13, random()%%14, random()%%15,"
+ "random()%%16, random()%%17, random()%%18, random()%%19,"
+ "concat('data-',nnn), format('%%x',random()) FROM counter;",
+ n
+ );
+ speedtest1_end_test();
+
+ speedtest1_begin_test(110, "Create indexes on all attributes columns");
+ for(i=1; i<=8; i++){
+ speedtest1_exec(
+ "CREATE INDEX fact_attr%02d ON facttab(attr%02d)", i, i
+ );
+ }
+ speedtest1_end_test();
+
+ speedtest1_begin_test(120, "Create dimension tables");
+ for(i=1; i<=8; i++){
+ speedtest1_exec(
+ "CREATE TABLE dimension%02d("
+ "beta%02d INT, "
+ "content%02d TEXT, "
+ "rate%02d REAL)",
+ i, i, i, i
+ );
+ speedtest1_exec(
+ "WITH RECURSIVE ctr(nn) AS"
+ " (VALUES(1) UNION ALL SELECT nn+1 FROM ctr WHERE nn<%d)"
+ " INSERT INTO dimension%02d"
+ " SELECT nn%%(%d), concat('content-%02d-',nn),"
+ " (random()%%10000)*0.125 FROM ctr;",
+ 4*(i+1), i, 2*(i+1), i
+ );
+ if( i&2 ){
+ speedtest1_exec(
+ "CREATE INDEX dim%02d ON dimension%02d(beta%02d);",
+ i, i, i
+ );
+ }else{
+ speedtest1_exec(
+ "CREATE INDEX dim%02d ON dimension%02d(beta%02d,content%02d);",
+ i, i, i, i
+ );
+ }
+ }
+ speedtest1_end_test();
+
+ speedtest1_begin_test(130, "Star query over the entire fact table");
+ speedtest1_exec(
+ "SELECT count(*), max(content04), min(content03), sum(rate04), avg(rate05)"
+ " FROM facttab, dimension01, dimension02, dimension03, dimension04,"
+ " dimension05, dimension06, dimension07, dimension08"
+ " WHERE attr01=beta01"
+ " AND attr02=beta02"
+ " AND attr03=beta03"
+ " AND attr04=beta04"
+ " AND attr05=beta05"
+ " AND attr06=beta06"
+ " AND attr07=beta07"
+ " AND attr08=beta08"
+ ";"
+ );
+ speedtest1_end_test();
+
+ speedtest1_begin_test(130, "Star query with LEFT JOINs");
+ speedtest1_exec(
+ "SELECT count(*), max(content04), min(content03), sum(rate04), avg(rate05)"
+ " FROM facttab LEFT JOIN dimension01 ON attr01=beta01"
+ " LEFT JOIN dimension02 ON attr02=beta02"
+ " JOIN dimension03 ON attr03=beta03"
+ " JOIN dimension04 ON attr04=beta04"
+ " JOIN dimension05 ON attr05=beta05"
+ " LEFT JOIN dimension06 ON attr06=beta06"
+ " JOIN dimension07 ON attr07=beta07"
+ " JOIN dimension08 ON attr08=beta08"
+ " WHERE facttab.data01 LIKE 'data-9%%'"
+ ";"
+ );
+ speedtest1_end_test();
+}
+
+/*
+** Tests that simulate an application opening and closing an SQLite database
+** frequently. Fossil is used as the model. The focus here is on rapidly
+** parsing the database schema and rapidly generating prepared statements,
+** in other words, rapid start-up of Fossil-like applications.
+**
+** The same database has no data, so the performance of sqlite3_step() is
+** not significant to this testset.
+*/
+static void testset_app(void){
+ int i, n;
+ speedtest1_begin_test(100, "Generate a Fossil-like database schema");
+ speedtest1_exec(
+ "BEGIN;"
+ "CREATE TABLE blob(\n"
+ " rid INTEGER PRIMARY KEY,\n"
+ " rcvid INTEGER,\n"
+ " size INTEGER,\n"
+ " uuid TEXT UNIQUE NOT NULL,\n"
+ " content BLOB,\n"
+ " CHECK( length(uuid)>=40 AND rid>0 )\n"
+ ");\n"
+ "CREATE TABLE delta(\n"
+ " rid INTEGER PRIMARY KEY,\n"
+ " srcid INTEGER NOT NULL REFERENCES blob\n"
+ ");\n"
+ "CREATE TABLE rcvfrom(\n"
+ " rcvid INTEGER PRIMARY KEY,\n"
+ " uid INTEGER REFERENCES user,\n"
+ " mtime DATETIME,\n"
+ " nonce TEXT UNIQUE,\n"
+ " ipaddr TEXT\n"
+ ");\n"
+ "CREATE TABLE private(rid INTEGER PRIMARY KEY);\n"
+ "CREATE TABLE accesslog(\n"
+ " uname TEXT,\n"
+ " ipaddr TEXT,\n"
+ " success BOOLEAN,\n"
+ " mtime TIMESTAMP\n"
+ ");\n"
+ "CREATE TABLE user(\n"
+ " uid INTEGER PRIMARY KEY,\n"
+ " login TEXT UNIQUE,\n"
+ " pw TEXT,\n"
+ " cap TEXT,\n"
+ " cookie TEXT,\n"
+ " ipaddr TEXT,\n"
+ " cexpire DATETIME,\n"
+ " info TEXT,\n"
+ " mtime DATE,\n"
+ " photo BLOB\n"
+ ", jx TEXT DEFAULT '{}');\n"
+ "CREATE TABLE reportfmt(\n"
+ " rn INTEGER PRIMARY KEY,\n"
+ " owner TEXT,\n"
+ " title TEXT UNIQUE,\n"
+ " mtime INTEGER,\n"
+ " cols TEXT,\n"
+ " sqlcode TEXT\n"
+ ", jx TEXT DEFAULT '{}');\n"
+ "CREATE TABLE config(\n"
+ " name TEXT PRIMARY KEY NOT NULL,\n"
+ " value CLOB, mtime INTEGER,\n"
+ " CHECK( typeof(name)='text' AND length(name)>=1 )\n"
+ ") WITHOUT ROWID;\n"
+ "CREATE TABLE shun(uuid PRIMARY KEY, mtime INTEGER, scom TEXT)\n"
+ " WITHOUT ROWID;\n"
+ "CREATE TABLE concealed(\n"
+ " hash TEXT PRIMARY KEY,\n"
+ " content TEXT\n"
+ ", mtime INTEGER) WITHOUT ROWID;\n"
+ "CREATE TABLE admin_log(\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " time INTEGER, -- Seconds since 1970\n"
+ " page TEXT, -- path of page\n"
+ " who TEXT, -- User who made the change\n"
+ " what TEXT -- What changed\n"
+ ");\n"
+ "CREATE TABLE unversioned(\n"
+ " name TEXT PRIMARY KEY,\n"
+ " rcvid INTEGER,\n"
+ " mtime DATETIME,\n"
+ " hash TEXT,\n"
+ " sz INTEGER,\n"
+ " encoding INT,\n"
+ " content BLOB\n"
+ ") WITHOUT ROWID;\n"
+ "CREATE TABLE subscriber(\n"
+ " subscriberId INTEGER PRIMARY KEY,\n"
+ " subscriberCode BLOB DEFAULT (randomblob(32)) UNIQUE,\n"
+ " semail TEXT UNIQUE COLLATE nocase,\n"
+ " suname TEXT,\n"
+ " sverified BOOLEAN DEFAULT true,\n"
+ " sdonotcall BOOLEAN,\n"
+ " sdigest BOOLEAN,\n"
+ " ssub TEXT,\n"
+ " sctime INTDATE,\n"
+ " mtime INTDATE,\n"
+ " smip TEXT\n"
+ ", lastContact INT);\n"
+ "CREATE TABLE pending_alert(\n"
+ " eventid TEXT PRIMARY KEY,\n"
+ " sentSep BOOLEAN DEFAULT false,\n"
+ " sentDigest BOOLEAN DEFAULT false\n"
+ ", sentMod BOOLEAN DEFAULT false) WITHOUT ROWID;\n"
+ "CREATE TABLE filename(\n"
+ " fnid INTEGER PRIMARY KEY,\n"
+ " name TEXT UNIQUE\n"
+ ") STRICT;\n"
+ "CREATE TABLE mlink(\n"
+ " mid INTEGER,\n"
+ " fid INTEGER,\n"
+ " pmid INTEGER,\n"
+ " pid INTEGER,\n"
+ " fnid INTEGER REFERENCES filename,\n"
+ " pfnid INTEGER,\n"
+ " mperm INTEGER,\n"
+ " isaux INT DEFAULT 0\n"
+ ") STRICT;\n"
+ "CREATE TABLE plink(\n"
+ " pid INTEGER REFERENCES blob,\n"
+ " cid INTEGER REFERENCES blob,\n"
+ " isprim INT,\n"
+ " mtime REAL,\n"
+ " baseid INTEGER REFERENCES blob,\n"
+ " UNIQUE(pid, cid)\n"
+ ") STRICT;\n"
+ "CREATE TABLE leaf(rid INTEGER PRIMARY KEY);\n"
+ "CREATE TABLE event(\n"
+ " type TEXT,\n"
+ " mtime REAL,\n"
+ " objid INTEGER PRIMARY KEY,\n"
+ " tagid INTEGER,\n"
+ " uid INTEGER REFERENCES user,\n"
+ " bgcolor TEXT,\n"
+ " euser TEXT,\n"
+ " user TEXT,\n"
+ " ecomment TEXT,\n"
+ " comment TEXT,\n"
+ " brief TEXT,\n"
+ " omtime REAL\n"
+ ") STRICT;\n"
+ "CREATE TABLE phantom(\n"
+ " rid INTEGER PRIMARY KEY\n"
+ ");\n"
+ "CREATE TABLE orphan(\n"
+ " rid INTEGER PRIMARY KEY,\n"
+ " baseline INTEGER\n"
+ ") STRICT;\n"
+ "CREATE TABLE unclustered(\n"
+ " rid INTEGER PRIMARY KEY\n"
+ ");\n"
+ "CREATE TABLE unsent(\n"
+ " rid INTEGER PRIMARY KEY\n"
+ ");\n"
+ "CREATE TABLE tag(\n"
+ " tagid INTEGER PRIMARY KEY,\n"
+ " tagname TEXT UNIQUE\n"
+ ") STRICT;\n"
+ "CREATE TABLE tagxref(\n"
+ " tagid INTEGER REFERENCES tag,\n"
+ " tagtype INTEGER,\n"
+ " srcid INTEGER REFERENCES blob,\n"
+ " origid INTEGER REFERENCES blob,\n"
+ " value TEXT,\n"
+ " mtime REAL,\n"
+ " rid INTEGER REFERENCES blob,\n"
+ " UNIQUE(rid, tagid)\n"
+ ") STRICT;\n"
+ "CREATE TABLE backlink(\n"
+ " target TEXT,\n"
+ " srctype INT,\n"
+ " srcid INT,\n"
+ " mtime REAL,\n"
+ " UNIQUE(target, srctype, srcid)\n"
+ ") STRICT;\n"
+ "CREATE TABLE attachment(\n"
+ " attachid INTEGER PRIMARY KEY,\n"
+ " isLatest INT DEFAULT 0,\n"
+ " mtime REAL,\n"
+ " src TEXT,\n"
+ " target TEXT,\n"
+ " filename TEXT,\n"
+ " comment TEXT,\n"
+ " user TEXT\n"
+ ") STRICT;\n"
+ "CREATE TABLE cherrypick(\n"
+ " parentid INT,\n"
+ " childid INT,\n"
+ " isExclude INT DEFAULT false,\n"
+ " PRIMARY KEY(parentid, childid)\n"
+ ") WITHOUT ROWID, STRICT;\n"
+ "CREATE TABLE vcache(\n"
+ " vid INTEGER, -- check-in ID\n"
+ " fname TEXT, -- filename\n"
+ " rid INTEGER, -- artifact ID\n"
+ " PRIMARY KEY(vid,fname)\n"
+ ") WITHOUT ROWID;\n"
+ "CREATE TABLE synclog(\n"
+ " sfrom TEXT,\n"
+ " sto TEXT,\n"
+ " stime INT NOT NULL,\n"
+ " stype TEXT,\n"
+ " PRIMARY KEY(sfrom,sto)\n"
+ ") WITHOUT ROWID;\n"
+ "CREATE TABLE chat(\n"
+ " msgid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+ " mtime JULIANDAY,\n"
+ " lmtime TEXT,\n"
+ " xfrom TEXT,\n"
+ " xmsg TEXT,\n"
+ " fname TEXT,\n"
+ " fmime TEXT,\n"
+ " mdel INT,\n"
+ " file BLOB\n"
+ ");\n"
+ "CREATE TABLE ftsdocs(\n"
+ " rowid INTEGER PRIMARY KEY,\n"
+ " type CHAR(1),\n"
+ " rid INTEGER,\n"
+ " name TEXT,\n"
+ " idxed BOOLEAN,\n"
+ " label TEXT,\n"
+ " url TEXT,\n"
+ " mtime DATE,\n"
+ " bx TEXT,\n"
+ " UNIQUE(type,rid)\n"
+ ");\n"
+ "CREATE TABLE ticket(\n"
+ " -- Do not change any column that begins with tkt_\n"
+ " tkt_id INTEGER PRIMARY KEY,\n"
+ " tkt_uuid TEXT UNIQUE,\n"
+ " tkt_mtime DATE,\n"
+ " tkt_ctime DATE,\n"
+ " -- Add as many fields as required below this line\n"
+ " type TEXT,\n"
+ " status TEXT,\n"
+ " subsystem TEXT,\n"
+ " priority TEXT,\n"
+ " severity TEXT,\n"
+ " foundin TEXT,\n"
+ " private_contact TEXT,\n"
+ " resolution TEXT,\n"
+ " title TEXT,\n"
+ " comment TEXT\n"
+ ");\n"
+ "CREATE TABLE ticketchng(\n"
+ " -- Do not change any column that begins with tkt_\n"
+ " tkt_id INTEGER REFERENCES ticket,\n"
+ " tkt_rid INTEGER REFERENCES blob,\n"
+ " tkt_mtime DATE,\n"
+ " tkt_user TEXT,\n"
+ " -- Add as many fields as required below this line\n"
+ " login TEXT,\n"
+ " username TEXT,\n"
+ " mimetype TEXT,\n"
+ " icomment TEXT\n"
+ ");\n"
+ "CREATE TABLE forumpost(\n"
+ " fpid INTEGER PRIMARY KEY,\n"
+ " froot INT,\n"
+ " fprev INT,\n"
+ " firt INT,\n"
+ " fmtime REAL\n"
+ ");\n"
+ "CREATE INDEX delta_i1 ON delta(srcid);\n"
+ "CREATE INDEX blob_rcvid ON blob(rcvid);\n"
+ "CREATE INDEX subscriberUname\n"
+ " ON subscriber(suname) WHERE suname IS NOT NULL;\n"
+ "CREATE INDEX mlink_i1 ON mlink(mid);\n"
+ "CREATE INDEX mlink_i2 ON mlink(fnid);\n"
+ "CREATE INDEX mlink_i3 ON mlink(fid);\n"
+ "CREATE INDEX mlink_i4 ON mlink(pid);\n"
+ "CREATE INDEX plink_i2 ON plink(cid,pid);\n"
+ "CREATE INDEX event_i1 ON event(mtime);\n"
+ "CREATE INDEX orphan_baseline ON orphan(baseline);\n"
+ "CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime);\n"
+ "CREATE INDEX backlink_src ON backlink(srcid, srctype);\n"
+ "CREATE INDEX attachment_idx1 ON attachment(target, filename, mtime);\n"
+ "CREATE INDEX attachment_idx2 ON attachment(src);\n"
+ "CREATE INDEX cherrypick_cid ON cherrypick(childid);\n"
+ "CREATE INDEX ftsdocIdxed ON ftsdocs(type,rid,name) WHERE idxed==0;\n"
+ "CREATE INDEX ftsdocName ON ftsdocs(name) WHERE type='w';\n"
+ "CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime);\n"
+ "CREATE INDEX forumthread ON forumpost(froot,fmtime);\n"
+ "CREATE VIEW artifact(rid,rcvid,size,atype,srcid,hash,content) AS\n"
+ " SELECT blob.rid,rcvid,size,1,srcid,uuid,content\n"
+ " FROM blob LEFT JOIN delta ON (blob.rid=delta.rid);\n"
+ "CREATE VIEW ftscontent AS\n"
+ " SELECT rowid, type, rid, name, idxed, label, url, mtime,\n"
+ " title(type,rid,name) AS 'title', body(type,rid,name) AS 'body'\n"
+ " FROM ftsdocs;\n"
+ );
+ if( sqlite3_compileoption_used("ENABLE_FTS5") ){
+ speedtest1_exec(
+ "CREATE VIRTUAL TABLE ftsidx\n"
+ " USING fts5(content=\"ftscontent\", title, body);\n"
+ "CREATE VIRTUAL TABLE chatfts1 USING fts5(\n"
+ " xmsg, content=chat, content_rowid=msgid,tokenize=porter);\n"
+ );
+ }else{
+ speedtest1_exec(
+ "CREATE TABLE ftsidx_data(id INTEGER PRIMARY KEY, block BLOB);\n"
+ "CREATE TABLE ftsidx_idx(segid, term, pgno, PRIMARY KEY(segid, term))\n"
+ " WITHOUT ROWID;\n"
+ "CREATE TABLE ftsidx_docsize(id INTEGER PRIMARY KEY, sz BLOB);\n"
+ "CREATE TABLE ftsidx_config(k PRIMARY KEY, v) WITHOUT ROWID;\n"
+ "CREATE TABLE chatfts1_data(id INTEGER PRIMARY KEY, block BLOB);\n"
+ "CREATE TABLE chatfts1_idx(segid, term, pgno, PRIMARY KEY(segid, term))\n"
+ " WITHOUT ROWID;\n"
+ "CREATE TABLE chatfts1_docsize(id INTEGER PRIMARY KEY, sz BLOB);\n"
+ "CREATE TABLE chatfts1_config(k PRIMARY KEY, v) WITHOUT ROWID;\n"
+ );
+ }
+ speedtest1_exec(
+ "ANALYZE sqlite_schema;\n"
+ "INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES\n"
+ " ('ftsidx_config','ftsidx_config','1 1'),\n"
+ " ('ftsidx_idx','ftsidx_idx','4215 401 1'),\n"
+ " ('user','sqlite_autoindex_user_1','25 1'),\n"
+ " ('phantom',NULL,'26'),\n"
+ " ('reportfmt','sqlite_autoindex_reportfmt_1','9 1'),\n"
+ " ('rcvfrom','sqlite_autoindex_rcvfrom_1','18445 401'),\n"
+ " ('private',NULL,'99'),\n"
+ " ('mlink','mlink_i4','116678 401'),\n"
+ " ('mlink','mlink_i3','121212 2'),\n"
+ " ('mlink','mlink_i2','106372 401'),\n"
+ " ('mlink','mlink_i1','99298 5'),\n"
+ " ('ftsidx_data',NULL,'3795'),\n"
+ " ('leaf',NULL,'1559'),\n"
+ " ('delta','delta_i1','66340 1'),\n"
+ " ('unversioned','unversioned','3 1'),\n"
+ " ('pending_alert','pending_alert','3 1'),\n"
+ " ('cherrypick','cherrypick_cid','680 2'),\n"
+ " ('cherrypick','cherrypick','628 1 1'),\n"
+ " ('config','config','128 1'),\n"
+ " ('ftsidx_docsize',NULL,'33848'),\n"
+ " ('event','event_i1','36096 1'),\n"
+ " ('plink','plink_i2','38236 1 1'),\n"
+ " ('plink','sqlite_autoindex_plink_1','38357 1 1'),\n"
+ " ('shun','shun','10 1'),\n"
+ " ('concealed','concealed','110 1'),\n"
+ " ('vcache','vcache','1888 401 1'),\n"
+ " ('ftsdocs','ftsdocName','19 1'),\n"
+ " ('ftsdocs','ftsdocIdxed','168 84 1 1'),\n"
+ " ('ftsdocs','sqlite_autoindex_ftsdocs_1','37312 401 1'),\n"
+ " ('subscriber','subscriberUname','5 1'),\n"
+ " ('subscriber','sqlite_autoindex_subscriber_2','37 1'),\n"
+ " ('subscriber','sqlite_autoindex_subscriber_1','37 1'),\n"
+ " ('tag','sqlite_autoindex_tag_1','2990 1'),\n"
+ " ('filename','sqlite_autoindex_filename_1','3168 1'),\n"
+ " ('chat',NULL,'56124'),\n"
+ " ('tagxref','tagxref_i1','40992 401 2'),\n"
+ " ('tagxref','sqlite_autoindex_tagxref_1','79233 3 1'),\n"
+ " ('attachment','attachment_idx2','11 1'),\n"
+ " ('attachment','attachment_idx1','11 2 2 1'),\n"
+ " ('blob','blob_rcvid','128240 201'),\n"
+ " ('blob','sqlite_autoindex_blob_1','126480 1'),\n"
+ " ('synclog','synclog','12 3 1'),\n"
+ " ('backlink','backlink_src','2160 2 2'),\n"
+ " ('backlink','sqlite_autoindex_backlink_1','2340 2 2 1'),\n"
+ " ('accesslog',NULL,'38'),\n"
+ " ('chatfts1_config','chatfts1_config','1 1'),\n"
+ " ('chatfts1_idx','chatfts1_idx','688 230 1'),\n"
+ " ('ticket','sqlite_autoindex_ticket_1','794 1'),\n"
+ " ('ticketchng','ticketchng_idx1','2089 3 1'),\n"
+ " ('forumpost','forumthread','4 4 1'),\n"
+ " ('unclustered',NULL,'12');\n"
+ "COMMIT;"
+ );
+ speedtest1_end_test();
+
+ n = g.szTest*3;
+ speedtest1_begin_test(110, "Open and use the database %d times", n);
+ for(i=0; i<n; i++){
+ sqlite3 *dbMain = g.db;
+ sqlite3 *dbAux = 0;
+ if( g.zDbName && g.zDbName[0] ){
+ if( sqlite3_open_v2(g.zDbName, &dbAux, SQLITE_OPEN_READWRITE, g.zVfs) ){
+ fatal_error("Cannot open database file: %s\n", g.zDbName);
+ }
+ g.db = dbAux;
+ }
+ speedtest1_exec(
+ "SELECT name FROM pragma_table_list /*scan*/"
+ " WHERE schema='repository' AND type IN ('table','virtual')"
+ " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
+ "'config','shun','private','reportfmt',"
+ "'concealed','accesslog','modreq',"
+ "'purgeevent','purgeitem','unversioned',"
+ "'subscriber','pending_alert','chat')"
+ " AND name NOT GLOB 'sqlite_*'"
+ " AND name NOT GLOB 'fx_*';"
+ "SELECT 1 FROM pragma_table_xinfo('ticket') WHERE name = 'mimetype';"
+ );
+ speedtest1_exec(
+ "SELECT"
+ " name,"
+ " value,"
+ " unixepoch()/86400-value,"
+ " date(value*86400,'unixepoch')"
+ " FROM config"
+ " WHERE name in ('email-renew-warning','email-renew-cutoff');"
+ "SELECT count(*) FROM pending_alert WHERE NOT sentDigest;"
+ );
+ speedtest1_exec(
+ "WITH priors(rid,who) AS ("
+ " SELECT firt, coalesce(euser,user)"
+ " FROM forumpost LEFT JOIN event ON fpid=objid"
+ " WHERE fpid=12345"
+ " UNION ALL"
+ " SELECT firt, coalesce(euser,user)"
+ " FROM priors, forumpost LEFT JOIN event ON fpid=objid"
+ " WHERE fpid=rid"
+ ")"
+ "SELECT ','||group_concat(DISTINCT 'u'||who)||"
+ "','||group_concat(rid) FROM priors;"
+ );
+ speedtest1_exec(
+ "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);\n"
+ );
+ speedtest1_exec(
+ "WITH RECURSIVE\n"
+ " parent(pid,cid,isCP) AS (\n"
+ " SELECT plink.pid, plink.cid, 0 AS xisCP FROM plink\n"
+ " UNION ALL\n"
+ " SELECT parentid, childid, 1 FROM cherrypick WHERE NOT isExclude\n"
+ " ),\n"
+ " ancestor(rid, mtime, isCP) AS (\n"
+ " SELECT 123, mtime, 0 FROM event WHERE objid=$object\n"
+ " UNION\n"
+ " SELECT parent.pid, event.mtime, parent.isCP\n"
+ " FROM ancestor, parent, event\n"
+ " WHERE parent.cid=ancestor.rid\n"
+ " AND event.objid=parent.pid\n"
+ " AND NOT ancestor.isCP\n"
+ " AND (event.mtime>=$date OR parent.pid=$pid)\n"
+ " ORDER BY mtime DESC LIMIT 10\n"
+ " )\n"
+ " INSERT OR IGNORE INTO ok SELECT rid FROM ancestor;"
+ );
+ sqlite3_close(dbAux);
+ g.db = dbMain;
+ }
+ speedtest1_end_test();
+}
+
#ifdef SQLITE_ENABLE_RTREE
/* Generate two numbers between 1 and mx. The first number is less than
** the second. Usually the numbers are near each other but can sometimes
@@ -2150,6 +2732,120 @@ void testset_debug1(void){
}
/*
+** Performance tests for JSON.
+*/
+void testset_json(void){
+ unsigned int r = 0x12345678;
+ sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, r, g.db);
+ speedtest1_begin_test(100, "table J1 is %d rows of JSONB",
+ g.szTest*5);
+ speedtest1_exec(
+ "CREATE TABLE j1(x JSONB);\n"
+ "WITH RECURSIVE\n"
+ " jval(n,j) AS (\n"
+ " VALUES(0,'{}'),(1,'[]'),(2,'true'),(3,'false'),(4,'null'),\n"
+ " (5,'{x:1,y:2}'),(6,'0.0'),(7,'3.14159'),(8,'-99.9'),\n"
+ " (9,'[1,2,\"\\n\\u2192\\\"\\u2190\",4]')\n"
+ " ),\n"
+ " c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<26*26-1),\n"
+ " array1(y) AS MATERIALIZED (\n"
+ " SELECT jsonb_group_array(\n"
+ " jsonb_object('x',x,\n"
+ " 'y',jsonb(coalesce(j,random()%%10000)),\n"
+ " 'z',hex(randomblob(50)))\n"
+ " )\n"
+ " FROM c LEFT JOIN jval ON (x%%20)=n\n"
+ " ),\n"
+ " object1(z) AS MATERIALIZED (\n"
+ " SELECT jsonb_group_object(char(0x61+x%%26,0x61+(x/26)%%26),\n"
+ " jsonb( coalesce(j,random()%%10000)))\n"
+ " FROM c LEFT JOIN jval ON (x%%20)=n\n"
+ " ),\n"
+ " c2(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c2 WHERE n<%d)\n"
+ "INSERT INTO j1(x)\n"
+ " SELECT jsonb_object('a',n,'b',n+10000,'c',jsonb(y),'d',jsonb(z),\n"
+ " 'e',n+20000,'f',n+30000)\n"
+ " FROM array1, object1, c2;",
+ g.szTest*5
+ );
+ speedtest1_end_test();
+
+ speedtest1_begin_test(110, "table J2 is %d rows from J1 converted to text", g.szTest);
+ speedtest1_exec(
+ "CREATE TABLE j2(x JSON TEXT);\n"
+ "INSERT INTO j2(x) SELECT json(x) FROM j1 LIMIT %d", g.szTest
+ );
+ speedtest1_end_test();
+
+ speedtest1_begin_test(120, "create indexes on JSON expressions on J1");
+ speedtest1_exec(
+ "BEGIN;\n"
+ "CREATE INDEX j1x1 ON j1(x->>'a');\n"
+ "CREATE INDEX j1x2 ON j1(x->>'b');\n"
+ "CREATE INDEX j1x3 ON j1(x->>'f');\n"
+ "COMMIT;\n"
+ );
+ speedtest1_end_test();
+
+ speedtest1_begin_test(130, "create indexes on JSON expressions on J2");
+ speedtest1_exec(
+ "BEGIN;\n"
+ "CREATE INDEX j2x1 ON j2(x->>'a');\n"
+ "CREATE INDEX j2x2 ON j2(x->>'b');\n"
+ "CREATE INDEX j2x3 ON j2(x->>'f');\n"
+ "COMMIT;\n"
+ );
+ speedtest1_end_test();
+
+ speedtest1_begin_test(140, "queries against J1");
+ speedtest1_exec(
+ "WITH c(n) AS (VALUES(0) UNION ALL SELECT n+1 FROM c WHERE n<7)\n"
+ " SELECT sum(x->>format('$.c[%%d].x',n)) FROM c, j1;\n"
+
+ "WITH c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<5)\n"
+ " SELECT sum(x->>format('$.\"c\"[#-%%d].y',n)) FROM c, j1;\n"
+
+ "SELECT sum(x->>'$.d.ez' + x->>'$.d.\"xz\"' + x->>'a' + x->>'$.c[10].y') FROM j1;\n"
+
+ "SELECT x->>'$.d.tz[2]', x->'$.d.tz' FROM j1;\n"
+ );
+ speedtest1_end_test();
+
+ speedtest1_begin_test(141, "queries involving json_type()");
+ speedtest1_exec(
+ "WITH c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<20)\n"
+ " SELECT json_type(x,format('$.c[#-%%d].y',n)), count(*)\n"
+ " FROM c, j1\n"
+ " WHERE j1.rowid=1\n"
+ " GROUP BY 1 ORDER BY 2;"
+ );
+ speedtest1_end_test();
+
+
+ speedtest1_begin_test(150, "json_insert()/set()/remove() on every row of J1");
+ speedtest1_exec(
+ "BEGIN;\n"
+ "UPDATE j1 SET x=jsonb_insert(x,'$.g',(x->>'f')+1,'$.h',3.14159,'$.i','hello',\n"
+ " '$.j',json('{x:99}'),'$.k','{y:98}');\n"
+ "UPDATE j1 SET x=jsonb_set(x,'$.e',(x->>'f')-1);\n"
+ "UPDATE j1 SET x=jsonb_remove(x,'$.d');\n"
+ "COMMIT;\n"
+ );
+ speedtest1_end_test();
+
+ speedtest1_begin_test(160, "json_insert()/set()/remove() on every row of J2");
+ speedtest1_exec(
+ "BEGIN;\n"
+ "UPDATE j2 SET x=json_insert(x,'$.g',(x->>'f')+1);\n"
+ "UPDATE j2 SET x=json_set(x,'$.e',(x->>'f')-1);\n"
+ "UPDATE j2 SET x=json_remove(x,'$.d');\n"
+ "COMMIT;\n"
+ );
+ speedtest1_end_test();
+
+}
+
+/*
** This testset focuses on the speed of parsing numeric literals (integers
** and real numbers). This was added to test the impact of allowing "_"
** characters to appear in numeric SQL literals to make them easier to read.
@@ -2168,25 +2864,25 @@ void testset_parsenumber(void){
const int NROW = 100*g.szTest;
int ii;
- speedtest1_begin_test(100, "parsing small integers");
+ speedtest1_begin_test(100, "parsing %d small integers", NROW);
for(ii=0; ii<NROW; ii++){
sqlite3_exec(g.db, zSql1, 0, 0, 0);
}
speedtest1_end_test();
- speedtest1_begin_test(110, "parsing large integers");
+ speedtest1_begin_test(110, "parsing %d large integers", NROW);
for(ii=0; ii<NROW; ii++){
sqlite3_exec(g.db, zSql2, 0, 0, 0);
}
speedtest1_end_test();
- speedtest1_begin_test(200, "parsing small reals");
+ speedtest1_begin_test(200, "parsing %d small reals", NROW);
for(ii=0; ii<NROW; ii++){
sqlite3_exec(g.db, zSql3, 0, 0, 0);
}
speedtest1_end_test();
- speedtest1_begin_test(210, "parsing large reals");
+ speedtest1_begin_test(210, "parsing %d large reals", NROW);
for(ii=0; ii<NROW; ii++){
sqlite3_exec(g.db, zSql4, 0, 0, 0);
}
@@ -2264,11 +2960,9 @@ int main(int argc, char **argv){
int memDb = 0; /* --memdb. Use an in-memory database */
int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
; /* SQLITE_OPEN_xxx flags. */
- char *zTSet = "main"; /* Which --testset torun */
- const char * zVfs = 0; /* --vfs NAME */
+ char *zTSet = "mix1"; /* Which --testset torun */
int doTrace = 0; /* True for --trace */
const char *zEncoding = 0; /* --utf16be or --utf16le */
- const char *zDbName = 0; /* Name of the test database */
void *pHeap = 0; /* Allocated heap space */
void *pLook = 0; /* Allocated lookaside space */
@@ -2277,6 +2971,10 @@ int main(int argc, char **argv){
int i; /* Loop counter */
int rc; /* API return code */
+ /* "mix1" is a macro testset: */
+ static char zMix1Tests[] =
+ "main,orm/25,cte/20,json,fp/3,parsenumber/25,rtree/10,star,app";
+
#ifdef SQLITE_SPEEDTEST1_WASM
/* Resetting all state is important for the WASM build, which may
** call main() multiple times. */
@@ -2295,10 +2993,13 @@ int main(int argc, char **argv){
sqlite3_libversion(), sqlite3_sourceid());
/* Process command-line arguments */
+ g.zDbName = 0;
+ g.zVfs = 0;
g.zWR = "";
g.zNN = "";
g.zPK = "UNIQUE";
g.szTest = 100;
+ g.szBase = 100;
g.nRepeat = 1;
for(i=1; i<argc; i++){
const char *z = argv[i];
@@ -2408,7 +3109,7 @@ int main(int argc, char **argv){
g.bMemShrink = 1;
}else if( strcmp(z,"size")==0 ){
ARGC_VALUE_CHECK(1);
- g.szTest = integerValue(argv[++i]);
+ g.szTest = g.szBase = integerValue(argv[++i]);
}else if( strcmp(z,"stats")==0 ){
showStats = 1;
}else if( strcmp(z,"temp")==0 ){
@@ -2437,7 +3138,7 @@ int main(int argc, char **argv){
#endif
}else if( strcmp(z,"vfs")==0 ){
ARGC_VALUE_CHECK(1);
- zVfs = argv[++i];
+ g.zVfs = argv[++i];
}else if( strcmp(z,"reserve")==0 ){
ARGC_VALUE_CHECK(1);
g.nReserve = atoi(argv[++i]);
@@ -2467,8 +3168,8 @@ int main(int argc, char **argv){
fatal_error("unknown option: %s\nUse \"%s -?\" for help\n",
argv[i], argv[0]);
}
- }else if( zDbName==0 ){
- zDbName = argv[i];
+ }else if( g.zDbName==0 ){
+ g.zDbName = argv[i];
}else{
fatal_error("surplus argument: %s\nUse \"%s -?\" for help\n",
argv[i], argv[0]);
@@ -2497,8 +3198,8 @@ int main(int argc, char **argv){
#endif
sqlite3_initialize();
- if( zDbName!=0 ){
- sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs);
+ if( g.zDbName!=0 ){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfs);
/* For some VFSes, e.g. opfs, unlink() is not sufficient. Use the
** selected (or default) VFS's xDelete method to delete the
** database. This is specifically important for the "opfs" VFS
@@ -2506,15 +3207,15 @@ int main(int argc, char **argv){
** can be cleaned up properly. For historical compatibility, we'll
** also simply unlink(). */
if( pVfs!=0 ){
- pVfs->xDelete(pVfs, zDbName, 1);
+ pVfs->xDelete(pVfs, g.zDbName, 1);
}
- unlink(zDbName);
+ unlink(g.zDbName);
}
/* Open the database and the input file */
- if( sqlite3_open_v2(memDb ? ":memory:" : zDbName, &g.db,
- openFlags, zVfs) ){
- fatal_error("Cannot open database file: %s\n", zDbName);
+ if( sqlite3_open_v2(memDb ? ":memory:" : g.zDbName, &g.db,
+ openFlags, g.zVfs) ){
+ fatal_error("Cannot open database file: %s\n", g.zDbName);
}
#if SQLITE_VERSION_NUMBER>=3006001
if( nLook>0 && szLook>0 ){
@@ -2572,8 +3273,10 @@ int main(int argc, char **argv){
}
if( g.bExplain ) printf(".explain\n.echo on\n");
+ if( strcmp(zTSet,"mix1")==0 ) zTSet = zMix1Tests;
do{
char *zThisTest = zTSet;
+ char *zSep;
char *zComma = strchr(zThisTest,',');
if( zComma ){
*zComma = 0;
@@ -2581,7 +3284,20 @@ int main(int argc, char **argv){
}else{
zTSet = "";
}
- if( g.iTotal>0 || zComma!=0 ){
+ zSep = strchr(zThisTest, '/');
+ if( zSep ){
+ int kk;
+ for(kk=1; zSep[kk] && ISDIGIT(zSep[kk]); kk++){}
+ if( kk==1 || zSep[kk]!=0 ){
+ fatal_error("bad modifier on testset name: \"%s\"", zThisTest);
+ }
+ g.szTest = g.szBase*integerValue(zSep+1)/100;
+ if( g.szTest<=0 ) g.szTest = 1;
+ zSep[0] = 0;
+ }else{
+ g.szTest = g.szBase;
+ }
+ if( g.iTotal>0 || zComma==0 ){
printf(" Begin testset \"%s\"\n", zThisTest);
}
if( strcmp(zThisTest,"main")==0 ){
@@ -2592,8 +3308,14 @@ int main(int argc, char **argv){
testset_orm();
}else if( strcmp(zThisTest,"cte")==0 ){
testset_cte();
+ }else if( strcmp(zThisTest,"star")==0 ){
+ testset_star();
+ }else if( strcmp(zThisTest,"app")==0 ){
+ testset_app();
}else if( strcmp(zThisTest,"fp")==0 ){
testset_fp();
+ }else if( strcmp(zThisTest,"json")==0 ){
+ testset_json();
}else if( strcmp(zThisTest,"trigger")==0 ){
testset_trigger();
}else if( strcmp(zThisTest,"parsenumber")==0 ){
diff --git a/test/starschema1.test b/test/starschema1.test
index af8168b51..bb7d8aa79 100644
--- a/test/starschema1.test
+++ b/test/starschema1.test
@@ -10,7 +10,7 @@
#***********************************************************************
#
# Test cases for the ability of the query planner to cope with
-# star-schema queries on databases with goofy indexes.
+# star-schema queries.
#
set testdir [file dirname $argv0]
diff --git a/test/testrunner_data.tcl b/test/testrunner_data.tcl
index c749481f5..4685dabf5 100644
--- a/test/testrunner_data.tcl
+++ b/test/testrunner_data.tcl
@@ -98,6 +98,7 @@ namespace eval trd {
set build(All-Debug) {
--with-debug --enable-all
-DSQLITE_ENABLE_ORDERED_SET_AGGREGATES
+ -DSQLITE_ENABLE_NORMALIZE
}
set build(All-O0) {
-O0 --enable-all
@@ -111,6 +112,7 @@ namespace eval trd {
CC=clang -fsanitize=address,undefined -fno-sanitize-recover=undefined
-DSQLITE_ENABLE_STAT4
-DSQLITE_OMIT_LOOKASIDE=1
+ -DSQLITE_ENABLE_NORMALIZE
-DCONFIG_SLOWDOWN_FACTOR=5.0
-DSQLITE_ENABLE_RBU
--with-debug
@@ -169,6 +171,7 @@ namespace eval trd {
-DSQLITE_SOUNDEX=1
-DSQLITE_ENABLE_ATOMIC_WRITE=1
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
+ -DSQLITE_ENABLE_NORMALIZE
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_STMT_SCANSTATUS
@@ -184,6 +187,7 @@ namespace eval trd {
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_MEMSYS5=1
+ -DSQLITE_ENABLE_NORMALIZE
-DSQLITE_ENABLE_COLUMN_METADATA=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_HIDDEN_COLUMNS
@@ -300,6 +304,7 @@ namespace eval trd {
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_FTS3_PARENTHESIS=1
-DSQLITE_ENABLE_FTS3_TOKENIZER=1
+ -DSQLITE_ENABLE_NORMALIZE=1
-DSQLITE_ENABLE_PERSIST_WAL=1
-DSQLITE_ENABLE_PURGEABLE_PCACHE=1
-DSQLITE_ENABLE_RTREE=1
diff --git a/test/trace3.test b/test/trace3.test
index 496cc2360..639aefafa 100644
--- a/test/trace3.test
+++ b/test/trace3.test
@@ -342,5 +342,21 @@ do_test 12.1.2 {
sqlite3_finalize $STMT
} {SQLITE_OK}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 13.0 {
+ CREATE TABLE T1(a, b);
+ INSERT INTO t1 VALUES(1, 2), (3, 4);
+}
+
+proc trace_callback {args} {}
+db trace_v2 trace_callback profile
+
+do_test 13.1 {
+ db eval { SELECT * FROM t1 } {
+ db trace_v2 "" ""
+ }
+ set {} {}
+} {}
finish_test
diff --git a/test/walsetlk3.test b/test/walsetlk3.test
index cbd2f7247..efd5cdf92 100644
--- a/test/walsetlk3.test
+++ b/test/walsetlk3.test
@@ -18,6 +18,7 @@ source $testdir/lock_common.tcl
set testprefix walsetlk3
ifcapable !wal {finish_test ; return }
+ifcapable !setlk_timeout {finish_test ; return }
do_execsql_test 1.0 {
CREATE TABLE t1(x, y);
diff --git a/test/with6.test b/test/with6.test
index 95e630547..b95ec0b76 100644
--- a/test/with6.test
+++ b/test/with6.test
@@ -325,6 +325,12 @@ do_eqp_test 331 {
# marked with M10d_Yes and hence prohibited from participating in the
# query flattening optimization.
#
+# Updated 2025-01-02.
+# https://sqlite.org/forum/forumpost/8f38fc9878a92aa9
+#
+# The same optimization that made Grunthos's query fast made
+# Jean-Noël Mayor's query slow. Bummer.
+#
reset_db
db eval {
CREATE TABLE raw(country,date,total,delta, UNIQUE(country,date));
diff --git a/tool/buildtclext.tcl b/tool/buildtclext.tcl
index c74540c9e..905087d1d 100644
--- a/tool/buildtclext.tcl
+++ b/tool/buildtclext.tcl
@@ -15,6 +15,7 @@ Options:
--info Show info on existing SQLite TCL extension installs
--install-only Install an extension previously build
--uninstall Uninstall the extension
+ --version-check Check extension version against this source tree
--destdir DIR Installation root (used by "make install DESTDIR=...")
Other options are retained and passed through into the compiler.}
@@ -24,6 +25,7 @@ set build 1
set install 1
set uninstall 0
set infoonly 0
+set versioncheck 0
set CC {}
set OPTS {}
set DESTDIR ""; # --destdir "$(DESTDIR)"
@@ -36,11 +38,18 @@ for {set ii 0} {$ii<[llength $argv]} {incr ii} {
} elseif {$a0=="--uninstall"} {
set build 0
set install 0
+ set versioncheck 0
set uninstall 1
} elseif {$a0=="--info"} {
set build 0
set install 0
+ set versioncheck 0
set infoonly 1
+ } elseif {$a0=="--version-check"} {
+ set build 0
+ set install 0
+ set infoonly 0
+ set versioncheck 1
} elseif {$a0=="--cc" && $ii+1<[llength $argv]} {
incr ii
set CC [lindex $argv $ii]
@@ -156,6 +165,33 @@ if {$tcl_platform(platform)=="windows"} {
set CMD [subst $cmd]
}
+# Check the SQLite TCL extension that is loaded by default by this running
+# TCL interpreter to see if it has the same SQLITE_SOURCE_ID as the source
+# code in the directory holding this script.
+#
+if {$versioncheck} {
+ if {[catch {package require sqlite3} msg]} {
+ puts stderr "No SQLite TCL extension available: $msg"
+ exit 1
+ }
+ sqlite3 db :memory:
+ set extvers [db one {SELECT sqlite_source_id()}]
+ db close
+ set fd [open sqlite3.h rb]
+ set sqlite3h [read $fd]
+ close $fd
+ regexp {#define SQLITE_SOURCE_ID +"([^"]+)"} $sqlite3h all srcvers
+ set srcvers [string range $srcvers 0 78]
+ set extvers [string range $extvers 0 78]
+ if {$srcvers==$extvers} {
+ puts "source code and extension versions aligned:\n$extvers"
+ exit 0
+ }
+ puts stderr "source code and extension versions differ"
+ puts stderr "source: $srcvers\nextension: $extvers"
+ exit 1
+}
+
# Show information about prior installs
#
if {$infoonly} {
@@ -253,7 +289,7 @@ if {$build} {
# Tcl package index file, version ???
#
package ifneeded sqlite3 $VERSION \\
- [list load [file join \$dir $OUT] sqlite3]
+ [list load [file join \$dir $OUT] Sqlite3]
}]
close $fd
diff --git a/tool/emcc.sh.in b/tool/emcc.sh.in
index 1263e1b0e..1264df537 100644
--- a/tool/emcc.sh.in
+++ b/tool/emcc.sh.in
@@ -63,4 +63,4 @@ if [ x = "x${emcc}" ]; then
fi
fi
-exec emcc "$@"
+exec $emcc "$@"
diff --git a/tool/mkamalzip.tcl b/tool/mkamalzip.tcl
new file mode 100644
index 000000000..92feb4122
--- /dev/null
+++ b/tool/mkamalzip.tcl
@@ -0,0 +1,23 @@
+#!/usr/bin/tclsh
+#
+# Build a ZIP archive for the amalgamation source code found in the current
+# directory.
+#
+set VERSION-file [file dirname [file dirname [file normalize $argv0]]]/VERSION
+set fd [open ${VERSION-file} rb]
+set vers [read $fd]
+close $fd
+scan $vers %d.%d.%d major minor patch
+set numvers [format {3%02d%02d00} $minor $patch]
+set dir sqlite-amalgamation-$numvers
+file delete -force $dir
+file mkdir $dir
+set filelist {sqlite3.c sqlite3.h shell.c sqlite3ext.h}
+foreach f $filelist {
+ file copy $f $dir/$f
+}
+set cmd "zip -r $dir.zip $dir"
+puts $cmd
+file delete -force $dir.zip
+exec {*}$cmd
+file delete -force $dir
diff --git a/tool/mkautoconfamal.sh b/tool/mkautoconfamal.sh
index 35dbfb41e..c26ca47bf 100644
--- a/tool/mkautoconfamal.sh
+++ b/tool/mkautoconfamal.sh
@@ -13,7 +13,7 @@
#
-# Bail out of the script if any command returns a non-zero exit
+# Bail out of the script if any command returns a non-zero exit
# status. Or if the script tries to use an unset variable. These
# may fail for old /bin/sh interpreters.
#
@@ -22,8 +22,8 @@ set -u
TMPSPACE=./mkpkg_tmp_dir
VERSION=`cat $TOP/VERSION`
-HASH=`sed 's/^\(..........\).*/\1/' $TOP/manifest.uuid`
-DATETIME=`grep '^D' $TOP/manifest | sed -e 's/[^0-9]//g' -e 's/\(............\).*/\1/'`
+HASH=`cut -c1-10 $TOP/manifest.uuid`
+DATETIME=`grep '^D' $TOP/manifest | tr -c -d '[0-9]' | cut -c1-12`
# Verify that the version number in the TEA autoconf file is correct.
# Fail with an error if not.
@@ -34,12 +34,12 @@ else echo "TEA version number mismatch. Should be $VERSION"; exit 1
fi
# If this script is given an argument of --snapshot, then generate a
-# snapshot tarball named for the current checkout SHA1 hash, rather than
+# snapshot tarball named for the current checkout SHA hash, rather than
# the version number.
#
if test "$#" -ge 1 -a x$1 != x--snapshot
then
- # Set global variable $ARTIFACT to the "3xxyyzz" string incorporated
+ # Set global variable $ARTIFACT to the "3xxyyzz" string incorporated
# into artifact filenames. And $VERSION2 to the "3.x.y[.z]" form.
xx=`echo $VERSION|sed 's/3\.\([0-9]*\)\..*/\1/'`
yy=`echo $VERSION|sed 's/3\.[^.]*\.\([0-9]*\).*/\1/'`
@@ -54,6 +54,8 @@ fi
rm -rf $TMPSPACE
cp -R $TOP/autoconf $TMPSPACE
+cp -R $TOP/autosetup $TMPSPACE
+cp -p $TOP/configure $TMPSPACE
cp sqlite3.c $TMPSPACE
cp sqlite3.h $TMPSPACE
cp sqlite3ext.h $TMPSPACE
@@ -63,28 +65,33 @@ cp $TOP/sqlite3.pc.in $TMPSPACE
cp shell.c $TMPSPACE
cp $TOP/src/sqlite3.rc $TMPSPACE
cp $TOP/tool/Replace.cs $TMPSPACE
-
-cat $TMPSPACE/configure.ac |
-sed "s/--SQLITE-VERSION--/$VERSION/" > $TMPSPACE/tmp
-mv $TMPSPACE/tmp $TMPSPACE/configure.ac
+cp $TOP/VERSION $TMPSPACE
+cp $TOP/main.mk $TMPSPACE
cd $TMPSPACE
-autoreconf -i
-#libtoolize
-#aclocal
-#autoconf
-#automake --add-missing
+
+# Clean up emacs-generated backup files from the target
+rm -f ./autosetup/*~
+rm -f ./*~
+
+#if true; then
+ # Clean up *~ files (emacs-generated backups).
+ # This bit is only for use during development of
+ # the autoconf bundle.
+# find . -name '*~' -exec rm \{} \;
+#fi
mkdir -p tea/generic
-echo "#ifdef USE_SYSTEM_SQLITE" > tea/generic/tclsqlite3.c
-echo "# include <sqlite3.h>" >> tea/generic/tclsqlite3.c
-echo "#else" >> tea/generic/tclsqlite3.c
-echo "#include \"sqlite3.c\"" >> tea/generic/tclsqlite3.c
-echo "#endif" >> tea/generic/tclsqlite3.c
+cat <<EOF > tea/generic/tclsqlite3.c
+#ifdef USE_SYSTEM_SQLITE
+# include <sqlite3.h>
+#else
+# include "sqlite3.c"
+#endif
+EOF
cat $TOP/src/tclsqlite.c >> tea/generic/tclsqlite3.c
-cat tea/configure.ac |
- sed "s/AC_INIT(\[sqlite\], .*)/AC_INIT([sqlite], [$VERSION])/" > tmp
+sed "s/AC_INIT(\[sqlite\], .*)/AC_INIT([sqlite], [$VERSION])/" tea/configure.ac > tmp
mv tmp tea/configure.ac
cd tea
@@ -93,9 +100,9 @@ rm -rf autom4te.cache
cd ../
./configure && make dist
-tar -xzf sqlite-$VERSION.tar.gz
+tar xzf sqlite-$VERSION.tar.gz
mv sqlite-$VERSION $TARBALLNAME
-tar -czf $TARBALLNAME.tar.gz $TARBALLNAME
+tar czf $TARBALLNAME.tar.gz $TARBALLNAME
mv $TARBALLNAME.tar.gz ..
cd ..
ls -l $TARBALLNAME.tar.gz
diff --git a/tool/mkshellc.tcl b/tool/mkshellc.tcl
index af9804e4f..85e14f849 100644
--- a/tool/mkshellc.tcl
+++ b/tool/mkshellc.tcl
@@ -12,6 +12,9 @@
set topdir [file dir [file dir [file normal $argv0]]]
set out stdout
fconfigure stdout -translation binary
+if {[lindex $argv 0]!=""} {
+ set out [open [lindex $argv 0] wb]
+}
puts $out {/* DO NOT EDIT!
** This file is automatically generated by the script in the canonical
** SQLite source tree at tool/mkshellc.tcl. That script combines source
diff --git a/tool/mksqlite3c-noext.tcl b/tool/mksqlite3c-noext.tcl
index 845207256..1148b1c0d 100644
--- a/tool/mksqlite3c-noext.tcl
+++ b/tool/mksqlite3c-noext.tcl
@@ -57,7 +57,7 @@ close $in
#
set out [open sqlite3.c w]
# Force the output to use unix line endings, even on Windows.
-fconfigure $out -translation lf
+fconfigure $out -translation binary
set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
puts $out [subst \
{/******************************************************************************
diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl
index 1b3958f46..1d0f89236 100644
--- a/tool/mksqlite3c.tcl
+++ b/tool/mksqlite3c.tcl
@@ -88,7 +88,7 @@ set fname sqlite3.c
if {$enable_recover} { set fname sqlite3r.c }
set out [open $fname wb]
# Force the output to use unix line endings, even on Windows.
-fconfigure $out -translation lf
+fconfigure $out -translation binary
set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
puts $out [subst \
{/******************************************************************************
@@ -130,7 +130,7 @@ if {[file executable $vsrcprog] && [file readable $srcroot/manifest]} {
} else {
puts $out " with changes in files:\n**"
foreach f [lrange $res 1 end] {
- puts $out "** $f"
+ puts $out "** [string trim $f]"
}
}
} else {
diff --git a/tool/mksqlite3h.tcl b/tool/mksqlite3h.tcl
index c242005a0..b1d5ecdcd 100644
--- a/tool/mksqlite3h.tcl
+++ b/tool/mksqlite3h.tcl
@@ -24,18 +24,36 @@
# 6) Adds the SQLITE_CALLBACK calling convention macro in front of all
# callback declarations.
#
-# This script outputs to stdout.
+# This script outputs to stdout unless the -o FILENAME option is used.
#
# Example usage:
#
-# tclsh mksqlite3h.tcl ../sqlite >sqlite3.h
+# tclsh mksqlite3h.tcl ../sqlite [OPTIONS]
+# ^^^^^^^^^
+# Root of source tree
+#
+# Where options are:
+#
+# --enable-recover Include the sqlite3recover extension
+# -o FILENAME Write results to FILENAME instead of stdout
+# --useapicall SQLITE_APICALL instead of SQLITE_CDECL
#
+# Default output stream
+set out stdout
# Get the source tree root directory from the command-line
#
set TOP [lindex $argv 0]
+# If the -o FILENAME option is present, use FILENAME for output.
+#
+set x [lsearch $argv -o]
+if {$x>0} {
+ incr x
+ set out [open [lindex $argv $x] wb]
+}
+
# Enable use of SQLITE_APICALL macros at the right points?
#
set useapicall 0
@@ -44,6 +62,7 @@ set useapicall 0
#
set enable_recover 0
+# Process command-line arguments
if {[lsearch -regexp [lrange $argv 1 end] {^-+useapicall}] != -1} {
set useapicall 1
}
@@ -62,7 +81,7 @@ set nVersion [eval format "%d%03d%03d" [split $zVersion .]]
#
set PWD [pwd]
cd $TOP
-set tmpfile tmp-[clock millisec]-[expr {int(rand()*100000000000)}].txt
+set tmpfile $PWD/tmp-[clock millisec]-[expr {int(rand()*100000000000)}].txt
exec $PWD/mksourceid manifest > $tmpfile
set fd [open $tmpfile rb]
set zSourceId [string trim [read $fd]]
@@ -88,7 +107,7 @@ set declpattern5 \
{^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3rebaser_[_a-zA-Z0-9]+)(\(.*)$}
# Force the output to use unix line endings, even on Windows.
-fconfigure stdout -translation lf
+fconfigure stdout -translation binary
set filelist [subst {
$TOP/src/sqlite.h.in
@@ -118,7 +137,7 @@ set cdecllist {
foreach file $filelist {
set in [open $file rb]
if {![regexp {sqlite\.h\.in} $file]} {
- puts "/******** Begin file [file tail $file] *********/"
+ puts $out "/******** Begin file [file tail $file] *********/"
}
while {![eof $in]} {
@@ -161,11 +180,11 @@ foreach file $filelist {
"(SQLITE_SYSAPI *sqlite3_syscall_ptr)"] $line]
regsub {\(\*} $line {(SQLITE_CALLBACK *} line
}
- puts $line
+ puts $out $line
}
close $in
if {![regexp {sqlite\.h\.in} $file]} {
- puts "/******** End of [file tail $file] *********/"
+ puts $out "/******** End of [file tail $file] *********/"
}
}
-puts "#endif /* SQLITE3_H */"
+puts $out "#endif /* SQLITE3_H */"
diff --git a/tool/mksrczip.tcl b/tool/mksrczip.tcl
new file mode 100644
index 000000000..4431c3d66
--- /dev/null
+++ b/tool/mksrczip.tcl
@@ -0,0 +1,14 @@
+#!/usr/bin/tclsh
+#
+# Build a ZIP archive for the complete, unedited source code that
+# corresponds to the current check-out.
+#
+set VERSION-file [file dirname [file dirname [file normalize $argv0]]]/VERSION
+set fd [open ${VERSION-file} rb]
+set vers [read $fd]
+close $fd
+scan $vers %d.%d.%d major minor patch
+set numvers [format {3%02d%02d00} $minor $patch]
+set cmd "fossil zip current sqlite-src-$numvers.zip --name sqlite-src-$numvers"
+puts $cmd
+exec {*}$cmd
diff --git a/tool/omittest.tcl b/tool/omittest.tcl
index e9033c0bd..0452a4c6f 100644
--- a/tool/omittest.tcl
+++ b/tool/omittest.tcl
@@ -200,8 +200,8 @@ foreach sym $CompileOptionsToTest {
} else {
set opts OPT_FEATURE_FLAGS=-D$sym
}
- puts "make tidy sqlite3.lo $opts"
- if {[catch {exec make tidy sqlite3.lo $opts >& $logfile}]} {
+ puts "make tidy sqlite3.o $opts"
+ if {[catch {exec make tidy sqlite3.o $opts >& $logfile}]} {
puts "BUILD FAILED: see $logfile for details"
if {[info exists FailIsOk($sym)]} {
set Failure($sym) 1
diff --git a/tool/split-sqlite3c.tcl b/tool/split-sqlite3c.tcl
index 0308431da..de4db55a1 100644
--- a/tool/split-sqlite3c.tcl
+++ b/tool/split-sqlite3c.tcl
@@ -15,7 +15,7 @@ set END {^/\*+ End of %s \*+/}
set in [open sqlite3.c]
set out1 [open sqlite3-all.c w]
-fconfigure $out1 -translation lf
+fconfigure $out1 -translation binary
# Copy the header from sqlite3.c into sqlite3-all.c
#
diff --git a/tool/stripccomments.c b/tool/stripccomments.c
index 53933c013..1bdb5c6b8 100644
--- a/tool/stripccomments.c
+++ b/tool/stripccomments.c
@@ -111,7 +111,24 @@ void do_it_all(void){
}
else if(slash == ch){
/* MARKER(("state 0 ==> 1 @ %d:%d\n", line, col)); */
- state = S_SLASH1;
+ if( '\\'==prev ){
+ /**
+ JS regexes may contain slash-asterisks, as happened at:
+
+ https://github.com/emscripten-core/emscripten/issues/23412
+
+ Such regexes will always necessarily be preceeded by a
+ backslash, though.
+
+ It is hypothetically possible for a legitimate comment
+ slash-asterisk to appear immediately before a
+ backslash, but that seems like an even rarer corner
+ case than the JS regex case.
+ */
+ fputc(ch, out);
+ }else{
+ state = S_SLASH1;
+ }
break;
}
fputc(ch, out);