diff --git a/Makefile.in b/Makefile.in index 5b17c0e426..15e61217f2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -323,9 +323,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 +332,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 479b6a669f..93790a8b35 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -2335,7 +2335,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 @@ -2399,7 +2399,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 @@ -2812,7 +2812,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 # <> del /Q $(SQLITE3TCLDLL) pkgIndex.tcl 2>NUL diff --git a/VERSION b/VERSION index 7dd5eda815..549b777ead 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.48.0 +3.49.0 diff --git a/auto.def b/auto.def index c9aa0cb9d1..52c758850c 100644 --- a/auto.def +++ b/auto.def @@ -12,18 +12,17 @@ # # JimTCL: https://jim.tcl.tk # -use cc cc-db cc-shared cc-lib proj pkg-config +use sqlite-config + +if {[string first " " $autosetup(srcdir)] != -1} { + user-error "The pathname of the source tree\ + may not contain space characters" +} +if {[string first " " $autosetup(builddir)] != -1} { + user-error "The pathname of the build directory\ + may not contain space characters" +} -# $DUMP_DEFINES_TXT is the file emitted by --dump-defines, intended -# only for build debugging and not part of the public build interface. -set DUMP_DEFINES_TXT ./config.defines.txt -# $DUMP_DEFINES_JSON is the autosetup counterpart of the historical -# "DEFS" var which was generated by the autotools in the pre-processed -# autotools builds (but not in the canonical tree). Generation of this -# file is disabled (via an empty file name) until/unless someone -# voices a specific interest in it. The original motivating use case -# is handled fine by sqlite_cfg.h. -set DUMP_DEFINES_JSON ""; #./config.defines.json ######################################################################## # Regarding flag compatibility with the historical autotool configure @@ -34,10 +33,9 @@ set DUMP_DEFINES_JSON ""; #./config.defines.json # flags compared to the historical autotools build. The differences # are documented here: # -# 1) --debug is used by autosetup itself, so we have to rename it to -# --with-debug. We cannot use --enable-debug because that is, for -# autosetup, an alias for --debug=1. Alternately, we can patch -# autosetup to use --autosetup-debug for its own purposes instead. +# 1) --debug is used by autosetup itself, but we patch it because +# decades of muscle memory expect --debug to apply to this code, +# not the configure script (details are in autosetup/README.md). # # 2) In autosetup, all flags starting with (--enable, --disable) are # forced to be booleans and receive special handling in how they're @@ -199,9 +197,9 @@ 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.} 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 +207,20 @@ 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 + dump-defines=0 => {Dump autosetup defines to $::sqliteConfig(dump-defines-txt) (for build debugging)} # } -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 +228,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]. } -######################################################################## -# 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 +262,19 @@ 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 -} +define LINK_TOOLS_DYNAMICALLY [proj-opt-was-provided dynlink-tools] -######################################################################## -# 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 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 , which - # some system's don't actually have despite having libedit. If we - # end up finding 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 or . - 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 - } elseif {[string match */editline $rlInc]} { - set editLibDef HAVE_EDITLINE - set rlInc [file dirname $rlInc]; # shell #include's - } - 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 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 - #ifdef HAVE_EDITLINE - #include - #else - #include - #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 - } -} - -######################################################################## -# 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-process-dot-in-files +sqlite-post-config-validation +sqlite-dump-defines diff --git a/autoconf/INSTALL b/autoconf/INSTALL deleted file mode 100644 index a1e89e18ad..0000000000 --- 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 `' 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 1eaa560ff8..0000000000 --- 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 0000000000..0c97f16321 --- /dev/null +++ b/autoconf/Makefile.in @@ -0,0 +1,221 @@ +######################################################################## +# 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. +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.icu = @LDFLAGS_ICU@ +CFLAGS.icu = @CFLAGS_ICU@ +LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@ + +# 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): + $(INSTALL) -d "$@" + + +# +# 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 = \ + $(LDFLAGS.rpath) $(LDFLAGS.pthread) \ + $(LDFLAGS.math) $(LDFLAGS.dlopen) \ + $(LDFLAGS.zlib) $(LDFLAGS.icu) \ + $(LDFLAGS.configure) +LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@ +CFLAGS.libsqlite3 = -I. $(CFLAGS.core) $(CFLAGS.icu) $(OPT_FEATURE_FLAGS) + +sqlite3.o: sqlite3.h sqlite3.c + $(CC) -c 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.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) symlinks..."; \ + cd "$(install-dir.lib)" || exit $$?; \ + 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 +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): shell.c sqlite3.c + $(CC) -o $@ \ + shell.c 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: sqlite3.h $(install-dir.include) + $(INSTALL.noexec) sqlite3.h 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: sqlite3.1 $(install-dir.man1) + $(INSTALL.noexec) sqlite3.1 "$(install-dir.man1)" +install: install-man1 + +clean: + rm -f *.o sqlite3$(T.exe) + rm -f $(libsqlite3.LIB) $(libsqlite3.SO) + +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 1f0e42db4b..47e0a83af8 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 5c2ea0a70f..75c4a76d61 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 b3d3510746..646c0a1215 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 0000000000..12eb3d75c3 --- /dev/null +++ b/autoconf/auto.def @@ -0,0 +1,98 @@ +#/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 { + # + static=1 => {Disable build of static library} + shared=1 => {Disable build of shared library} + # + # + 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} + # + # + 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} + # + # + 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} + # + # + # 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.} + # + 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". + } +} + +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-process-dot-in-files +sqlite-post-config-validation diff --git a/autoconf/configure.ac b/autoconf/configure.ac deleted file mode 100644 index 0c7a32db1f..0000000000 --- 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 8abf8ad02f..e653798fc5 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.49.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 fd426d56d9..19a16c943a 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. @@ -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: @@ -331,8 +347,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/proj.tcl b/autosetup/proj.tcl index a469c898de..88da2112cf 100644 --- a/autosetup/proj.tcl +++ b/autosetup/proj.tcl @@ -184,7 +184,7 @@ proc proj-lshift_ {listVar {count 1}} { # out any lines which begin with an 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]]} { @@ -276,9 +276,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} { @@ -850,16 +850,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 +1119,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 0000000000..9f300e317d --- /dev/null +++ b/autosetup/sqlite-config.tcl @@ -0,0 +1,1349 @@ +# 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. +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 + + 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 "" + } +} + +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 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 + # + # If any configure flags for features are in conflict with + # CFLAGS-specified feature flags, all bets are off. There are no + # guarantees about which one will take precedence. + foreach cf [get-define CFLAGS ""] { + switch -glob -- $cf { + -DSQLITE_OMIT* - + -DSQLITE_ENABLE* { + sqlite-add-feature-flag $cf + } + } + } +} + +######################################################################## +# 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 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 , which + # some system's don't actually have despite having libedit. If we + # end up finding 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 or . + 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 + } elseif {[string match */editline $rlInc]} { + set editLibDef HAVE_EDITLINE + set rlInc [file dirname $rlInc]; # shell #include's + } + 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 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 + #ifdef HAVE_EDITLINE + #include + #else + #include + #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. +proc sqlite-handle-load-extension {} { + 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." + } +} + +######################################################################## +# 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" + } +} + +######################################################################## +# 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-windows.md b/doc/compile-for-windows.md index 717569dd78..2e62286339 100644 --- a/doc/compile-for-windows.md +++ b/doc/compile-for-windows.md @@ -43,8 +43,13 @@ systems, including MacOS. or .
  • Untar or unzip the source archive. CD into the "win/" subfolder of the source tree. -
  • Run: `nmake /f makefile.vc release` -
  • Run: `nmake /f makefile.vc INSTALLDIR=c:\Tcl install` +
  • Run: `nmake /f makefile.vc INSTALLDIR=c:\Tcl release` +
  • Run: `nmake /f makefile.vc INSTALLDIR=c:\Tcl install`
    + Notes: +
      +
    1. The previous two `nmake` commands must be run separately. +
    2. Also, the INSTALLDIR=... argument is required on both. +
  • Optional: CD to `c:\Tcl\bin` and make a copy of `tclsh90.exe` over into just `tclsh.exe`.
  • Optional: diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index a8ac98b699..c53bad8248 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; } @@ -5009,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; @@ -6730,7 +6740,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); } @@ -6741,11 +6751,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); } /* @@ -6946,6 +6955,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. @@ -6973,7 +6992,7 @@ static Fts5TokenDataIter *fts5AppendTokendataIter( } } if( p->rc ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pAppend); + fts5IterClose((Fts5IndexIter*)pAppend); }else{ pRet->apIter[pRet->nIter++] = pAppend; } @@ -7186,7 +7205,7 @@ static Fts5Iter *fts5SetupTokendataIter( fts5BufferSet(&p->rc, &bSeek, nToken, pToken); } if( p->rc ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pNew); + fts5IterClose((Fts5IndexIter*)pNew); break; } @@ -7251,7 +7270,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; } @@ -7380,9 +7399,9 @@ int sqlite3Fts5IndexQuery( } if( p->rc ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pRet); + fts5IterClose((Fts5IndexIter*)pRet); pRet = 0; - sqlite3Fts5IndexCloseReader(p); + fts5IndexCloseReader(p); } *ppIter = (Fts5IndexIter*)pRet; @@ -7632,11 +7651,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); } } @@ -8166,7 +8183,7 @@ static int fts5QueryCksum( rc = sqlite3Fts5IterNext(pIter); } } - sqlite3Fts5IterClose(pIter); + fts5IterClose(pIter); *pCksum = cksum; return rc; diff --git a/ext/fts5/test/fts5faultI.test b/ext/fts5/test/fts5faultI.test index 72f25caee1..ab84d37de5 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 c2e580c564..2aca1986a1 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/misc/base64.c b/ext/misc/base64.c index b8147707f9..17b3bbfc71 100644 --- a/ext/misc/base64.c +++ b/ext/misc/base64.c @@ -198,7 +198,7 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){ deliberate_fall_through; /* FALLTHRU */ case 1: pOut[0] = (qv>>16) & 0xff; - deliberate_fall_through; /* FALLTHRU */ + break; } pOut += nbo; } diff --git a/ext/misc/sqlite3_stdio.c b/ext/misc/sqlite3_stdio.c index 97c3551da2..c9bceb1942 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 fed87e88f3..c274558d17 100644 --- a/ext/misc/vfstrace.c +++ b/ext/misc/vfstrace.c @@ -1033,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 dfc1aa8957..6da9051791 100644 --- a/ext/session/session1.test +++ b/ext/session/session1.test @@ -285,7 +285,7 @@ do_conflict_test $tn.3.2.3 -tables t2 -sql { {FOREIGN_KEY 1} } do_execsql_test $tn.3.2.4 "SELECT * FROM t2" {} -do_db2_test $tn.3.2.5 "SELECT * FROM t2" {1 one 2 two 4 five} +do_db2_test $tn.3.2.5 "SELECT * FROM t2" {4 five} # Test UPDATE changesets. # diff --git a/ext/session/session9.test b/ext/session/session9.test index 6b7d1648b2..5c406c344e 100644 --- a/ext/session/session9.test +++ b/ext/session/session9.test @@ -80,7 +80,7 @@ foreach {tn delrow trans conflictargs conflictret} { 8 3 1 {FOREIGN_KEY 1} ABORT } { - set A(OMIT,0) {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} @@ -95,7 +95,7 @@ foreach {tn delrow trans conflictargs conflictret} { do_test 1.2.$tn.2 { set ::xConflict } $conflictargs - set A(OMIT,0) {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} diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl index 3ff84f1c5e..7c1273bb1a 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 0000000000..e9de4beaba --- /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 e447bc8a16..54e9a62151 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 @@ -111,6 +111,9 @@ do_execsql_test 1.8 { # 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); @@ -164,5 +167,66 @@ 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 f761a3d62b..0e6c1c806b 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -147,11 +147,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 */ @@ -554,22 +556,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; inCol; 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; @@ -906,6 +908,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 @@ -914,10 +917,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 */ @@ -1042,9 +1045,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 */ ){ @@ -1059,6 +1064,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 ); @@ -1066,6 +1072,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; @@ -1075,9 +1083,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(""); @@ -1085,7 +1093,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; @@ -1102,7 +1110,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; @@ -1111,7 +1121,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; @@ -1122,8 +1132,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); @@ -1138,27 +1148,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( 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; + 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); } @@ -1171,6 +1186,7 @@ static int sessionTableInfo( if( pazDflt ) *pazDflt = (const char**)azDflt; *pabPK = abPK; *pnCol = nDbCol; + if( paiIdx ) *paiIdx = aiIdx; }else{ sessionFree(pSession, azCol); } @@ -1202,7 +1218,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 ){ @@ -1237,15 +1254,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 ){ @@ -1268,8 +1287,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 ){ @@ -1587,7 +1608,7 @@ static int sessionUpdateMaxSize( int ii; for(ii=0; iinCol; 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); } } @@ -1607,8 +1628,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; } @@ -1705,11 +1727,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)nTotalColnCol-pTab->bRowid)!=nExpect ){ + if( pTab->nTotalCol!=nExpect ){ pSession->rc = SQLITE_SCHEMA; return; } @@ -1766,14 +1788,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; inCol; 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 ); } @@ -1808,12 +1831,13 @@ static void sessionPreupdateOneChange( sessionPutI64(&pC->aRecord[1], iRowid); nByte = 9; } - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=pTab->bRowid; inCol; 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); } @@ -2215,7 +2239,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 ){ @@ -2792,10 +2817,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}; @@ -2808,9 +2833,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/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. @@ -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,20 @@ $(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) + $$(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 +606,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 @@ -826,7 +813,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 +834,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 +860,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 +909,22 @@ 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),\ +$(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) @@ -961,6 +940,27 @@ sqlite3-api.ext.jses += \ all quick: $(sqlite3-api.ext.jses) q: quick +ifneq (1,$(MAKING_CLEAN)) +######################################################################## +# 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 + ######################################################################## # batch-runner.js is part of one of the test apps which reads in SQL # dumps generated by $(speedtest1) and executes them. @@ -1042,7 +1042,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 +1052,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 +1078,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 6656a2072a..4a527fc5ef 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 0c328310d9..c41e54bd2a 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 to your login shell's resource file (`~/.bashrc` -or equivalent). +Optionally, add that `source` part to your login shell's resource file +(`~/.bashrc` or equivalent). -That `env` script needs to be sourced for building this application -from the top of the sqlite3 build tree: +Another way is to pass the EMSDK dir to configure: ``` +$ ./configure --with-emsdk=/path/to/emsdk +``` + +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. + +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 ebd4aaacb1..ce7e58ebed 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. 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 63e55051c6..3598c0d6fe 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 58882cbd9c..7af12cbe34 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 7fd82a7d6c..a543c14f3a 100644 --- a/ext/wasm/api/post-js-header.js +++ b/ext/wasm/api/post-js-header.js @@ -7,17 +7,22 @@ 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*/){ + /** ^^^ As 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 the Module.postRun handler."); /* This function will contain at least the following: - 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 diff --git a/ext/wasm/api/sqlite3-api-cleanup.js b/ext/wasm/api/sqlite3-api-cleanup.js index 65dbb4eb64..7fb29e6487 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 680218370a..bcaff7243d 100644 --- a/ext/wasm/api/sqlite3-api-glue.c-pp.js +++ b/ext/wasm/api/sqlite3-api-glue.c-pp.js @@ -228,11 +228,36 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }), '*' ]], + /** + 2025-02-03: 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, it is strongly recommended that clients use + wasm.installFunction() to create such callbacks, then pass that + pointer to sqlite3_set_auxdata(). Relying on automated + conversions here will 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. + */ ["sqlite3_set_auxdata", undefined, [ "sqlite3_context*", "int", "*", new wasm.xWrap.FuncPtrAdapter({ name: 'xDestroyAuxData', - signature: 'v(*)', + signature: 'v(p)', contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */] }) ]], @@ -1047,6 +1072,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 c8db3698c1..277efa14ab 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 an Emscripten Module.postRun()-style 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). 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-wasm.c b/ext/wasm/api/sqlite3-wasm.c index c5dd495e54..461afe0663 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 8fe4a990b6..509d33b371 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. */ diff --git a/ext/wasm/config.make.in b/ext/wasm/config.make.in new file mode 100644 index 0000000000..f30baac3f1 --- /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/dist.make b/ext/wasm/dist.make index e820e066d4..60699ff5c0 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 7b778b0205..47bae3f7a9 100644 --- a/ext/wasm/index-dist.html +++ b/ext/wasm/index-dist.html @@ -97,8 +97,8 @@ wrapper is significantly easier to use, however.
  • demo-worker1-promiser: a demo of the Promise-based wrapper of the Worker1 API.
  • -
  • demo-worker1-promiser-esm: - same as the previous demo except loads the promiser from an ESM module.
  • + diff --git a/ext/wasm/index.html b/ext/wasm/index.html index a3d41f1a9c..5d53b62d48 100644 --- a/ext/wasm/index.html +++ b/ext/wasm/index.html @@ -84,8 +84,8 @@ wrapper is significantly easier to use, however.
  • demo-worker1-promiser: a demo of the Promise-based wrapper of the Worker1 API.
  • -
  • demo-worker1-promiser-esm: - same as the previous demo except loads the promiser from an ESM module.
  • +
  • speedtest1 ports (sqlite3's primary benchmarking tool)... diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c index 29b6cafae9..1e09f83c01 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,7 +144,7 @@ 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); @@ -84,14 +153,14 @@ static void mk_pre_post(const char *zName /* build name */, zNM, zNM); pf("$(pre-js.js.%s-%s): $(MAKEFILE)\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); } /* @@ -155,23 +224,23 @@ static void mk_fiddle(){ "$(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,28 @@ 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("$(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", + "$(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); @@ -227,33 +306,45 @@ static void mk_lib_mode(const char *zName /* build name */, /* 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", + 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"); + }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 a21a1c330e..880edcec1d 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,73 @@ 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 args = []; + const pAuxDtor = wasm.installFunction('v(p)', function(ptr){ + //log("freeing auxdata"); + ++pAuxDestructed; + }); + let pAuxDtorDestructed = false; + db.onclose = { + after: ()=>{ + pAuxDtorDestructed = true; + wasm.uninstallFunction(pAuxDtor); + } + }; + try{ + db.createFunction("auxtest",{ + xFunc: function(pCx, x, y){ + args.push(x); + 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, relying + on automated conversions for those is not + recommended. 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(). + */ + capi.sqlite3_set_auxdata(pCx, 0, pAux, pAuxDtor); + }else{ + /* This is never actually hit in this example and it's + not entirely clear how to cause it to. The point of + this test, however, is to demonstrate that the + finalizer impl gets triggered, so we're not going to + fret over this at the moment. */ + //log("seen auxdata",localAux); + T.assert(pAux===localAux); + } + return x; + } + }); + db.exec([ + "create table t(a);", + "insert into t(a) values(1),(2),(3);", + "select auxtest(a,a), auxtest(a,a) from t order by a" + ]); + }finally{ + db.close(); + wasm.pstack.restore(stack); + } + T.assert(6===args.length); + 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 9de5574f26..2c6fa35bdd 100644 --- a/ext/wasm/wasmfs.make +++ b/ext/wasm/wasmfs.make @@ -101,7 +101,7 @@ $(speedtest1-wasmfs.mjs): $(speedtest1.cfiles) $(sqlite3-wasmfs.js) \ $(emcc.flags.sqlite3-wasmfs) \ $(emcc.flags.speedtest1-wasmfs) \ -o $@ $(speedtest1.cfiles) -lm - @$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,1,1) + @$(call SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT,1,1) $(maybe-wasm-strip) $(speedtest1-wasmfs.wasm) chmod -x $(speedtest1-wasmfs.wasm) ls -la $@ $(speedtest1-wasmfs.wasm) diff --git a/main.mk b/main.mk index b6916c2e85..3c9ac0a237 100644 --- a/main.mk +++ b/main.mk @@ -1068,7 +1068,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) @@ -1077,7 +1077,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/ @@ -1509,7 +1509,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) @@ -2019,7 +2019,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) @@ -2033,7 +2033,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 @@ -2212,7 +2212,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. diff --git a/manifest b/manifest index 062e958cd0..77504e331f 100644 --- a/manifest +++ b/manifest @@ -1,31 +1,30 @@ -C Consolidate\smemory\sallocations\smade\swhile\sloading\sstat4\sdata\sin\sa\sway\sthat\smay\sbe\smore\sefficient\son\ssystems\sunder\sload. -D 2025-01-29T17:26:44.487 +C Merge\sall\sthe\slatest\strunk\senhancements\sinto\sthe\sbedrock\sbranch. +D 2025-02-03T15:11:11.716 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d -F Makefile.in ad349acf91b3569033439fe498fa197aa530cafaa01362eb7daad2f84e43d265 +F Makefile.in 38485d15d9190cdad0d7bee25af7b442028865964025dcc61f40fd8d6e369cfc F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0 -F Makefile.msc 7dfa4e65856c90354c058b49df45aa0eb4134d18195bb2f015a42a073e5e342c +F Makefile.msc d7ec4558b2b557048b4394a3834520833f296fbf8cc609de7b31d9de2d696cc1 F README.md c3c0f19532ce28f6297a71870f3c7b424729f0e6d9ab889616d3587dd2332159 -F VERSION 8dc0c3df15fd5ff0622f88fc483533fce990b1cbb2f5fb9fdfb4dbd71eef2889 +F VERSION 01f7606130e48fd58a74d1e45e565f2674819d6eadbc219d328d94bb3362b818 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 e7e92090c98aeb0174d29988c259834eb1b71ae1ea927015c3ef300f6f9b68ae 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 56697ad25ecf23afa317148b06bdc14f85960b42e5ec434ac1ba87f63a3cb789 w autoconf/Makefile.am +F autoconf/Makefile.msc 0a071367537dc395285a5d624ac4f99f3a387b27cc5e89752423c0499e15aec4 +F autoconf/README.first f1d3876e9a7852c22f275a6f06814e64934cecbc0b5b9617d64849094c1fd136 +F autoconf/README.txt 7f01dc3915e2d68f329011073662369e62a0938a2c69398807823c57591cb288 +F autoconf/auto.def 23bc095a3890c0ca334abf7ef67d1c8af4c22c12832bcc738015e868d54fe9d7 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 d22326594f005a493a7857cb4ad2496b91480101be731d7f0541bb8d7eba22a2 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 2737c4eb44b022a694b1f93fb01c3b6c3a45b4f663e18490c2106643a77b39da F autosetup/autosetup df8b53928b1fe3c67db5bc77c8e1eb8160c1b6a26c370e9a06c68748f803b7e4 x F autosetup/autosetup-config.guess dfa101c5e8220e864d5e9c72a85e87110df60260d36cb951ad0a85d6d9eaa463 x F autosetup/autosetup-config.sub a38fb074d0dece01cf919e9fb534a26011608aa8fa606490864295328526cd73 x @@ -50,14 +49,15 @@ F autosetup/cc-shared.tcl 4f024e94a47f427ba61de1739f6381ef0080210f9fae89112d5c1d F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e45f F autosetup/jimsh0.c d40e381ea4526a067590e7b91bd4b2efa6d4980d286f908054c647b3df4aee14 F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba -F autosetup/proj.tcl 2e817159b997077cb79bd871f6255276b787558f386dfc0830b0f825f6a53767 +F autosetup/proj.tcl 9adf1539673cef15bff862d9360b479e6920cc2c0d85de707b0ba31c04ce4531 +F autosetup/sqlite-config.tcl 00af5b9d94d580367bf01984b86397e8d35b74090427def9591a54ded0e1a287 F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9 F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd F doc/begin_concurrent.md 4bee2c3990d1eb800f1ce3726a911292a8e4b889300b2ffd4b08d357370db299 F doc/compile-for-unix.md c9dce1ddd4bf0d25efccc5c63eb047e78c01ce06a6ff29c73e0a8af4a0f4adbc -F doc/compile-for-windows.md 31cddda1d5f34027f1f2b7484d580e7558f22a9875884805b6fdc84d56cab848 +F doc/compile-for-windows.md 5141661e783c9ca9e3fd30e813345898712f5c311d71316f183db87038fa28a6 F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f F doc/jsonb.md 5fab4b8613aa9153fbeb6259297bd4697988af8b3d23900deba588fa7841456b F doc/lemon.html 8b266ff711d2ec7f867c3dca37634963f48a630329908cc282beebfa8c708706 @@ -114,7 +114,7 @@ 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 f1f6da5938af616e0a5e54f0423a3134df95b9f17ac1c6ebf2e2e8132bbc75b9 +F ext/fts5/fts5_index.c a59ccd06af157da2471f356198af14bc37d86e46231e4e1858b2af2f94c2c6e4 F ext/fts5/fts5_main.c 47e7a63a936b5573570be299c13e9eaf2651eb25dce41b3e16430142e682e2c8 F ext/fts5/fts5_storage.c 1ad05dab4830a4e2eaf2900bb143477f93bc17437093582f36f4b818809e88d8 F ext/fts5/fts5_tcl.c 7fb5a3d3404099075aaa2457307cb459bbc257c0de3dbd52b1e80a5b503e0329 @@ -194,7 +194,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 @@ -209,7 +209,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 @@ -403,7 +403,7 @@ 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 95abb0547cb1799d9851f3357c8d7fc3c09a95c63c8772aa3acd5f65f12050f6 +F ext/misc/base64.c 73c31eb325c71bae2e27276565e3f674fc095d8b0d7a651becb3b241a4d2fa57 F ext/misc/base85.c a70c885c5c9350261ea6e7b166038eab21a09cf4fceae856ce41fae9c2213b60 F ext/misc/basexx.c 89ad6b76558efbceb627afd5e2ef1d84b2e96d9aaf9b7ecb20e3d00b51be6fcf F ext/misc/bgckpt.c 18cfc9c39ffab3299f730f86ae2991c8574c0bd9ec80efd2f89196798a7b7181 @@ -446,7 +446,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 @@ -458,7 +458,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 9c4abd2f67ae2760e7a241eca2e8517c64480ac2c3e66a499326e688a9bbee22 +F ext/misc/vfstrace.c a73386403c350b210dc788a2d23a0f5cc89c49b176109a66af11b5078c116331 F ext/misc/vtablog.c 1100250ce8782db37c833e3a9a5c9a3ecf1af5e15b8325572b82e6e0a138ffb5 F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f65b4fc0668 @@ -582,14 +582,14 @@ F ext/session/changebatchfault.test be49c793219bf387ad692a60856b921f0854ad6d F ext/session/changeset.c 7a1e6a14c7e92d36ca177e92e88b5281acd709f3b726298dc34ec0fb58869cb5 F ext/session/changesetfuzz.c 227076ab0ae4447d742c01ee88a564da6478bbf26b65108bf8fac9cd8b0b24aa F ext/session/changesetfuzz1.test 15b629004e58d5ffcc852e6842a603775bb64b1ce51254831f3d12b113b616cd -F ext/session/session1.test 8d0509cd3fcfdee6a33422d5fe5c95a9770d62a0b8588adb0177ecdf79b2c345 +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 be090b1420f3824a573da9e56ff542b1e1c2a4f772118e9ab2f75774e66d25d0 +F ext/session/session9.test 4e3aff62d6b4294498ddbe309076de06f4fddffad4fe5f5a6c033358b01df083 F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f F ext/session/sessionB.test c4fb7f8a688787111606e123a555f18ee04f65bb9f2a4bb2aa71d55ce4e6d02c F ext/session/sessionC.test f8a5508bc059ae646e5ec9bdbca66ad24bc92fe99fda5790ac57e1f59fce2fdf @@ -598,7 +598,8 @@ F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401 F ext/session/sessionG.test 3efe388282d641b65485b5462e67851002cd91a282dc95b685d085eb8efdad0a F ext/session/sessionH.test 29a5441c3dc0a63fa596d745e64bc6c636e062ae04cd89bc84e32c7d98b1fa9b -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 @@ -612,7 +613,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 0f552bd318b764bbc5b2cd6f3518435254a1c830fdaa5aab9c688f507ebc301e +F ext/session/sessionnoact.test 4c7ae5c7d351cb5323bca62b6b095592ad24bd90a6713c178b62ab0063d23e19 F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7 F ext/session/sessionnoop2.test de4672dce88464396ec9f30ed08c6c01643a69c53ae540fadbbf6d30642d64e8 F ext/session/sessionrebase.test 702378bdcb5062f1106e74457beca8797d09c113a81768734a58b197b5b334e2 @@ -622,13 +623,13 @@ F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544 F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc F ext/session/sqlite3changebatch.c d488b42d8fd49fb013a1e9c4535232680dabeb28ae8f9421b65ea0ccc3b430f7 F ext/session/sqlite3changebatch.h e72016998c9a22d439ddfd547b69e1ebac810c24 -F ext/session/sqlite3session.c 40ee1b8d91b95048e6857fd9e63859918c07b577f2462cfb1d6280b1eb7c1036 +F ext/session/sqlite3session.c 5a5c46168f4ac3155b422c23dd7299b7663e747cb9f34735e7a10e2146f07b0b F ext/session/sqlite3session.h 3376dbf372cb00cc0f4e960ca0a0125418638da8c55aad749c9fe7a58a770506 F ext/session/test_session.c 3e9a06d0840013d6411fd17bf7948282224d4c54626cda3a1faa39ac89f0c056 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 47f121d057c08ba49443c06c1c51ba2572e3d5d28a06c968cf0b2ccd5878c3d3 +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 @@ -638,16 +639,16 @@ 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 54b2b4294501b3866245cc94315a16f5424c0e87729d0fb610fba151593c6d26 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 6e2f2eaf681e342fcb047fcdd01d6e3c1b466fb9b45c1acc38676164a8b60f45 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-prologue.js 5ff913355b3144f1c9719d0406667fa6e13eb813c71ed7ce29440e2e65363e82 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 5cc22a3c0d52828cb32aad8691488719f47d27567e63e8bc8b832d74371c352d F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-opfs-async-proxy.js 3774befd97cd1a5e2895c8225a894aad946848c6d9b4028acc988b5d123475af @@ -655,7 +656,7 @@ F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c 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 @@ -666,7 +667,8 @@ 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 d76c69617e95d85ffc9996f7d9d7481df6976dcbd860ecd82bd8c075e3a101ae +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 @@ -676,17 +678,17 @@ F ext/wasm/demo-worker1-promiser.c-pp.html 635cf90685805e21772a5f7a35d1ace80f98a F ext/wasm/demo-worker1-promiser.c-pp.js fcc628cb42fcfaf07d250477801de1e6deb1e319d003976612a0db8d76b9fccc F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d F ext/wasm/demo-worker1.js 836bece8615b17b1b572584f7b15912236a5947fe8c68b98d2737d7e287447ef -F ext/wasm/dist.make 653e212c1e84aa3be168d62a10616ccea45ee9585b0192745d2706707a5248ce +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.html e4bbffdb3d40eff12b3f9c7abedef91787e2935620b7f8d40f2c774b80ad8fa9 +F ext/wasm/index-dist.html 56132399702b15d70c474c3f1952541e25cb0922942868f70daf188f024b3730 +F ext/wasm/index.html 10ff3ad190aadccb713109fa55a38e5c1f3c2a8cf05cd31783745bab3f184079 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 d5885bacf2253bed913cdc7eb16b44f9c9e782133e10600652d1a78841c337af F ext/wasm/module-symbols.html dc476b403369b26a1a23773e13b80f41b9a49f0825e81435fe3600a7cfbbe337 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63 @@ -702,13 +704,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 fb8d0761daaa69bd40c8253cc2d6c8c37ada97e1751b7f07af7369842ba2aeae 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 246580165715eefcb0b063bd58d58e05f179a2c05009caa542f17b222b91fb78 +F main.mk 5f85c6e70d5f9a24d0b1c285b5344136e4df2092070ab9efb932e1a2a6f2c37c F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421 @@ -720,7 +722,7 @@ F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc F sqlite3.pc.in 0977c03a4da7c4204bd60e784a0efb8d51a190448aba78a4e973fe7192bdaf03 F src/alter.c aa93e37e4a36a0525bbb2a2aeda20d2018f0aa995542c7dc658e031375e3f532 F src/analyze.c c5573e4c5442bdcebd38692319fb4636c4b8c17de28be10e9ee9c2b57f7f8794 -F src/attach.c f35bb8cc1fcdde8f6815a7ef09ae413bcac71821d530796800ba24b3c7da1e80 +F src/attach.c 3a5cb9ee4aad6c5b22268287340a4f2f7b07959b7a522201be30fee23cd802e9 F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523 F src/bitvec.c 501daeef838fa82a9fb53540d72f29e3d9172c8867f1e19f94f681e2e20b966e @@ -728,28 +730,28 @@ F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522 F src/btree.c 9145be06761b9947d621e575d3837f9cf265242a013c86b23f28ef4be66b3f3e F src/btree.h df26089b055c4cffe243e5bc98edc729c4ad880bfeb8f229fd16248e4cec10ff F src/btreeInt.h bb28bf05e6206befd5f5fd2ed3825fc6382979fa4a83bf50f1875a0d3404111b -F src/build.c 5a14f6593b9b0002f54d4215febceeaa1354c12f8eca53f8135d3fdf8a93f4d7 -F src/callback.c 43c8ca52b1ecbdec43522f121126fd4e3ee10bc9ca01cdd3ae207cfa419780b6 +F src/build.c 085d2ae28ef3b7301773fbbce74264f1c79f2de9d494942620f8845ea8b0526c +F src/callback.c bd1ecfce052f6a5854497b16e6cae4f39f314d62fe43bd4cdaa452ab93623f3c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c dbd2d51fa2874ad54c673cb71b1f5bbd0df1b8b47b34f31d105f42500680a89a -F src/date.c 89ce1ff20512a7fa5070ba6e7dd5c171148ca7d580955795bf97c79c2456144a -F src/dbpage.c e90410e5d4c0217dfddc4184a81e38ec4903c25d4ec0f201060a0e54e7c2099f +F src/date.c 842c08ac143a56a627b05ac51d68624f2b7b03e3b4cba596205e735eed64ee57 +F src/dbpage.c 2e677acb658a29965e55398bbc61161cb7819da538057c8032adac7ab8e4a8c0 F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42 -F src/expr.c 30a407765d4e4b592f9f958085fb4e8336e54fa46a70ade7f5a67111bc191563 +F src/expr.c 8705be31ee713aaa43c97d91399db09f16ee41b88250406eb99de6b47f550a98 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f -F src/func.c f4bcf21772a5848fa4fe8f45102da6c32653fe8b359823b54133e4b705a2773f +F src/func.c 624f4bd5004e3dbd07f97f0e82288798942e4c54c01bbc2aceacca1d08f9caea F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c f8d1a0f8ee258411009c6b7f2d93170e351bd19f5ad89d57e1180644297cbe70 +F src/insert.c db8bfff30fd7f71812651df3ddf5d1624b9e19104b31e349cd9055bbc9d622c4 F src/json.c 68a98c020c22127f2d65f08855f7fc7460ff352a6ce0b543d8931dde83319c22 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 -F src/main.c ddc4ccd8fa0f3c49b8f002fa16f8c5f299d3a02b76ef8799beb37ff91ea1da1b +F src/main.c e07834d8f6a1d0cfbe54b54642f38abf78afc0f3b2904ad2c059d2534bbf52b8 F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2 @@ -770,12 +772,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 baf68ffa9dec97e0741054404877078c42148a01010b9828d3713831b191d37a +F src/os_unix.c 447cfc845acfd6369556a2295f69c1a7fe8260e91b97cf1b162d959328ed3437 F src/os_win.c 49c7725b500f5867e8360e75eeb30f9d70b62fa1f05c8a101da627210578df32 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a -F src/pager.c 3e48d31c099b99b542e6c8bbfbb9efa32a54679a6c2b58bf92f92efdf9002ddf +F src/pager.c ece5d04a4dbd5723d28c8868975a06a23098c6ffdb320465a56b8c71157f2a0a F src/pager.h dd6ade22dd303a8ca6c34f1ff0f299add7191c1bff65f0289b7fd7c3460f9551 -F src/parse.y 5e6958ec69f538fe98f22dda2ace520eabcda314c651f48546ce72c8c0b4e221 +F src/parse.y 6382e8e5e552e82a0f2f6656771b42fad5cfa83a21235f0b4c3fc3a2750605d5 F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache1.c 430b86e10b8d6ae65832a19a0016f8f65f74207687bc9501c0b15a5908bcb6ad @@ -787,15 +789,15 @@ F src/random.c 9bd018738ec450bf35d28050b4b33fa9a6eebf3aaefb1a1cff42dc14a7725673 F src/resolve.c c8a5372b97b2a2e972a280676f06ddb5b74e885d3b1f5ce383f839907b57ef68 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 96b4e6ed50ec65a372f0beb5d782dbe4776541d6974f80ff8a2538a46d2cae03 -F src/shell.c.in beb370609906092a6810fcd9ea76737be2c91694445061c2eb05c4c0a3753de4 -F src/sqlite.h.in 278a2679a4e50ebe965c5f8e3ec78d52541aa5eeb2632b6eb0a0a395f63b1cea +F src/shell.c.in b377a59822f207106424f08aead37e78b609222e98f86f04cc8a03563ccf3237 +F src/sqlite.h.in df148bd964f83e6953b7c6c03023d7db951422ee66a34b07ece6e57b4bb535f8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 -F src/sqliteInt.h 1fc598d06c6c7d09fbb68791f8e876ba5a72a42421f55c3f14e066f155bee1d2 +F src/sqliteInt.h 2545f879e1c97992c2acc0029632ab41c53b706211b1e599879da7a5b26534ad F src/sqliteLimit.h 1bbdbf72bd0411d003267ffebc59a262f061df5653027a75627d03f48ca30523 F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 -F src/tclsqlite.c c6b9d3a0b1100e1e028460c418c41ca180dac5958e96bef79f6799b552522a37 +F src/tclsqlite.c 5c1e367e26711044730c93d4b81312170918a8d1fe811f45be740ab48f7de8c1 F src/tclsqlite.h 65e2c761446e1c9fa0342b7d2612a703483643c8b6a316d12a65b745a4727395 F src/test1.c 8aacd293374b9428e4a7de7e19aed8bbed07aa8e6001b3f915666a04d19bbea2 F src/test2.c 7ebc518e6735939d8979273a6f7b1d9b5702babf059f6ad62499f7f60a9eb9a3 @@ -847,33 +849,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 d1f3003cb21846828f314a304cf9117f5e80ce0be259315a681d25147004d26d +F src/tokenize.c 375a772e2342274f4bf73605a70633237da09deed00a9bf4c4816a56777ea7c9 +F src/treeview.c d85ce76e6d1498d781957c07cb234da6d77ce0ed2d196480d516f54dabc62279 F src/trigger.c 247e2d712d5edc6021d52a169f6ac9a9c10d7144bc4ac7ea06c1ed2aa414659f F src/update.c 2dd1b745acc9253df1b210ac69137c7a6b290e561d3f42da24418c4e807e889b F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 8b29d9a5956569ea2700f869669b8ef67a9662ee5e724ff77ab3c387e27094ba F src/util.c e5f6a5eeaa26b69054a43bbd0048cfe3d2851f6961052b35aed8f695df922850 F src/vacuum.c 25e407a6dc8b288fa4295b3d92fa9ce9318503e84df53cdf403a50fccbc1ba31 -F src/vdbe.c f567c19f5029f3e221931ced6436c718a1609d2de7fb158de57eac1a0f1e61ce -F src/vdbe.h 9676348d342bd04e21e384c63b57224171ce84fac77853357334ef94c4d33cf4 -F src/vdbeInt.h bf294a0c8fc4cc80779e74b04b8bd82c6e1197b3137cefe0b16cdf002fc7dfd6 -F src/vdbeapi.c 38c252a202d70b56cfb734460bc888ddbd581afec1a10cd4d6c894c9e0b5baea -F src/vdbeaux.c 641abda4f5fab43d391c4b46d9cc60b8db4294a2ad64fb7d5b67189d8c7a2e36 +F src/vdbe.c a54340fd136a2abfc98a3770f659665cf4c767b3c9baafbf936734538034c937 +F src/vdbe.h 3d26d5c7660c5c7bd33ffb0d8784615072d8b23c81f8110870efe2631136bc89 +F src/vdbeInt.h 895b1ab7536f018d3d70d690f6c0adbd1062b6dddce1c2cad912927856d4033c +F src/vdbeapi.c 82fe278a7c71b653235c6f9fb5de0b5de589908dfcb011ba2a782e8becf06f86 +F src/vdbeaux.c 9f1733ce10249ae435643f23562ab7187bb81c04fae1ea2b9873f031eeb702cb F src/vdbeblob.c 255be187436da38b01f276c02e6a08103489bbe2a7c6c21537b7aecbe0e1f797 -F src/vdbemem.c df568ef0187e4be2788c35174f6d9b8566ab9475f9aff2d73907ed05aa5684b2 +F src/vdbemem.c 977438546df236c6a3e7d8b4fe86c0643c13b89b00235db1f11c3a91a4796d30 F src/vdbesort.c d0a3c7056c081703c8b6d91ad60f17da5e062a5c64bf568ed0fa1b5f4cae311f F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 -F src/vtab.c 316cd48e9320660db3047cd306cd056e4361180cebb4d0f10a39244e10c11422 +F src/vtab.c bd4ab699ac4d1ee6da7339d3fbbb5edf23d9737c1fd322ccd75984329d070472 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c f552156ce5f8392b224d56fe99a49e1667cab8429c2b430eed9deaa23abd1542 F src/wal.h 8d02ab8c2a93a941f5898eb3345bf711c1d3f8f86f4be8d5428fb6c074962d8a F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c 604f17baed46f4997ffe79f25c07c4b51a4165a5938cc27fe165c7e1ca485d11 -F src/whereInt.h 1e36ec50392f7cc3d93d1152d4338064cd522b87156a0739388b7e273735f0ca +F src/where.c 09dc313e7223ca1217c39c7026b00f16ff449a8323511a762fcba7863a00f4cd +F src/whereInt.h d20cddddb1d61b18d5cb1fcfa9b77fbeebbc4afe44d996e603452a23b3009ee1 F src/wherecode.c 0c3d3199a2b769a5e2bb70feb5003dc85b3d86842ecaf903a47f2b4205ca5dab -F src/whereexpr.c 0f93a29cabd3a338d09a1f5c6770620a1ac51ec1157f3229502a7e7767c60b6f +F src/whereexpr.c 2415c8eee5ff89a8b709d7d83d71c1ff986cd720d0520057e1d8a5371339012a F src/window.c 2bf01f9941a64fbcead61a0e3cb5db3fca5094b30d2ff0d23274c2a81d2e2385 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -933,7 +935,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 @@ -997,7 +999,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 @@ -1088,7 +1090,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 @@ -1174,7 +1176,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 bdb9c808349a149575b87cf4bfd82d4c81612f0c4d954d27b3f42f043a385396 +F test/fkey6.test ebd11efb00b9c70b57f4c6b6184445145c96e320329bd90a175036570c5b25ca F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d031 F test/fkey8.test 51deda7f1a1448bca95875e4a6e1a3a75b4bd7215e924e845bd60de60e4d84bf F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749 @@ -1326,7 +1328,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 @@ -1420,7 +1422,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 @@ -1697,7 +1699,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 8a9362c1e429318e741b91d26888e7edcc326f98c3aea505ffd618cc5b9e7f0a x +F test/speedtest1.c 204acd8af326bbca2c28f68166635d4574381f4cabbac1bc243663f5dcc5051d F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3 F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33 @@ -1705,7 +1709,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 @@ -1745,7 +1749,7 @@ F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637 F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc F test/tester.tcl b1ffedf6bc6e0044448813e37f3ec3496e35268c35802a508f2f013cf5f74247 F test/testrunner.tcl 90ed8b6c2b26dc1f6af08aeb04670a5df86172f3d9828d8af000f972afa50061 x -F test/testrunner_data.tcl ba4aeea28aa03cfa6fe7e57782ddecb7a7b91c3a0b3251583cb4f0ee002de6a6 +F test/testrunner_data.tcl 63ff9eba1d11a3b0a6fc8446d5fa32da21aabda55b994e8fcbd4a8ce81f48378 F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899 F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1909,7 +1913,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 @@ -2123,7 +2127,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 @@ -2145,7 +2149,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 e82120d672b34b507e1d9cb220ce18c5c36c3ee0ff0328e35f1806ce74ed2266 +F tool/buildtclext.tcl 20726b6b73c7911baa8519a9467b4062104339a5ce57947819884525c56d79e3 F tool/cg_anno.tcl c1f875f5a4c9caca3d59937b16aff716f8b1883935f1b4c9ae23124705bc8099 x F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2 F tool/cktclsh.sh 6075eef9c6b9ba4b38fef2ca2a66d25f2311bd3c610498d18a9b01f861629cca @@ -2154,7 +2158,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 @@ -2175,7 +2179,7 @@ F tool/logest.c c34e5944318415de513d29a6098df247a9618c96d83c38d4abd88641fe46e669 F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439 F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176 F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f005910876a -F tool/mkautoconfamal.sh cbdcf993fa83dccbef7fb77b39cdeb31ef9f77d9d88c9e343b58d35ca3898a6a +F tool/mkautoconfamal.sh 14d2144043c6455958012f92324f4ce7c90a261b5daa2f2c7509498468475f8d F tool/mkccode.tcl 210159febe0ef0ecbc53c79833500663ceaba0115b2b374405818dc835b5f84b x F tool/mkctimec.tcl e78bd291adb921d76565860605b1a9666ea74fb72d5fd671f737aa2faa89bfa5 x F tool/mkkeywordhash.c 6b0be901c47f9ad42215fc995eb2f4384ac49213b1fba395102ec3e999acf559 @@ -2184,12 +2188,12 @@ F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61 F tool/mkopcodeh.tcl 2b4e6967a670ef21bf53a164964c35c6163277d002a4c6f56fa231d68c88d023 F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa F tool/mkpragmatab.tcl d03737ad2ac48928d8225d1c571e487b9b7e73e8c1bdcabd61d69b244614408b -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 5a8d23f35462bfcf74324a19465abd0ad6717b92a404d177160963c292df5d04 +F tool/mksqlite3c.tcl 1b24a4388f544a7f42fc2d03f34422182d3b2263453f65f642890259566369c1 +F tool/mksqlite3h.tcl 3cc8f3fbb3eca38c899549385622637667254067d865a70ad16e0996c2fd3214 F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mksrczip.tcl 81efd9974dbb36005383f2cd655520057a2ae5aa85ac2441a80c7c28f803ac52 F tool/mktoolzip.tcl 34b4e92be544f820e2cc26f143f7d5aec511e826ec394cc82969a5dcf7c7a27c @@ -2228,7 +2232,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 @@ -2242,8 +2246,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 dc74bd8915a9e1a915fb4ff3229a7b5e8f89486fe1df812a7738f6627d379648 -R e6eba16885e8253a0c8420a72196b2b2 -U dan -Z f498dbc7b0d6c6dc50ccede72f5ffcd3 +P af65a902d10e50d827ff31f9ded7d05bc7ab0956a767366e1321b28fcb60b0bd e2d4c1890acfb97b6deda316d5308cea90d39f668319c3b42199b982d746e05c +R 9532ba8fd6bbaaaca5d4ed5415ff2b96 +U drh +Z f4ef86ff9d0108204f2e920b48048359 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9008a1b088..41115289e0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -af65a902d10e50d827ff31f9ded7d05bc7ab0956a767366e1321b28fcb60b0bd +1cef92de5059e468e0b1282425f50b089629c4f74671763bcefcb835798a9124 diff --git a/src/attach.c b/src/attach.c index 9f23dce1ed..399a6cb537 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 d75f2fa8ca..08ea8b4d71 100644 --- a/src/build.c +++ b/src/build.c @@ -4691,7 +4691,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; inId; i++){ sqlite3DbFree(db, pList->a[i].zName); } diff --git a/src/callback.c b/src/callback.c index f78abe049b..c7855d02c9 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 8c48a81fa5..de27366370 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 40ebe4f14a..eb5ab33fe1 100644 --- a/src/dbpage.c +++ b/src/dbpage.c @@ -424,6 +424,7 @@ static int dbpageUpdate( return rc; update_fail: + pTab->pgnoTrunc = 0; sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = sqlite3_mprintf("%s", zErr); return SQLITE_ERROR; diff --git a/src/expr.c b/src/expr.c index ca5b9092e7..8f898a1e3b 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1932,16 +1932,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; inId; 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; } @@ -3465,6 +3462,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; @@ -3511,6 +3509,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 ); @@ -3531,7 +3530,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])); @@ -3574,6 +3572,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; @@ -3709,6 +3708,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 39f3f7661d..a64ada8d9c 100644 --- a/src/func.c +++ b/src/func.c @@ -2697,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), @@ -2729,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 ), @@ -2777,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 ), @@ -2816,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/insert.c b/src/insert.c index d380281bed..83baeece64 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,15 +1072,15 @@ void sqlite3Insert( */ bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; if( pColumn ){ - assert( pColumn->eU4!=EU4_EXPR ); - pColumn->eU4 = EU4_IDX; - for(i=0; inId; i++){ - pColumn->a[i].u4.idx = -1; - } + aTabColMap = sqlite3DbMallocZero(db, pTab->nCol*sizeof(int)); + if( aTabColMap==0 ) goto insert_cleanup; for(i=0; inId; i++){ + const char *zCName = pColumn->a[i].zName; + u8 hName = sqlite3StrIHash(zCName); for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){ - pColumn->a[i].u4.idx = j; + if( pTab->aCol[j].hName!=hName ) continue; + if( sqlite3StrICmp(zCName, pTab->aCol[j].zCnName)==0 ){ + if( aTabColMap[j]==0 ) aTabColMap[j] = i+1; if( i!=j ) bIdListInOrder = 0; if( j==pTab->iPKey ){ ipkColumn = i; assert( !withoutRowid ); @@ -1401,9 +1402,9 @@ void sqlite3Insert( } } if( pColumn ){ - assert( pColumn->eU4==EU4_IDX ); - for(j=0; jnId && 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 +1412,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 +1657,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/main.c b/src/main.c index a6ca315a41..171b57ce8e 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 */ @@ -3321,6 +3324,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 diff --git a/src/os_unix.c b/src/os_unix.c index 5c1e577133..8580337f00 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1685,7 +1685,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 e248e5bfd8..c05ac78e03 100644 --- a/src/pager.c +++ b/src/pager.c @@ -811,7 +811,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 f27f9096da..1b4cf67b51 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1890,7 +1890,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*} @@ -2068,9 +2069,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/shell.c.in b/src/shell.c.in index 17054a961c..fcc9316b00 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -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 }, @@ -11475,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; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index fb70d3837d..c931a7b14d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2223,8 +2223,12 @@ struct sqlite3_mem_methods { **
    ** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    -**
    ^This option takes three additional arguments that determine the -** [lookaside memory allocator] configuration for the [database connection]. +**
    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 not +** in the [DBCONFIG arguments|usual format]. +** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two. ** ^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 @@ -2247,7 +2251,8 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **
    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^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 @@ -2269,13 +2274,13 @@ struct sqlite3_mem_methods { **

    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.)^

    ** ** [[SQLITE_DBCONFIG_ENABLE_VIEW]] **
    SQLITE_DBCONFIG_ENABLE_VIEW
    **
    ^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 @@ -2294,7 +2299,7 @@ struct sqlite3_mem_methods { **
    ^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. @@ -2309,7 +2314,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. @@ -2323,22 +2328,27 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^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 +** schema. This option does not follow the +** [DBCONFIG arguments|usual SQLITE_DBCONFIG argument format]. +** This option takes exactly one argument, which ust 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. **
    ** ** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    -**
    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. +**
    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 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 ** 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. @@ -2500,7 +2510,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.

    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 @@ -2514,7 +2524,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].

    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, @@ -2523,7 +2533,74 @@ struct sqlite3_mem_methods { ** first argument. **

    ** +** [[SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]] +**
    SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE
    +**
    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.

    +** 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. +**

    +** +** [[SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE]] +**
    SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE
    +**
    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.

    +** 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. +**

    +** +** [[SQLITE_DBCONFIG_ENABLE_COMMENTS]] +**
    SQLITE_DBCONFIG_ENABLE_COMMENTS
    +**
    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.

    +** 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. +**

    +** **
    +** +** [[DBCONFIG arguments]]

    Arguments To SQLITE_DBCONFIG Options

    +** +**

    Most of the SQLITE_DBCONFIG options take two arguments: an integer +** and a pointer to an integer. If the first integer 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. +** +**

    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 */ @@ -2545,7 +2622,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 @@ -10773,8 +10853,9 @@ SQLITE_EXPERIMENTAL int sqlite3_wal_info( /* ** 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 255ffb5f2f..dc02b17844 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -881,6 +881,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 +1153,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 +1172,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 */ @@ -1857,6 +1861,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 */ #define SQLITE_NoopUpdate 0x01000000 /* UPDATE operations are no-ops */ /* Flags used only if debugging */ @@ -1917,6 +1924,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 */ /* @@ -3246,13 +3254,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]; }; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 598c9355ff..824e8c4d3c 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -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. @@ -1964,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); } @@ -2993,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); @@ -4021,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/tokenize.c b/src/tokenize.c index b49b2aa16e..fe300ca529 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 2cfcfb69b0..8329659249 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -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, inId-1); - sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0); - sqlite3TreeViewPop(&pView); - } - } + fprintf(stdout, "%s\n", zName); sqlite3TreeViewPop(&pView); } } diff --git a/src/vdbe.c b/src/vdbe.c index 2cccf71090..3c9f86bd7a 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; inMem; 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; } diff --git a/src/vdbe.h b/src/vdbe.h index 71aae29a08..476f1b4ea2 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 2cb4f8c2a1..24cf1ac56c 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 }; diff --git a/src/vdbeapi.c b/src/vdbeapi.c index e33cb2e4d3..0dc09d501e 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 && iIdxpCsr->nField ); - pMem = &p->aNew[iIdx]; + assert( iStore>=0 && iStorepCsr->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 a5e37ab1c4..a972132f2c 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2152,6 +2152,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 ); diff --git a/src/vdbemem.c b/src/vdbemem.c index 0fc6b68f5e..38ba5abe80 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -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; inMem; 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; inMem; 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 76ad3613e8..09f0c2d7f1 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -830,7 +830,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 20b1c38c0c..5cb52b8adb 100644 --- a/src/where.c +++ b/src/where.c @@ -949,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]; @@ -1080,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; inCol; 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 ); @@ -1091,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"; @@ -1147,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); @@ -2415,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; @@ -2426,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); } @@ -2457,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; inLTerm; i++){ @@ -3923,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 */ @@ -5426,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; iLoopbStarUsed ); + aFromTabs = pWInfo->pTabList->a; + pStart = pWInfo->pLoops; + for(iFromIdx=0, m=1; iFromIdxpLoops; 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; + } + } + 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; + } } } 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); - } -#endif - if( pWInfo->nOutStarDelta==0 ){ + + /* 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; - for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ - if( pWLoop->maskSelf==m ){ - pWLoop->rRun -= rDelta; - pWLoop->nOut -= rDelta; - pWLoop->rStarDelta = 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->iTabiTab>iFromIdx ) break; + if( pWLoop->rRun>mxRun ) mxRun = pWLoop->rRun; + } + if( ALWAYS(mxRunpNextLoop){ + if( (pWLoop->maskSelf & mSeen)==0 ) continue; + if( pWLoop->nLTerm ) continue; + if( pWLoop->rRuniTab; + 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->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; } /* @@ -5511,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 */ @@ -5540,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 ); @@ -5608,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 (..) */ @@ -5626,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; @@ -5652,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 @@ -5686,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 @@ -5694,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 @@ -5713,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 @@ -5724,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->rCostrCost==rCost - && (pTo->nRownRow==nOut && pTo->rUnsorted<=rUnsorted) - ) - ) + if( (pTo->rCostrCost==rCost && pTo->nRowrCost==rCost && pTo->nRow==nOut && pTo->rUnsortrCost==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 */ @@ -5755,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 } @@ -5768,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]; jjrCost>mxCost - || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) + || (pTo->rCost==mxCost && pTo->rUnsort>mxUnsort) ){ mxCost = pTo->rCost; - mxUnsorted = pTo->rUnsorted; + mxUnsort = pTo->rUnsort; mxI = jj; } } @@ -5793,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( nDonerCost>rFloor && pTo->rCostrCost; @@ -5810,10 +5968,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ sqlite3DebugPrintf("\n"); } nDone++; + nProgress++; } } rFloor = rMin; - } + }while( nDone0 ); } #endif @@ -5907,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); @@ -6305,7 +6467,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( } } nSearch += pLoop->nOut; - if( pWInfo->nOutStarDelta ) nSearch += pLoop->rStarDelta; } } @@ -6788,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 f262b0eebc..8ba8a7072d 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/whereexpr.c b/src/whereexpr.c index 2b6eb6a78d..4a24dadd23 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]; } - *pC = c + 1; + + /* Increment the value of the last utf8 character in the prefix. */ + while( *pC==0xBF && pC>(u8*)pStr2->u.zToken ){ + *pC = 0x80; + pC--; + } + 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 b294a2721f..1c8ce007f0 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 e65f90e3aa..6319d8284d 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 d22b652b47..2042880a92 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/fkey6.test b/test/fkey6.test index 8658759523..72de926b52 100644 --- a/test/fkey6.test +++ b/test/fkey6.test @@ -250,7 +250,22 @@ 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/in7.test b/test/in7.test index 4dc0821d18..763396140a 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 a93e113d62..0b28574376 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/speedtest.md b/test/speedtest.md new file mode 100644 index 0000000000..135e562aed --- /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 + * mkdir -p ../speed
    + ↑ 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". + * test/speedtest.tcl ../baseline/sqlite3.c ../speed/baseline.txt
    + ↑ The performance measure will be written into ../speed/baseline.txt + and that file will be brought up in an editor for easy viewing.
    + ↑ The "sqlite3.h" will be taken from the directory that contains + the "sqlite3.c" amalgamation file. + +## Comparing the current checkout against the baseline + + * make sqlite3.c + * test/speedtest.tcl sqlite3.c ../speed/test.txt ../speed/baseline.txt
    + ↑ 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 0000000000..93b407c94e --- /dev/null +++ b/test/speedtest.tcl @@ -0,0 +1,290 @@ +#!/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 + --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] + } + -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 >valgrind-out.txt 2>valgrind-err.txt +puts $stcmd +if {!$dryrun} { + 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 b0817858ae..9d8ddc4545 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,10 @@ 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," + " debug)\n" + " Can be a comma-separated list of values, with /SCALE\n" + " 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" @@ -99,6 +124,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 */ @@ -2149,6 +2175,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 "_" @@ -2168,25 +2308,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; ii0 || 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 ){ @@ -2594,6 +2751,8 @@ int main(int argc, char **argv){ testset_cte(); }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 af8168b510..bb7d8aa79b 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 9abfb242da..2cfa7f3b31 100644 --- a/test/testrunner_data.tcl +++ b/test/testrunner_data.tcl @@ -97,6 +97,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 @@ -110,6 +111,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 @@ -168,6 +170,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 @@ -183,6 +186,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 @@ -299,6 +303,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 496cc2360a..639aefafa6 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/with6.test b/test/with6.test index 95e6305474..b95ec0b763 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 26f9b6dcc9..905087d1da 100644 --- a/tool/buildtclext.tcl +++ b/tool/buildtclext.tcl @@ -289,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 1263e1b0ea..1264df5376 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/mkautoconfamal.sh b/tool/mkautoconfamal.sh index 35dbfb41e0..c26ca47bf1 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 " >> 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 < tea/generic/tclsqlite3.c +#ifdef USE_SYSTEM_SQLITE +# include +#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 af9804e4fa..85e14f8498 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.tcl b/tool/mksqlite3c.tcl index 1b3958f460..ddc1e58776 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -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 b409d306b2..8ef123bc72 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 } @@ -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/stripccomments.c b/tool/stripccomments.c index 53933c0138..1bdb5c6b82 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);