diff options
author | dan <Dan Kennedy> | 2025-02-11 17:10:46 +0000 |
---|---|---|
committer | dan <Dan Kennedy> | 2025-02-11 17:10:46 +0000 |
commit | 138951dc2eb7256ae932d4b75266618773eb504b (patch) | |
tree | 9c6f157123d9bd225cc670605bc0324a44305937 | |
parent | 2d878947004909b22c2057eb124b9d00fabe8d82 (diff) | |
parent | 62e1d44846baa68cdfcdcbdd58fcb4483cc5de47 (diff) | |
download | sqlite-138951dc2eb7256ae932d4b75266618773eb504b.tar.gz sqlite-138951dc2eb7256ae932d4b75266618773eb504b.zip |
Merge latest changes from trunk into this branch.
FossilOrigin-Name: e5ec5bb9f4dc3e02db7ab0e49686f47617af75d3f7d4ab23288a1aea4a693e59
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>> @@ -1 +1 @@ -3.48.0 +3.50.0 @@ -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** → + The top-level directory of a Fossil check-out of the TCL source tree. + <li> **SQLITESOURCE** → + A Fossil check-out of the SQLite source tree. + <li> **TCLBUILD** → + 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> + ↑ Or some other version of Tcl8.6. +<li> `fossil clean -x` +<li> `./configure --prefix=$TCLBUILD/tcl86 --disable-shared` <br> + ↑ 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> + ↑ Verify extension installed at $TCLBUILD/tcl86/lib/tcl8.6/sqlite3.* +<li> `make tclextension-list` <br> + ↑ Verify TCL extension correctly installed. +<li> `make tclextension-verify` <br> + ↑ Verify that the correct version is installed. +<li> `$TCLBUILD/tcl86/bin/tclsh8.6 test/testrunner.tcl release --explain` <br> + ↑ 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> + ↑ Or some other version of Tcl9 +<li> `fossil clean -x` +<li> `./configure --prefix=$TCLBUILD/tcl90 --disable-shared` <br> + ↑ 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> + ↑ 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> + ↑ Verify extension installed at $TCLBUILD/tcl90/lib/sqlite3.* +<li> `make tclextension-list` <br> + ↑ Verify TCL extension correctly installed. +<li> `make tclextension-verify` +<li> `$TCLBUILD/tcl90/bin/tclsh9.0 test/testrunner.tcl release --explain` <br> + ↑ 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** → + The top-level directory of a Fossil check-out of the TCL source tree. + <li> **SQLITESOURCE** → + A Fossil check-out of the SQLite source tree. + <li> **TCLBUILD** → + 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** → + 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> + ↑ Or some other version of Tcl8.6. +<li> `fossil clean -x` +<li> `set INSTALLDIR=%TCLBUILD%\tcl86` +<li> `nmake /f makefile.vc release` <br> + ⇅ 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> + ↑ 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> + ↑ 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> + ↑ Or some other version of Tcl9 +<li> `fossil clean -x` +<li> `set INSTALLDIR=%TCLBUILD%\tcl90` +<li> `nmake /f makefile.vc release` <br> + ⇅ 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> + ↑ Verify extension installed at %TCLBUILD%\\tcl90\\lib\\sqlite3.* +<li> `nmake /f Makefile.msc tclextension-verify` +<li> `tclsh90 test/testrunner.tcl release --explain` <br> + ↑ 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(¤tTime); SystemTimeToFileTime(¤tTime, &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) @@ -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) @@ -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 Binary files differindex 3e3418007..469df2c68 100644 --- a/test/fuzzdata8.db +++ b/test/fuzzdata8.db 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> + ↑ 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> + ↑ The performance measure will be written into ../speed/baseline.txt + and that file will be brought up in an editor for easy viewing. <br> + ↑ 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> + ↑ 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); |