aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in3
-rw-r--r--auto.def7
-rw-r--r--autoconf/Makefile.in10
-rw-r--r--autoconf/auto.def3
-rw-r--r--autosetup/README.md105
-rw-r--r--autosetup/proj.tcl35
-rw-r--r--autosetup/sqlite-config.tcl99
-rw-r--r--ext/fts3/fts3Int.h19
-rw-r--r--ext/fts3/fts3_expr.c52
-rw-r--r--ext/fts3/fts3_snippet.c26
-rw-r--r--ext/fts5/fts5Int.h17
-rw-r--r--ext/fts5/fts5_expr.c55
-rw-r--r--ext/fts5/fts5_index.c73
-rw-r--r--ext/fts5/fts5_main.c6
-rw-r--r--ext/misc/series.c21
-rw-r--r--ext/recover/sqlite3recover.c17
-rw-r--r--ext/rtree/rtree.c17
-rw-r--r--ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js79
-rw-r--r--ext/wasm/mkwasmbuilds.c7
-rw-r--r--ext/wasm/tester1.c-pp.js2
-rw-r--r--ext/wasm/tests/opfs/sahpool/digest-worker.js94
-rw-r--r--ext/wasm/tests/opfs/sahpool/digest.html151
-rw-r--r--main.mk114
-rw-r--r--manifest104
-rw-r--r--manifest.uuid2
-rw-r--r--src/build.c17
-rw-r--r--src/expr.c13
-rw-r--r--src/main.c2
-rw-r--r--src/resolve.c16
-rw-r--r--src/select.c13
-rw-r--r--src/shell.c.in2
-rw-r--r--src/sqliteInt.h61
-rw-r--r--src/trigger.c16
-rw-r--r--src/vdbe.c12
-rw-r--r--src/vdbe.h4
-rw-r--r--src/vdbeInt.h27
-rw-r--r--src/vdbeapi.c6
-rw-r--r--src/vdbeaux.c17
-rw-r--r--src/vdbeblob.c9
-rw-r--r--src/vdbesort.c9
-rw-r--r--src/wal.c9
-rw-r--r--src/where.c20
-rw-r--r--src/whereInt.h7
-rw-r--r--src/wherecode.c17
-rw-r--r--test/bloom1.test41
-rw-r--r--test/fuzzcheck.c96
-rw-r--r--test/shell2.test12
-rw-r--r--test/tabfunc01.test30
-rwxr-xr-xtool/mkccode.tcl13
-rw-r--r--tool/sqlite3_analyzer.c.in1
50 files changed, 1195 insertions, 393 deletions
diff --git a/Makefile.in b/Makefile.in
index 2abf714e5..6a2ba323a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -135,6 +135,9 @@ ENABLE_LIB_STATIC = @ENABLE_LIB_STATIC@
HAVE_WASI_SDK = @HAVE_WASI_SDK@
libsqlite3.DLL.install-rules = @SQLITE_DLL_INSTALL_RULES@
+# -fsanitize flags for the fuzzcheck-asap app
+CFLAGS.fuzzcheck-asan.fsanitize = @CFLAGS_ASAN_FSANITIZE@
+
T.cc.sqlite = $(T.cc) @TARGET_DEBUG@
#
diff --git a/auto.def b/auto.def
index c4fb2c5ab..ee852dddf 100644
--- a/auto.def
+++ b/auto.def
@@ -25,7 +25,7 @@ sqlite-configure canonical {
# -------------^^^^^^^ intentionally using [get-env] instead of
# [proj-get-env] here because [sqlite-setup-default-cflags] uses
# [proj-get-env] and we want this to supercede that.
- sqlite-munge-cflags
+ sqlite-munge-cflags; # straighten out -DSQLITE_ENABLE/OMIT flags
}
sqlite-check-common-bins ;# must come before [sqlite-handle-wasi-sdk]
sqlite-handle-wasi-sdk ;# must run relatively early, as it changes the environment
@@ -46,6 +46,11 @@ sqlite-configure canonical {
define LINK_TOOLS_DYNAMICALLY [proj-opt-was-provided dynlink-tools]
+ if {[set fsan [join [opt-val asan-fsanitize] ","]] in {auto ""}} {
+ set fsan address,bounds-strict
+ }
+ define CFLAGS_ASAN_FSANITIZE [proj-check-fsanitize [split $fsan ", "]]
+
sqlite-handle-tcl
sqlite-handle-emsdk
diff --git a/autoconf/Makefile.in b/autoconf/Makefile.in
index e59864a20..0fa9065be 100644
--- a/autoconf/Makefile.in
+++ b/autoconf/Makefile.in
@@ -50,6 +50,7 @@ CC = @CC@
ENABLE_LIB_SHARED = @ENABLE_LIB_SHARED@
ENABLE_LIB_STATIC = @ENABLE_LIB_STATIC@
+HAVE_WASI_SDK = @HAVE_WASI_SDK@
CFLAGS = @CFLAGS@ @CPPFLAGS@
#
@@ -236,11 +237,14 @@ sqlite3$(T.exe): $(TOP)/shell.c $(sqlite3-shell-deps.$(ENABLE_STATIC_SHELL))
$(CFLAGS) $(CFLAGS.readline) $(CFLAGS.icu) \
$(LDFLAGS) $(LDFLAGS.readline)
-all: sqlite3$(T.exe)
+sqlite3$(T.exe)-1:
+sqlite3$(T.exe)-0: sqlite3$(T.exe)
+all: sqlite3$(T.exe)-$(HAVE_WASI_SDK)
-install-shell: sqlite3$(T.exe) $(install-dir.bin)
+install-shell-0: sqlite3$(T.exe) $(install-dir.bin)
$(INSTALL.strip) sqlite3$(T.exe) "$(install-dir.bin)"
-install: install-shell
+install-shell-1:
+install: install-shell-$(HAVE_WASI_SDK)
install-headers: $(TOP)/sqlite3.h $(install-dir.include)
$(INSTALL.noexec) $(TOP)/sqlite3.h $(TOP)/sqlite3ext.h "$(install-dir.include)"
diff --git a/autoconf/auto.def b/autoconf/auto.def
index 3ba900d95..5d7ff8391 100644
--- a/autoconf/auto.def
+++ b/autoconf/auto.def
@@ -5,6 +5,7 @@
# "autoconf" bundle of the SQLite project.
use sqlite-config
sqlite-configure autoconf {
- sqlite-check-common-bins
+ 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
}
diff --git a/autosetup/README.md b/autosetup/README.md
index 2d6cf723c..a61f94fbd 100644
--- a/autosetup/README.md
+++ b/autosetup/README.md
@@ -14,7 +14,7 @@ build infrastructure. It is not an [Autosetup][] reference.
- Symbolic Names of Feature Flags
- Do Not Update Global Shared State
- [Updating Autosetup](#updating)
- - [Patching Autosetup for Project-local changes](#patching)
+ - ***[Patching Autosetup for Project-local changes](#patching)***
------------------------------------------------------------------------
@@ -42,12 +42,13 @@ following files:
(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...
+- [auto.def][]: the primary driver for the `./configure` process.
+ When we talk about "the configure script," we're technically
+ referring to this file, though it actually contains very little
+ of the TCL code.
- [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
@@ -61,11 +62,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 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).
+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 part
+of Autosetup's core packages and are scattered around [the TCL files
+in ./autosetup](/dir/autosetup).
In (mostly) alphabetical order:
@@ -83,19 +84,14 @@ In (mostly) alphabetical order:
Works like `get-env` but will, if that function finds no match,
look for a file named `./.env-$VAR` and, if found, return its
trimmed contents. This can be used, e.g., to set a developer's
- local preferences for the default `CFLAGS`.
-
-- **`define-for-opt flag defineName ?checkingMsg? ?yesVal=1? ?noVal=0?`**\
- `[define $defineName]` to either `$yesVal` or `$noVal`, depending on
- whether `--$flag` is truthy or not. `$checkingMsg` is a
- human-readable description of the check being made, e.g. "enable foo?"
- If no `checkingMsg` is provided, the operation is silent.\
- Potential TODO: change the final two args to `-yes` and `-no`
- flags. They're rarely needed, though: search [auto.def][] for
- `TSTRNNR_OPTS` for an example of where they are used.
+ local preferences for the default `CFLAGS`.\
+ Tip: adding `-O0` to `.env-CFLAGS` reduces rebuild times
+ considerably at the cost of performance in `make devtest` and the
+ like.
- **`proj-fatal msg`**\
- Emits `$msg` to stderr and exits with non-zero.
+ Emits `$msg` to stderr and exits with non-zero. Its differences from
+ autosetup's `user-error` are purely cosmetic.
- **`proj-if-opt-truthy flag thenScript ?elseScript?`**\
Evals `thenScript` if the given `--flag` is truthy, else it
@@ -117,7 +113,10 @@ In (mostly) alphabetical order:
else 0. This distinction can be used to determine, e.g., whether
`--with-readline` was provided or whether we're searching for
readline by default. In the former case, failure to find it should
- be treated as fatal, where in the latter case it's not.
+ be treated as fatal, where in the latter case it's not.\
+ Unlike most functions which deal with `--flags`, this one does not
+ validate that `$FLAG` is a registered flag so will not fail fatally
+ if `$FLAG` is not registered as an Autosetup option.
- **`proj-val-truthy value`**\
Returns 1 if `$value` is "truthy," See `proj-opt-truthy` for the definition
@@ -139,6 +138,15 @@ In (mostly) alphabetical order:
The shell-specific counterpart of `sqlite-add-feature-flag` which
only adds the given flag(s) to the CLI-shell-specific CFLAGS.
+- **`sqlite-configure BUILD-NAME {script}`**\
+ This is where all configure `--flags` are defined for all known
+ build modes ("canonical" or "autoconf"). After processing all flags,
+ this function runs `$script`, which contains the build-mode-specific
+ configuration bits, and then runs any finalization bits which are
+ common to all build modes. The `auto.def` files are intended to contain
+ exactly two commands:
+ `use sqlite-config; sqlite-configure BUILD-NAME {script}`
+
- **`user-notice msg`**\
Queues `$msg` to be sent to stderr, but does not emit it until
either `show-notices` is called or the next time autosetup would
@@ -152,13 +160,18 @@ In (mostly) alphabetical order:
Ensuring TCL Compatibility
========================================================================
-It is important that any TCL files used by the configure process
-remain compatible with both [JimTCL][] and the canonical TCL. Though
-JimTCL has outstanding compatibility with canonical TCL, it does have
-a few corners with incompatibilities, e.g. regular expressions. If a
-script runs in JimTCL without using any JimTCL-specific features, then
-it's a certainty that it will run in canonical TCL as well. The
-opposite, however, is not _always_ the case.
+One of the significant benefits of using Autosetup is that (A) this
+project uses many TCL scripts in the build process and (B) Autosetup
+comes with a TCL interpreter named [JimTCL][].
+
+It is important that any TCL files used by the configure process and
+makefiles remain compatible with both [JimTCL][] and the canonical
+TCL. Though JimTCL has outstanding compatibility with canonical TCL,
+it does have a few corners with incompatibilities, e.g. regular
+expressions. If a script runs in JimTCL without using any
+JimTCL-specific features, then it's a certainty that it will run in
+canonical TCL as well. The opposite, however, is not _always_ the
+case.
When [`./configure`](/file/configure) is run, it goes through a
bootstrapping process to find a suitable TCL with which to run the
@@ -187,14 +200,17 @@ compatibility across TCL implementations:
before looking for a system-level `tclsh`. Be aware, though, that
`make distclean` will remove that file.
-**Note that `jimsh0` is distinctly different from the `jimsh`** which
-gets built for code-generation purposes. The latter requires
+**Note that `./jimsh0` is distinctly different from the `./jimsh`**
+which gets built for code-generation purposes. The latter requires
non-default build flags to enable features which are
platform-dependent, most notably to make its `[file normalize]` work.
This means, for example, that the configure script and its utility
APIs must not use `[file normalize]`, but autosetup provides a
TCL-only implementation of `[file-normalize]` (note the dash) for
-portable use in the configure script.
+portable use in the configure script. Contrariwise, code-generation
+scripts invoked via `make` may use `[file normalize]`, as they'll use
+`./jimsh` or `tclsh` instead of `./jimsh0`.
+
Known TCL Incompatibilities
------------------------------------------------------------------------
@@ -221,6 +237,7 @@ A summary of known incompatibilities in JimTCL
- `regsub` does not support the `\y` flag. A workaround is demonstrated
in [](/info/c2e5dd791cce3ec4).
+
<a name="conventions"></a>
Design Conventions
========================================================================
@@ -247,8 +264,9 @@ dots are not permitted.
The `X.y` convention is used in the makefiles primarily because the
person who did the initial port finds that considerably easier on the
eyes and fingers. In practice, the `X_Y` form of such exports is used
-exactly once in [Makefile.in][], where it's translated into into `X.y`
-form for consumption by [Makefile.in][] and [main.mk][]. For example:
+exactly once in [Makefile.in][], where it's translated from `@X_Y@`
+into into `X.y` form for consumption by [Makefile.in][] and
+[main.mk][]. For example:
>
```
@@ -265,9 +283,9 @@ of taste, for which there is no accounting.)
Do Not Update Global Shared State
------------------------------------------------------------------------
-In both the legacy Autotools-driven build and in common Autosetup
-usage, feature tests performed by the configure script may amend
-global flags such as `LIBS`, `LDFLAGS`, and `CFLAGS`[^as-cflags]. That's
+In both the legacy Autotools-driven build and common Autosetup usage,
+feature tests performed by the configure script may amend global flags
+such as `LIBS`, `LDFLAGS`, and `CFLAGS`[^as-cflags]. That's
appropriate for a makefile which builds a single deliverable, but less
so for makefiles which produce multiple deliverables. Drawbacks of
that approach include:
@@ -275,8 +293,8 @@ that approach include:
- It's unlikely that every single deliverable will require the same
core set of those flags.
- It can be difficult to determine the origin of any given change to
- that global state because those changes are hidden behind voodoo performed
- outside the immediate visibility of the configure script's
+ that global state because those changes are hidden behind voodoo
+ performed outside the immediate visibility of the configure script's
maintainer.
- It can force the maintainers of the configure script to place tests
in a specific order so that the resulting flags get applied at
@@ -357,12 +375,11 @@ Patching Autosetup for Project-local Changes
Autosetup reserves the flag name **`--debug`** for its own purposes,
and its own special handling of `--enable-...` flags makes `--debug`
-an alias for `--enable-debug`. As we have a long history of using
-`--enable-debug` for this project's own purposes, we patch autosetup
-to use the name `--autosetup-debug` in place of `--debug`. That
-requires (as of this writing) four small edits in
-[](/file/autosetup/autosetup), as demonstrated in [check-in
-3296c8d3](/info/3296c8d3).
+an alias for `--enable-debug`. As this project has a long history of
+using `--enable-debug`, we patch autosetup to use the name
+`--autosetup-debug` in place of `--debug`. That requires (as of this
+writing) four small edits in [](/file/autosetup/autosetup), as
+demonstrated in [check-in 3296c8d3](/info/3296c8d3).
If autosetup is upgraded and this patch is _not_ applied the invoking
`./configure` will fail loudly because of the declaration of the
diff --git a/autosetup/proj.tcl b/autosetup/proj.tcl
index adf31a1ad..ba5427b6a 100644
--- a/autosetup/proj.tcl
+++ b/autosetup/proj.tcl
@@ -183,6 +183,8 @@ proc proj-lshift_ {listVar {count 1}} {
}
########################################################################
+# @proj-strip-hash-comments value
+#
# Expects to receive string input, which it splits on newlines, strips
# out any lines which begin with any number of whitespace followed by
# a '#', and returns a value containing the [append]ed results of each
@@ -1032,6 +1034,39 @@ proc proj-check-soname {{libname "libfoo.so.0"}} {
}
########################################################################
+# @proj-check-fsanitize ?list-of-opts?
+#
+# Checks whether CC supports -fsanitize=X, where X is each entry of
+# the given list of flags. If any of those flags are supported, it
+# returns the string "-fsanitize=X..." where X... is a comma-separated
+# list of all flags from the original set which are supported. If none
+# of the given options are supported then it returns an empty string.
+#
+# Example:
+#
+# set f [proj-check-fsanitize {address bounds-check just-testing}]
+#
+# Will, on many systems, resolve to "-fsanitize=address,bounds-check",
+# but may also resolve to "-fsanitize=address".
+proc proj-check-fsanitize {{opts {address bounds-strict}}} {
+ set sup {}
+ foreach opt $opts {
+ # -nooutput is used because -fsanitize=hwaddress will otherwise
+ # pass this test on x86_64, but then warn at build time that
+ # "hwaddress is not supported for this target".
+ cc-with {-nooutput 1} {
+ if {[cc-check-flags "-fsanitize=$opt"]} {
+ lappend sup $opt
+ }
+ }
+ }
+ if {[llength $sup] > 0} {
+ return "-fsanitize=[join $sup ,]"
+ }
+ return ""
+}
+
+########################################################################
# Internal helper for proj-dump-defs-json. Expects to be passed a
# [define] name and the variadic $args which are passed to
# proj-dump-defs-json. If it finds a pattern match for the given
diff --git a/autosetup/sqlite-config.tcl b/autosetup/sqlite-config.tcl
index 56567ddb9..42b4382cf 100644
--- a/autosetup/sqlite-config.tcl
+++ b/autosetup/sqlite-config.tcl
@@ -1,6 +1,6 @@
# 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
+# that they can be reused in the autoconf sub-tree. This file requires
# functions from proj.tcl.
if {[string first " " $autosetup(srcdir)] != -1} {
@@ -24,7 +24,6 @@ use system ; # Will output "Host System" and "Build System" lines
if {"--help" ni $::argv} {
msg-result "Source dir = $::autosetup(srcdir)"
msg-result "Build dir = $::autosetup(builddir)"
-
use cc cc-db cc-shared cc-lib pkg-config
}
@@ -61,13 +60,21 @@ array set sqliteConfig [proj-strip-hash-comments {
set sqliteConfig(is-cross-compiling) [proj-is-cross-compiling]
########################################################################
-# Processes all configure --flags for this build $buildMode must be
-# either "canonical" or "autoconf", and others may be added in the
+# Processes all configure --flags for this build, run build-specific
+# config checks, then finalize the configure process. $buildMode must
+# be either "canonical" or "autoconf", and others may be added in the
# future. After bootstrapping, $configScript is eval'd in the caller's
# scope, then post-configuration finalization is run. $configScript is
# intended to hold configure code which is specific to the given
# $buildMode, with the caveat that _some_ build-specific code is
# encapsulated in the configuration finalization step.
+#
+# The intent is that all build-mode-specific configuration goes inside
+# the $configScript argument to this function, and that an auto.def file
+# contains only two commands:
+#
+# use sqlite-config
+# sqlite-configure BUILD_NAME { build-specific configure script }
proc sqlite-configure {buildMode configScript} {
set allBuildModes {canonical autoconf}
if {$buildMode ni $allBuildModes} {
@@ -131,7 +138,7 @@ proc sqlite-configure {buildMode configScript} {
########################################################################
set allFlags {
# Structure: a list of M {Z} pairs, where M is a descriptive
- # option group name and Z is a list of X Y pairs. X is a list of
+ # option group name and Z is a list of X Y pairs. X is a list of
# $buildMode name(s) to which the Y flags apply, or {*} to apply
# to all builds. Y is a {block} in the form expected by
# autosetup's [options] command. Each block which is applicable
@@ -168,8 +175,8 @@ proc sqlite-configure {buildMode configScript} {
largefile=1
=> {This legacy flag has no effect on the library but may influence
the contents of the generated sqlite_cfg.h}
- # ^^^ It's not clear that this actually does anything, as
- # HAVE_LFS is not checked anywhere in the .c/.h/.in files.
+ # ^^^ It's not clear that LFS support actually does anything,
+ # as HAVE_LFS is not checked anywhere in the .c/.h/.in files.
load-extension=1 => {Disable loading of external extensions}
math=1 => {Disable math functions}
json=1 => {Disable JSON functions}
@@ -251,11 +258,11 @@ proc sqlite-configure {buildMode configScript} {
# Options for exotic/alternative build modes
alternative-builds {
- {canonical} {
- # Potential TODO: add --with-wasi-sdk support to the autoconf
- # build
+ {*} {
with-wasi-sdk:=/opt/wasi-sdk
=> {Top-most dir of the wasi-sdk for a WASI build}
+ }
+ {canonical} {
with-emsdk:=auto
=> {Top-most dir of the Emscripten SDK installation.
@@ -330,6 +337,10 @@ proc sqlite-configure {buildMode configScript} {
=> {Enable #line macros in the amalgamation}
dynlink-tools
=> {Dynamically link libsqlite3 to certain tools which normally statically embed it}
+ asan-fsanitize:=auto
+ => {Comma- or space-separated list of -fsanitize flags for use with the
+ fuzzcheck-asan tool. Only those which the compiler claims to support
+ will actually be used. May be provided multiple times.}
}
{*} {
dump-defines=0
@@ -365,12 +376,13 @@ proc sqlite-configure {buildMode configScript} {
}; # sqlite-configure
########################################################################
-# Performs late-stage config steps common to both the canonical and
-# autoconf bundle builds.
+# Performs late-stage config steps common to all supported
+# $::sqliteConfig(build-mode) values.
proc sqlite-configure-finalize {} {
set buildMode $::sqliteConfig(build-mode)
set isCanonical [expr {$buildMode eq "canonical"}]
set isAutoconf [expr {$buildMode eq "autoconf"}]
+ proj-assert {$isCanonical || $isAutoconf} "Unknown build mode: $buildMode"
define HAVE_LFS 0
if {[opt-bool largefile]} {
@@ -417,6 +429,13 @@ proc sqlite-configure-finalize {} {
sqlite-handle-math
sqlite-handle-icu
sqlite-handle-env-quirks
+ sqlite-handle-common-feature-flags
+ sqlite-finalize-feature-flags
+ ########################################################################
+ # 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)
sqlite-process-dot-in-files
sqlite-post-config-validation
sqlite-dump-defines
@@ -429,16 +448,14 @@ proc sqlite-configure-finalize {} {
# top-level build and the "autoconf" build, but it's not intended to
# be a catch-all dumping ground for such.
proc sqlite-post-options-init {} {
- define PACKAGE_NAME "sqlite"
+ define PACKAGE_NAME sqlite
define PACKAGE_URL {https://sqlite.org}
define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
define PACKAGE_STRING "[get-define PACKAGE_NAME] [get-define PACKAGE_VERSION]"
- #
- # 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 {
+ # Carry values from hidden --flag aliases over to their canonical
+ # flag forms. This list must include only options which are common
+ # to all build modes supported by [sqlite-configure].
with-readline-inc => with-readline-cflags
with-readline-lib => with-readline-ldflags
with-debug => debug
@@ -468,11 +485,9 @@ proc msg-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
- #
+ # with. This can be used to automatically reconfigure.
set 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
@@ -507,6 +522,8 @@ proc sqlite-add-feature-flag {args} {
define-append OPT_FEATURE_FLAGS {*}$args
}
}
+
+########################################################################
# Appends $args, if not empty, to OPT_SHELL.
proc sqlite-add-shell-opt {args} {
if {"" ne $args} {
@@ -545,13 +562,11 @@ proc sqlite-check-common-bins {} {
# 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
@@ -566,7 +581,6 @@ proc sqlite-check-common-system-deps {} {
}
define LDFLAGS_RT [join [lsort -unique $ldrt] ""]
- #
# Check for needed/wanted headers
cc-check-includes \
sys/types.h sys/stat.h dlfcn.h unistd.h \
@@ -588,7 +602,6 @@ proc sqlite-check-common-system-deps {} {
########################################################################
# Move -DSQLITE_OMIT... and -DSQLITE_ENABLE... flags from CFLAGS and
# CPPFLAGS to OPT_FEATURE_FLAGS and remove them from BUILD_CFLAGS.
-# This is derived from the legacy build but is still practical.
proc sqlite-munge-cflags {} {
# Move CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and
# -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived
@@ -735,6 +748,10 @@ proc sqlite-finalize-feature-flags {} {
define OPT_SHELL [lsort -unique $oFF]
msg-result "Shell options: [get-define OPT_SHELL]"
}
+ if {"" ne [set extraSrc [get-define AMALGAMATION_EXTRA_SRC ""]]} {
+ proj-assert {"canonical" eq $::sqliteConfig(build-mode)}
+ msg-result "Appending source files to amalgamation: $extraSrc"
+ }
}
########################################################################
@@ -1271,7 +1288,9 @@ proc sqlite-handle-icu {} {
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
+ # Recall that shell.c builds with sqlite3.c except in the case
+ # of --disable-static-shell, a combination we do not
+ # specifically attempt to account for.
}
} elseif {[opt-bool icu-collations]} {
proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
@@ -1414,7 +1433,7 @@ proc sqlite-handle-dll-basename {} {
# The name of the import library is [define]d in SQLITE_OUT_IMPLIB.
#
# If the configure flag --out-implib is not used (or programmatically
-# set) then this is a no-op (but see [sqliet-handle-env-quirks]). If
+# set) then this is a no-op (but see [sqlite-handle-env-quirks]). If
# that flag is used but the capability is not available, a fatal error
# is triggered.
#
@@ -1493,7 +1512,7 @@ proc sqlite-env-is-unix-on-windows {{envTuple ""}} {
#
# [define]s SQLITE_DLL_INSTALL_RULES to a symbolic name suffix for a
# set of "make install" rules to use for installation of the DLL
-# deliverable. The makefile is tasked with with providing rules named
+# deliverable. The makefile is tasked with providing rules named
# install-dll-NAME which runs the installation for that set, as well
# as providing a rule named install-dll which resolves to
# install-dll-NAME (perhaps indirectly, depending on whether the DLL
@@ -1505,13 +1524,13 @@ proc sqlite-env-is-unix-on-windows {{envTuple ""}} {
#
# On platforms where an "import library" is conventionally used but
# --out-implib was not explicitly used, automatically add that flag.
-# This conventionally applies to the "Unix on Windows" environments
-# like msys and cygwin.
+# This conventionally applies only to the "Unix on Windows"
+# environments like msys and cygwin.
#
# 3) --dll-basename:
#
# On the same platforms addressed by --out-implib, if --dll-basename
-# is not specified, --dll-basename=auto is implied.
+# is not explicitly specified, --dll-basename=auto is implied.
proc sqlite-handle-env-quirks {} {
set instName unix-generic; # name of installation rules set
set autoDll 0; # true if --out-implib/--dll-basename should be implied
@@ -1558,21 +1577,6 @@ proc sqlite-handle-env-quirks {} {
# 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
- if {"" ne [set extraSrc [get-define AMALGAMATION_EXTRA_SRC ""]]} {
- msg-result "Appending source files to amalgamation: $extraSrc"
- }
-
- ########################################################################
# "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.
@@ -1652,7 +1656,8 @@ proc sqlite-handle-wasi-sdk {} {
tcl
threadsafe
} {
- if {[opt-bool $opt]} {
+ if {[proj-opt-exists $opt] && [opt-bool $opt]} {
+ # -^^^^ distinguish between canonical and autoconf builds
msg-result " --disable-$opt"
proj-opt-set $opt 0
}
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
index 06f3c6efe..a53ecdf17 100644
--- a/ext/fts3/fts3Int.h
+++ b/ext/fts3/fts3Int.h
@@ -202,6 +202,19 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
#define deliberate_fall_through
+/*
+** Macros needed to provide flexible arrays in a portable way
+*/
+#ifndef offsetof
+# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
+
+
#endif /* SQLITE_AMALGAMATION */
#ifdef SQLITE_DEBUG
@@ -431,9 +444,13 @@ struct Fts3Phrase {
*/
int nToken; /* Number of tokens in the phrase */
int iColumn; /* Index of column this phrase must match */
- Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
+ Fts3PhraseToken aToken[FLEXARRAY]; /* One for each token in the phrase */
};
+/* Size (in bytes) of an Fts3Phrase object large enough to hold N tokens */
+#define SZ_FTS3PHRASE(N) \
+ (offsetof(Fts3Phrase,aToken)+(N)*sizeof(Fts3PhraseToken))
+
/*
** A tree of these objects forms the RHS of a MATCH operator.
**
diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c
index ca857835e..681d4e862 100644
--- a/ext/fts3/fts3_expr.c
+++ b/ext/fts3/fts3_expr.c
@@ -162,6 +162,23 @@ int sqlite3Fts3OpenTokenizer(
static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
/*
+** Search buffer z[], size n, for a '"' character. Or, if enable_parenthesis
+** is defined, search for '(' and ')' as well. Return the index of the first
+** such character in the buffer. If there is no such character, return -1.
+*/
+static int findBarredChar(const char *z, int n){
+ int ii;
+ for(ii=0; ii<n; ii++){
+ if( (z[ii]=='"')
+ || (sqlite3_fts3_enable_parentheses && (z[ii]=='(' || z[ii]==')'))
+ ){
+ return ii;
+ }
+ }
+ return -1;
+}
+
+/*
** Extract the next token from buffer z (length n) using the tokenizer
** and other information (column names etc.) in pParse. Create an Fts3Expr
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
@@ -185,16 +202,9 @@ static int getNextToken(
int rc;
sqlite3_tokenizer_cursor *pCursor;
Fts3Expr *pRet = 0;
- int i = 0;
-
- /* Set variable i to the maximum number of bytes of input to tokenize. */
- for(i=0; i<n; i++){
- if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break;
- if( z[i]=='"' ) break;
- }
- *pnConsumed = i;
- rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor);
+ *pnConsumed = n;
+ rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
if( rc==SQLITE_OK ){
const char *zToken;
int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
@@ -202,7 +212,18 @@ static int getNextToken(
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
if( rc==SQLITE_OK ){
- nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
+ /* Check that this tokenization did not gobble up any " characters. Or,
+ ** if enable_parenthesis is true, that it did not gobble up any
+ ** open or close parenthesis characters either. If it did, call
+ ** getNextToken() again, but pass only that part of the input buffer
+ ** up to the first such character. */
+ int iBarred = findBarredChar(z, iEnd);
+ if( iBarred>=0 ){
+ pModule->xClose(pCursor);
+ return getNextToken(pParse, iCol, z, iBarred, ppExpr, pnConsumed);
+ }
+
+ nByte = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1) + nToken;
pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte);
if( !pRet ){
rc = SQLITE_NOMEM;
@@ -212,7 +233,7 @@ static int getNextToken(
pRet->pPhrase->nToken = 1;
pRet->pPhrase->iColumn = iCol;
pRet->pPhrase->aToken[0].n = nToken;
- pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1];
+ pRet->pPhrase->aToken[0].z = (char*)&pRet->pPhrase->aToken[1];
memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken);
if( iEnd<n && z[iEnd]=='*' ){
@@ -236,7 +257,11 @@ static int getNextToken(
}
*pnConsumed = iEnd;
- }else if( i && rc==SQLITE_DONE ){
+ }else if( n && rc==SQLITE_DONE ){
+ int iBarred = findBarredChar(z, n);
+ if( iBarred>=0 ){
+ *pnConsumed = iBarred;
+ }
rc = SQLITE_OK;
}
@@ -285,7 +310,7 @@ static int getNextString(
char *zTemp = 0;
i64 nTemp = 0;
- const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
+ const int nSpace = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1);
int nToken = 0;
/* The final Fts3Expr data structure, including the Fts3Phrase,
@@ -1239,7 +1264,6 @@ static void fts3ExprTestCommon(
}
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
- sqlite3Fts3ExprFree(pExpr);
sqlite3_result_error(context, "Error parsing expression", -1);
}else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
sqlite3_result_error_nomem(context);
diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c
index 9ec7df380..36ee94a48 100644
--- a/ext/fts3/fts3_snippet.c
+++ b/ext/fts3/fts3_snippet.c
@@ -108,9 +108,13 @@ struct MatchinfoBuffer {
int nElem;
int bGlobal; /* Set if global data is loaded */
char *zMatchinfo;
- u32 aMatchinfo[1];
+ u32 aMI[FLEXARRAY];
};
+/* Size (in bytes) of a MatchinfoBuffer sufficient for N elements */
+#define SZ_MATCHINFOBUFFER(N) \
+ (offsetof(MatchinfoBuffer,aMI)+(((N)+1)/2)*sizeof(u64))
+
/*
** The snippet() and offsets() functions both return text values. An instance
@@ -135,13 +139,13 @@ struct StrBuffer {
static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
MatchinfoBuffer *pRet;
sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1)
- + sizeof(MatchinfoBuffer);
+ + SZ_MATCHINFOBUFFER(1);
sqlite3_int64 nStr = strlen(zMatchinfo);
pRet = sqlite3Fts3MallocZero(nByte + nStr+1);
if( pRet ){
- pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
- pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0]
+ pRet->aMI[0] = (u8*)(&pRet->aMI[1]) - (u8*)pRet;
+ pRet->aMI[1+nElem] = pRet->aMI[0]
+ sizeof(u32)*((int)nElem+1);
pRet->nElem = (int)nElem;
pRet->zMatchinfo = ((char*)pRet) + nByte;
@@ -155,10 +159,10 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
static void fts3MIBufferFree(void *p){
MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]);
- assert( (u32*)p==&pBuf->aMatchinfo[1]
- || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2]
+ assert( (u32*)p==&pBuf->aMI[1]
+ || (u32*)p==&pBuf->aMI[pBuf->nElem+2]
);
- if( (u32*)p==&pBuf->aMatchinfo[1] ){
+ if( (u32*)p==&pBuf->aMI[1] ){
pBuf->aRef[1] = 0;
}else{
pBuf->aRef[2] = 0;
@@ -175,18 +179,18 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
if( p->aRef[1]==0 ){
p->aRef[1] = 1;
- aOut = &p->aMatchinfo[1];
+ aOut = &p->aMI[1];
xRet = fts3MIBufferFree;
}
else if( p->aRef[2]==0 ){
p->aRef[2] = 1;
- aOut = &p->aMatchinfo[p->nElem+2];
+ aOut = &p->aMI[p->nElem+2];
xRet = fts3MIBufferFree;
}else{
aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32));
if( aOut ){
xRet = sqlite3_free;
- if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32));
+ if( p->bGlobal ) memcpy(aOut, &p->aMI[1], p->nElem*sizeof(u32));
}
}
@@ -196,7 +200,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){
p->bGlobal = 1;
- memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32));
+ memcpy(&p->aMI[2+p->nElem], &p->aMI[1], p->nElem*sizeof(u32));
}
/*
diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h
index 832f9ad47..2da347862 100644
--- a/ext/fts5/fts5Int.h
+++ b/ext/fts5/fts5Int.h
@@ -75,6 +75,18 @@ typedef sqlite3_uint64 u64;
# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
#endif
+/*
+** Macros needed to provide flexible arrays in a portable way
+*/
+#ifndef offsetof
+# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
+
#endif
/* Truncate very long tokens to this many bytes. Hard limit is
@@ -147,10 +159,11 @@ typedef struct Fts5Colset Fts5Colset;
*/
struct Fts5Colset {
int nCol;
- int aiCol[1];
+ int aiCol[FLEXARRAY];
};
-
+/* Size (int bytes) of a complete Fts5Colset object with N columns. */
+#define SZ_FTS5COLSET(N) (sizeof(i64)*((N+2)/2))
/**************************************************************************
** Interface to code in fts5_config.c. fts5_config.c contains contains code
diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c
index dc2f7fb39..0a9b08ed1 100644
--- a/ext/fts5/fts5_expr.c
+++ b/ext/fts5/fts5_expr.c
@@ -86,9 +86,13 @@ struct Fts5ExprNode {
/* Child nodes. For a NOT node, this array always contains 2 entries. For
** AND or OR nodes, it contains 2 or more entries. */
int nChild; /* Number of child nodes */
- Fts5ExprNode *apChild[1]; /* Array of child nodes */
+ Fts5ExprNode *apChild[FLEXARRAY]; /* Array of child nodes */
};
+/* Size (in bytes) of an Fts5ExprNode object that holds up to N children */
+#define SZ_FTS5EXPRNODE(N) \
+ (offsetof(Fts5ExprNode,apChild) + (N)*sizeof(Fts5ExprNode*))
+
#define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING)
/*
@@ -119,9 +123,13 @@ struct Fts5ExprPhrase {
Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */
Fts5Buffer poslist; /* Current position list */
int nTerm; /* Number of entries in aTerm[] */
- Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */
+ Fts5ExprTerm aTerm[FLEXARRAY]; /* Terms that make up this phrase */
};
+/* Size (in bytes) of an Fts5ExprPhrase object that holds up to N terms */
+#define SZ_FTS5EXPRPHRASE(N) \
+ (offsetof(Fts5ExprPhrase,aTerm) + (N)*sizeof(Fts5ExprTerm))
+
/*
** One or more phrases that must appear within a certain token distance of
** each other within each matching document.
@@ -130,9 +138,12 @@ struct Fts5ExprNearset {
int nNear; /* NEAR parameter */
Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */
int nPhrase; /* Number of entries in aPhrase[] array */
- Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */
+ Fts5ExprPhrase *apPhrase[FLEXARRAY]; /* Array of phrase pointers */
};
+/* Size (in bytes) of an Fts5ExprNearset object covering up to N phrases */
+#define SZ_FTS5EXPRNEARSET(N) \
+ (offsetof(Fts5ExprNearset,apPhrase)+(N)*sizeof(Fts5ExprPhrase*))
/*
** Parse context.
@@ -292,7 +303,7 @@ int sqlite3Fts5ExprNew(
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
- int n = sizeof(Fts5Colset);
+ int n = SZ_FTS5COLSET(1);
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
if( pColset ){
pColset->nCol = 1;
@@ -1650,7 +1661,7 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
if( pParse->rc==SQLITE_OK ){
if( pNear==0 ){
sqlite3_int64 nByte;
- nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
+ nByte = SZ_FTS5EXPRNEARSET(SZALLOC+1);
pRet = sqlite3_malloc64(nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
@@ -1661,7 +1672,7 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
int nNew = pNear->nPhrase + SZALLOC;
sqlite3_int64 nByte;
- nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
+ nByte = SZ_FTS5EXPRNEARSET(nNew+1);
pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
@@ -1752,12 +1763,12 @@ static int fts5ParseTokenize(
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
- sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
+ SZ_FTS5EXPRPHRASE(nNew+1)
);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
- if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase));
+ if( pPhrase==0 ) memset(pNew, 0, SZ_FTS5EXPRPHRASE(1));
pCtx->pPhrase = pPhrase = pNew;
pNew->nTerm = nNew - SZALLOC;
}
@@ -1865,7 +1876,7 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
if( sCtx.pPhrase==0 ){
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
- sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, SZ_FTS5EXPRPHRASE(1));
}else if( sCtx.pPhrase->nTerm ){
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix;
}
@@ -1900,19 +1911,18 @@ int sqlite3Fts5ExprClonePhrase(
sizeof(Fts5ExprPhrase*));
}
if( rc==SQLITE_OK ){
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc,
- sizeof(Fts5ExprNode));
+ pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRNODE(1));
}
if( rc==SQLITE_OK ){
- pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
- sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
+ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
+ SZ_FTS5EXPRNEARSET(2));
}
if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
if( pColsetOrig ){
sqlite3_int64 nByte;
Fts5Colset *pColset;
- nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
+ nByte = SZ_FTS5COLSET(pColsetOrig->nCol);
pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
if( pColset ){
memcpy(pColset, pColsetOrig, (size_t)nByte);
@@ -1940,7 +1950,7 @@ int sqlite3Fts5ExprClonePhrase(
}else{
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
- sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRPHRASE(1));
}
}
@@ -2005,7 +2015,8 @@ void sqlite3Fts5ParseSetDistance(
);
return;
}
- nNear = nNear * 10 + (p->p[i] - '0');
+ if( nNear<214748363 ) nNear = nNear * 10 + (p->p[i] - '0');
+ /* ^^^^^^^^^^^^^^^--- Prevent integer overflow */
}
}else{
nNear = FTS5_DEFAULT_NEARDIST;
@@ -2034,7 +2045,7 @@ static Fts5Colset *fts5ParseColset(
assert( pParse->rc==SQLITE_OK );
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
- pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
+ pNew = sqlite3_realloc64(p, SZ_FTS5COLSET(nCol+1));
if( pNew==0 ){
pParse->rc = SQLITE_NOMEM;
}else{
@@ -2069,7 +2080,7 @@ Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){
int nCol = pParse->pConfig->nCol;
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
- sizeof(Fts5Colset) + sizeof(int)*nCol
+ SZ_FTS5COLSET(nCol+1)
);
if( pRet ){
int i;
@@ -2130,7 +2141,7 @@ Fts5Colset *sqlite3Fts5ParseColset(
static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
Fts5Colset *pRet;
if( pOrig ){
- sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
+ sqlite3_int64 nByte = SZ_FTS5COLSET(pOrig->nCol);
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
if( pRet ){
memcpy(pRet, pOrig, (size_t)nByte);
@@ -2298,7 +2309,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
assert( pNear->nPhrase==1 );
assert( pParse->bPhraseToAnd );
- nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*);
+ nByte = SZ_FTS5EXPRNODE(nTerm+1);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
pRet->eType = FTS5_AND;
@@ -2308,7 +2319,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(
- &pParse->rc, sizeof(Fts5ExprPhrase)
+ &pParse->rc, SZ_FTS5EXPRPHRASE(1)
);
if( pPhrase ){
if( parseGrowPhraseArray(pParse) ){
@@ -2377,7 +2388,7 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
if( pRight->eType==eType ) nChild += pRight->nChild-1;
}
- nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
+ nByte = SZ_FTS5EXPRNODE(nChild);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index 70a4752e2..63840de1f 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -422,9 +422,13 @@ struct Fts5Structure {
u64 nOriginCntr; /* Origin value for next top-level segment */
int nSegment; /* Total segments in this structure */
int nLevel; /* Number of levels in this index */
- Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */
+ Fts5StructureLevel aLevel[FLEXARRAY]; /* Array of nLevel level objects */
};
+/* Size (in bytes) of an Fts5Structure object holding up to N levels */
+#define SZ_FTS5STRUCTURE(N) \
+ (offsetof(Fts5Structure,aLevel) + (N)*sizeof(Fts5StructureLevel))
+
/*
** An object of type Fts5SegWriter is used to write to segments.
*/
@@ -554,11 +558,15 @@ struct Fts5SegIter {
** Array of tombstone pages. Reference counted.
*/
struct Fts5TombstoneArray {
- int nRef; /* Number of pointers to this object */
+ int nRef; /* Number of pointers to this object */
int nTombstone;
- Fts5Data *apTombstone[1]; /* Array of tombstone pages */
+ Fts5Data *apTombstone[FLEXARRAY]; /* Array of tombstone pages */
};
+/* Size (in bytes) of an Fts5TombstoneArray holding up to N tombstones */
+#define SZ_FTS5TOMBSTONEARRAY(N) \
+ (offsetof(Fts5TombstoneArray,apTombstone)+(N)*sizeof(Fts5Data*))
+
/*
** Argument is a pointer to an Fts5Data structure that contains a
** leaf page.
@@ -627,9 +635,12 @@ struct Fts5Iter {
i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */
Fts5CResult *aFirst; /* Current merge state (see above) */
- Fts5SegIter aSeg[1]; /* Array of segment iterators */
+ Fts5SegIter aSeg[FLEXARRAY]; /* Array of segment iterators */
};
+/* Size (in bytes) of an Fts5Iter object holding up to N segment iterators */
+#define SZ_FTS5ITER(N) (offsetof(Fts5Iter,aSeg)+(N)*sizeof(Fts5SegIter))
+
/*
** An instance of the following type is used to iterate through the contents
** of a doclist-index record.
@@ -656,9 +667,13 @@ struct Fts5DlidxLvl {
struct Fts5DlidxIter {
int nLvl;
int iSegid;
- Fts5DlidxLvl aLvl[1];
+ Fts5DlidxLvl aLvl[FLEXARRAY];
};
+/* Size (in bytes) of an Fts5DlidxIter object with up to N levels */
+#define SZ_FTS5DLIDXITER(N) \
+ (offsetof(Fts5DlidxIter,aLvl)+(N)*sizeof(Fts5DlidxLvl))
+
static void fts5PutU16(u8 *aOut, u16 iVal){
aOut[0] = (iVal>>8);
aOut[1] = (iVal&0xFF);
@@ -1026,7 +1041,7 @@ int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){
static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){
Fts5Structure *p = *pp;
if( *pRc==SQLITE_OK && p->nRef>1 ){
- i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel);
+ i64 nByte = SZ_FTS5STRUCTURE(p->nLevel);
Fts5Structure *pNew;
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte);
if( pNew ){
@@ -1100,10 +1115,7 @@ static int fts5StructureDecode(
){
return FTS5_CORRUPT;
}
- nByte = (
- sizeof(Fts5Structure) + /* Main structure */
- sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */
- );
+ nByte = SZ_FTS5STRUCTURE(nLevel);
pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte);
if( pRet ){
@@ -1183,10 +1195,7 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
- sqlite3_int64 nByte = (
- sizeof(Fts5Structure) + /* Main structure */
- sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */
- );
+ sqlite3_int64 nByte = SZ_FTS5STRUCTURE(nLevel+2);
pStruct = sqlite3_realloc64(pStruct, nByte);
if( pStruct ){
@@ -1725,7 +1734,7 @@ static Fts5DlidxIter *fts5DlidxIterInit(
int bDone = 0;
for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
- sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
+ sqlite3_int64 nByte = SZ_FTS5DLIDXITER(i+1);
Fts5DlidxIter *pNew;
pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte);
@@ -1943,7 +1952,7 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
const int nTomb = pIter->pSeg->nPgTombstone;
if( nTomb>0 ){
- int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray);
+ int nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1);
Fts5TombstoneArray *pNew;
pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
@@ -3404,8 +3413,7 @@ static Fts5Iter *fts5MultiIterAlloc(
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
pNew = fts5IdxMalloc(p,
- sizeof(Fts5Iter) + /* pNew */
- sizeof(Fts5SegIter) * (nSlot-1) + /* pNew->aSeg[] */
+ SZ_FTS5ITER(nSlot) + /* pNew + pNew->aSeg[] */
sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
);
if( pNew ){
@@ -5771,7 +5779,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
Fts5Structure *pStruct
){
Fts5Structure *pNew = 0;
- sqlite3_int64 nByte = sizeof(Fts5Structure);
+ sqlite3_int64 nByte = SZ_FTS5STRUCTURE(1);
int nSeg = pStruct->nSegment;
int i;
@@ -5801,6 +5809,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
}
nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel);
+ assert( nByte==SZ_FTS5STRUCTURE(pStruct->nLevel+2) );
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
@@ -6377,9 +6386,13 @@ struct Fts5TokenDataIter {
int nIterAlloc;
Fts5PoslistReader *aPoslistReader;
int *aPoslistToIter;
- Fts5Iter *apIter[1];
+ Fts5Iter *apIter[FLEXARRAY];
};
+/* Size in bytes of an Fts5TokenDataIter object holding up to N iterators */
+#define SZ_FTS5TOKENDATAITER(N) \
+ (offsetof(Fts5TokenDataIter,apIter) + (N)*sizeof(Fts5Iter))
+
/*
** The two input arrays - a1[] and a2[] - are in sorted order. This function
** merges the two arrays together and writes the result to output array
@@ -6642,7 +6655,7 @@ static void fts5SetupPrefixIter(
&& p->pConfig->bPrefixInsttoken
){
s.pTokendata = &s2;
- s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, sizeof(*s2.pT));
+ s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, SZ_FTS5TOKENDATAITER(1));
}
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
@@ -6770,15 +6783,17 @@ int sqlite3Fts5IndexRollback(Fts5Index *p){
** and the initial version of the "averages" record (a zero-byte blob).
*/
int sqlite3Fts5IndexReinit(Fts5Index *p){
- Fts5Structure s;
+ Fts5Structure *pTmp;
+ u8 tmpSpace[SZ_FTS5STRUCTURE(1)];
fts5StructureInvalidate(p);
fts5IndexDiscardData(p);
- memset(&s, 0, sizeof(Fts5Structure));
+ pTmp = (Fts5Structure*)tmpSpace;
+ memset(pTmp, 0, SZ_FTS5STRUCTURE(1));
if( p->pConfig->bContentlessDelete ){
- s.nOriginCntr = 1;
+ pTmp->nOriginCntr = 1;
}
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
- fts5StructureWrite(p, &s);
+ fts5StructureWrite(p, pTmp);
return fts5IndexReturn(p);
}
@@ -6986,7 +7001,7 @@ static Fts5TokenDataIter *fts5AppendTokendataIter(
if( p->rc==SQLITE_OK ){
if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
- int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter);
+ int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1);
Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);
if( pNew==0 ){
@@ -7502,7 +7517,8 @@ static int fts5SetupPrefixIterTokendata(
fts5BufferGrow(&p->rc, &token, nToken+1);
assert( token.p!=0 || p->rc!=SQLITE_OK );
- ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT));
+ ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc,
+ SZ_FTS5TOKENDATAITER(1));
if( p->rc==SQLITE_OK ){
@@ -7633,7 +7649,8 @@ int sqlite3Fts5IndexIterWriteTokendata(
if( pIter->nSeg>0 ){
/* This is a prefix term iterator. */
if( pT==0 ){
- pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*pT));
+ pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc,
+ SZ_FTS5TOKENDATAITER(1));
pIter->pTokenDataIter = pT;
}
if( pT ){
diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c
index 4d5e3cd4f..e888abf21 100644
--- a/ext/fts5/fts5_main.c
+++ b/ext/fts5/fts5_main.c
@@ -170,9 +170,11 @@ struct Fts5Sorter {
i64 iRowid; /* Current rowid */
const u8 *aPoslist; /* Position lists for current row */
int nIdx; /* Number of entries in aIdx[] */
- int aIdx[1]; /* Offsets into aPoslist for current row */
+ int aIdx[FLEXARRAY]; /* Offsets into aPoslist for current row */
};
+/* Size (int bytes) of an Fts5Sorter object with N indexes */
+#define SZ_FTS5SORTER(N) (offsetof(Fts5Sorter,nIdx)+((N+2)/2)*sizeof(i64))
/*
** Virtual-table cursor object.
@@ -1050,7 +1052,7 @@ static int fts5CursorFirstSorted(
const char *zRankArgs = pCsr->zRankArgs;
nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
- nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
+ nByte = SZ_FTS5SORTER(nPhrase);
pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
if( pSorter==0 ) return SQLITE_NOMEM;
memset(pSorter, 0, (size_t)nByte);
diff --git a/ext/misc/series.c b/ext/misc/series.c
index d500842d5..e8188f1c9 100644
--- a/ext/misc/series.c
+++ b/ext/misc/series.c
@@ -60,8 +60,7 @@
** step HIDDEN
** );
**
-** The virtual table also has a rowid, logically equivalent to n+1 where
-** "n" is the ascending integer in the aforesaid production definition.
+** The virtual table also has a rowid which is an alias for the value.
**
** Function arguments in queries against this virtual table are translated
** into equality constraints against successive hidden columns. In other
@@ -276,6 +275,7 @@ static int seriesConnect(
int rc;
/* Column numbers */
+#define SERIES_COLUMN_ROWID (-1)
#define SERIES_COLUMN_VALUE 0
#define SERIES_COLUMN_START 1
#define SERIES_COLUMN_STOP 2
@@ -363,13 +363,11 @@ static int seriesColumn(
#endif
/*
-** Return the rowid for the current row, logically equivalent to n+1 where
-** "n" is the ascending integer in the aforesaid production definition.
+** The rowid is the same as the value.
*/
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
series_cursor *pCur = (series_cursor*)cur;
- sqlite3_uint64 n = pCur->ss.uSeqIndexNow;
- *pRowid = (sqlite3_int64)((n<LARGEST_UINT64)? n+1 : 0);
+ *pRowid = pCur->ss.iValueNow;
return SQLITE_OK;
}
@@ -519,8 +517,7 @@ static int seriesFilter(
pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
}
if( pCur->ss.iTerm>iMax ){
- sqlite3_uint64 d = pCur->ss.iTerm - iMax;
- pCur->ss.iTerm -= ((d+szStep-1)/szStep)*szStep;
+ pCur->ss.iTerm = iMax;
}
}else{
sqlite3_int64 szStep = -pCur->ss.iStep;
@@ -530,8 +527,7 @@ static int seriesFilter(
pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
}
if( pCur->ss.iTerm<iMin ){
- sqlite3_uint64 d = iMin - pCur->ss.iTerm;
- pCur->ss.iTerm += ((d+szStep-1)/szStep)*szStep;
+ pCur->ss.iTerm = iMin;
}
}
}
@@ -659,7 +655,10 @@ static int seriesBestIndex(
continue;
}
if( pConstraint->iColumn<SERIES_COLUMN_START ){
- if( pConstraint->iColumn==SERIES_COLUMN_VALUE && pConstraint->usable ){
+ if( (pConstraint->iColumn==SERIES_COLUMN_VALUE ||
+ pConstraint->iColumn==SERIES_COLUMN_ROWID)
+ && pConstraint->usable
+ ){
switch( op ){
case SQLITE_INDEX_CONSTRAINT_EQ:
case SQLITE_INDEX_CONSTRAINT_IS: {
diff --git a/ext/recover/sqlite3recover.c b/ext/recover/sqlite3recover.c
index b13719083..d50aa25ea 100644
--- a/ext/recover/sqlite3recover.c
+++ b/ext/recover/sqlite3recover.c
@@ -33,6 +33,16 @@ typedef unsigned int u32;
typedef unsigned char u8;
typedef sqlite3_int64 i64;
+/*
+** Work around C99 "flex-array" syntax for pre-C99 compilers, so as
+** to avoid complaints from -fsanitize=strict-bounds.
+*/
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
+
typedef struct RecoverTable RecoverTable;
typedef struct RecoverColumn RecoverColumn;
@@ -140,9 +150,12 @@ struct RecoverColumn {
typedef struct RecoverBitmap RecoverBitmap;
struct RecoverBitmap {
i64 nPg; /* Size of bitmap */
- u32 aElem[1]; /* Array of 32-bit bitmasks */
+ u32 aElem[FLEXARRAY]; /* Array of 32-bit bitmasks */
};
+/* Size in bytes of a RecoverBitmap object sufficient to cover 32 pages */
+#define SZ_RECOVERBITMAP_32 (16)
+
/*
** State variables (part of the sqlite3_recover structure) used while
** recovering data for tables identified in the recovered schema (state
@@ -382,7 +395,7 @@ static int recoverError(
*/
static RecoverBitmap *recoverBitmapAlloc(sqlite3_recover *p, i64 nPg){
int nElem = (nPg+1+31) / 32;
- int nByte = sizeof(RecoverBitmap) + nElem*sizeof(u32);
+ int nByte = SZ_RECOVERBITMAP_32 + nElem*sizeof(u32);
RecoverBitmap *pRet = (RecoverBitmap*)recoverMalloc(p, nByte);
if( pRet ){
diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c
index 21c87bdc7..5e9fa6996 100644
--- a/ext/rtree/rtree.c
+++ b/ext/rtree/rtree.c
@@ -94,6 +94,14 @@ typedef unsigned int u32;
# define ALWAYS(X) (X)
# define NEVER(X) (X)
#endif
+#ifndef offsetof
+#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
#endif /* !defined(SQLITE_AMALGAMATION) */
/* Macro to check for 4-byte alignment. Only used inside of assert() */
@@ -414,9 +422,13 @@ struct RtreeMatchArg {
RtreeGeomCallback cb; /* Info about the callback functions */
int nParam; /* Number of parameters to the SQL function */
sqlite3_value **apSqlParam; /* Original SQL parameter values */
- RtreeDValue aParam[1]; /* Values for parameters to the SQL function */
+ RtreeDValue aParam[FLEXARRAY]; /* Values for parameters to the SQL function */
};
+/* Size of an RtreeMatchArg object with N parameters */
+#define SZ_RTREEMATCHARG(N) \
+ (offsetof(RtreeMatchArg,aParam)+(N)*sizeof(RtreeDValue))
+
#ifndef MAX
# define MAX(x,y) ((x) < (y) ? (y) : (x))
#endif
@@ -4369,8 +4381,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
sqlite3_int64 nBlob;
int memErr = 0;
- nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue)
- + nArg*sizeof(sqlite3_value*);
+ nBlob = SZ_RTREEMATCHARG(nArg) + nArg*sizeof(sqlite3_value*);
pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob);
if( !pBlob ){
sqlite3_result_error_nomem(ctx);
diff --git a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
index 95843a35d..73426f203 100644
--- a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
+++ b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
@@ -79,6 +79,48 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.SQLITE_OPEN_MAIN_JOURNAL |
capi.SQLITE_OPEN_SUPER_JOURNAL |
capi.SQLITE_OPEN_WAL;
+ const FLAG_COMPUTE_DIGEST_V2 = capi.SQLITE_OPEN_MEMORY
+ /* Part of the fix for
+ https://github.com/sqlite/sqlite-wasm/issues/97
+
+ Summary: prior to version 3.50.0 computeDigest() always computes
+ a value of [0,0] due to overflows, so it does not do anything
+ useful. Fixing it invalidates old persistent files, so we
+ instead only fix it for files created or updated since the bug
+ was discovered and fixed.
+
+ This flag determines whether we use the broken legacy
+ computeDigest() or the v2 variant. We only use this flag for
+ newly-created/overwritten files. Pre-existing files have the
+ broken digest stored in them so need to continue to use that.
+
+ What this means, in terms of db file compatibility between
+ versions:
+
+ - DBs created with versions older than this fix (<3.50.0)
+ can be read by post-fix versions. Such DBs which are written
+ to in-place (not replaced) by newer versions can still be read
+ by older versions, as the affected digest is only modified
+ when the SAH slot is assigned to a given filename.
+
+ - DBs created with post-fix versions will, when read by a pre-fix
+ version, be seen as having a "bad digest" and will be
+ unceremoniously replaced by that pre-fix version. When swapping
+ back to a post-fix version, that version will see that the file
+ entry is missing the FLAG_COMPUTE_DIGEST_V2 bit so will treat it
+ as a legacy file.
+
+ This flag is stored in the same memory as the various
+ SQLITE_OPEN_... flags and we must be careful here to not use a
+ flag bit which is otherwise relevant for the VFS.
+ SQLITE_OPEN_MEMORY is handled by sqlite3_open_v2() and friends,
+ not the VFS, so we'll repurpose that one. If we take a
+ currently-unused bit and it ends up, at some later point, being
+ used, we would have to invalidate existing VFS files in order to
+ move to another bit. Similarly, if the SQLITE_OPEN_MEMORY bit
+ were ever reassigned (which it won't be!), we'd invalidate all
+ VFS-side files.
+ */;
/** Subdirectory of the VFS's space where "opaque" (randomly-named)
files are stored. Changing this effectively invalidates the data
@@ -329,6 +371,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
const pool = getPoolForVfs(pVfs);
try{
+ flags &= ~FLAG_COMPUTE_DIGEST_V2;
pool.log(`xOpen ${wasm.cstrToJs(zName)} ${flags}`);
// First try to open a path that already exists in the file system.
const path = (zName && wasm.peek8(zName))
@@ -624,7 +667,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const fileDigest = new Uint32Array(HEADER_DIGEST_SIZE / 4);
sah.read(fileDigest, {at: HEADER_OFFSET_DIGEST});
- const compDigest = this.computeDigest(this.#apBody);
+ const compDigest = this.computeDigest(this.#apBody, flags);
+ //warn("getAssociatedPath() flags",'0x'+flags.toString(16), "compDigest", compDigest);
if(fileDigest.every((v,i) => v===compDigest[i])){
// Valid digest
const pathBytes = this.#apBody.findIndex((v)=>0===v);
@@ -633,6 +677,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
// leaving stale db data laying around.
sah.truncate(HEADER_OFFSET_DATA);
}
+ //warn("getAssociatedPath() flags",'0x'+flags.toString(16), "compDigest", compDigest,"pathBytes",pathBytes);
return pathBytes
? textDecoder.decode(this.#apBody.subarray(0,pathBytes))
: '';
@@ -655,10 +700,17 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(HEADER_MAX_PATH_SIZE <= enc.written + 1/*NUL byte*/){
toss("Path too long:",path);
}
+ if(path && flags){
+ /* When creating or re-writing files, update their digest, if
+ needed, to v2. We continue to use v1 for the (!path) case
+ (empty files) because there's little reason not to use a
+ digest of 0 for empty entries. */
+ flags |= FLAG_COMPUTE_DIGEST_V2;
+ }
this.#apBody.fill(0, enc.written, HEADER_MAX_PATH_SIZE);
this.#dvBody.setUint32(HEADER_OFFSET_FLAGS, flags);
-
- const digest = this.computeDigest(this.#apBody);
+ const digest = this.computeDigest(this.#apBody, flags);
+ //console.warn("setAssociatedPath(",path,") digest",digest);
sah.write(this.#apBody, {at: 0});
sah.write(digest, {at: HEADER_OFFSET_DIGEST});
sah.flush();
@@ -679,15 +731,22 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
metadata for each file as a validation check. Changing this
algorithm invalidates all existing databases for this VFS, so
don't do that.
+
+ See the docs for FLAG_COMPUTE_DIGEST_V2 for more details.
*/
- computeDigest(byteArray){
- let h1 = 0xdeadbeef;
- let h2 = 0x41c6ce57;
- for(const v of byteArray){
- h1 = 31 * h1 + (v * 307);
- h2 = 31 * h2 + (v * 307);
+ computeDigest(byteArray, fileFlags){
+ if( fileFlags & FLAG_COMPUTE_DIGEST_V2 ){
+ let h1 = 0xdeadbeef;
+ let h2 = 0x41c6ce57;
+ for(const v of byteArray){
+ h1 = Math.imul(h1 ^ v, 2654435761);
+ h2 = Math.imul(h2 ^ v, 104729);
+ }
+ return new Uint32Array([h1>>>0, h2>>>0]);
+ }else{
+ /* this is what the buggy legacy computation worked out to */
+ return new Uint32Array([0,0]);
}
- return new Uint32Array([h1>>>0, h2>>>0]);
}
/**
diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c
index e3cd34b00..d13302769 100644
--- a/ext/wasm/mkwasmbuilds.c
+++ b/ext/wasm/mkwasmbuilds.c
@@ -45,6 +45,7 @@
** "sqlite3-wasmfs" build, only "esm" (ES6 Module) is legal.
*/
#define JS_BUILD_MODES vanilla esm bundler-friendly node
+/* Separator to help eyeballs find the different sections */
static const char * zBanner =
"\n########################################################################\n";
@@ -140,8 +141,8 @@ static void mk_prologue(void){
** mk_lib_mode().
**
** Maintenance reminder: do not combine flags within this enum,
-** e.g. LIBMODE_BUNDLER_FRIEND=0x02|LIBMODE_ESM, as that will lead to
-** breakage in some of the flag checks.
+** e.g. LIBMODE_BUNDLER_FRIENDLY=0x02|LIBMODE_ESM, as that will lead
+** to breakage in some of the flag checks.
*/
enum LibModeFlags {
/* Indicates an ESM module build. */
@@ -208,7 +209,7 @@ static void mk_pre_post(const char *zName /* build name */,
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... */
+ /* Combined flags for use with emcc... */
pf("pre-post-common.flags.%s-%s := "
"$(pre-post-common.flags) "
"--post-js=$(post-js.js.%s-%s) "
diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js
index 8638845a7..d30e59e38 100644
--- a/ext/wasm/tester1.c-pp.js
+++ b/ext/wasm/tester1.c-pp.js
@@ -3506,7 +3506,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
});
db.exec([
"create table t(a);",
- "insert into t(a) values(1),(2),(3);",
+ "insert into t(a) values(1),(2),(1);",
"select auxtest(1,a), auxtest(1,a) from t order by a"
]);
}finally{
diff --git a/ext/wasm/tests/opfs/sahpool/digest-worker.js b/ext/wasm/tests/opfs/sahpool/digest-worker.js
new file mode 100644
index 000000000..28b3c1673
--- /dev/null
+++ b/ext/wasm/tests/opfs/sahpool/digest-worker.js
@@ -0,0 +1,94 @@
+/*
+ 2025-01-31
+
+ 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 is part of testing the OPFS SAHPool VFS's computeDigest()
+ fix. See ./digest.html for the details.
+*/
+const clog = console.log.bind(console);
+const wPost = (type,...args)=>postMessage({type, payload:args});
+const log = (...args)=>{
+ clog("Worker:",...args);
+ wPost('log',...args);
+}
+
+const hasOpfs = ()=>{
+ return globalThis.FileSystemHandle
+ && globalThis.FileSystemDirectoryHandle
+ && globalThis.FileSystemFileHandle
+ && globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle
+ && navigator?.storage?.getDirectory;
+};
+if( !hasOpfs() ){
+ wPost('error',"OPFS not detected");
+ throw new Error("OPFS not detected");
+}
+
+clog("Importing sqlite3...");
+const searchParams = new URL(self.location.href).searchParams;
+importScripts(searchParams.get('sqlite3.dir') + '/sqlite3.js');
+
+const runTests = function(sqlite3, poolUtil){
+ const fname = '/my.db';
+ let db = new poolUtil.OpfsSAHPoolDb(fname);
+ let n = (new Date()).valueOf();
+ try {
+ db.exec([
+ "create table if not exists t(a);"
+ ]);
+ db.exec({
+ sql: "insert into t(a) values(?)",
+ bind: n++
+ });
+ log(fname,"record count: ",db.selectValue("select count(*) from t"));
+ }finally{
+ db.close();
+ }
+
+ db = new poolUtil.OpfsSAHPoolDb(fname);
+ try {
+ db.exec({
+ sql: "insert into t(a) values(?)",
+ bind: n++
+ });
+ log(fname,"record count: ",db.selectValue("select count(*) from t"));
+ }finally{
+ db.close();
+ }
+
+ const fname2 = '/my2.db';
+ db = new poolUtil.OpfsSAHPoolDb(fname2);
+ try {
+ db.exec([
+ "create table if not exists t(a);"
+ ]);
+ db.exec({
+ sql: "insert into t(a) values(?)",
+ bind: n++
+ });
+ log(fname2,"record count: ",db.selectValue("select count(*) from t"));
+ }finally{
+ db.close();
+ }
+};
+
+globalThis.sqlite3InitModule().then(async function(sqlite3){
+ log("sqlite3 version:",sqlite3.version);
+ const sahPoolConfig = {
+ name: 'opfs-sahpool-digest',
+ clearOnInit: false,
+ initialCapacity: 6
+ };
+ return sqlite3.installOpfsSAHPoolVfs(sahPoolConfig).then(poolUtil=>{
+ log('vfs acquired');
+ runTests(sqlite3, poolUtil);
+ });
+});
diff --git a/ext/wasm/tests/opfs/sahpool/digest.html b/ext/wasm/tests/opfs/sahpool/digest.html
new file mode 100644
index 000000000..daa1f7728
--- /dev/null
+++ b/ext/wasm/tests/opfs/sahpool/digest.html
@@ -0,0 +1,151 @@
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
+ <link rel="stylesheet" href="../../../common/emscripten.css"/>
+ <link rel="stylesheet" href="../../../common/testing.css"/>
+ <title>sqlite3 tester: OpfsSAHPool Digest</title>
+ <style></style>
+ </head>
+ <body><h1 id='color-target'></h1>
+
+ <p>
+ This is a test app for the digest calculation of the OPFS
+ SAHPool VFS. It requires running it with a new database created using
+ v3.49.0 or older, then running it again with a newer version, then
+ again with 3.49.0 or older.
+ </p>
+ <div class='input-wrapper'>
+ <input type='checkbox' id='cb-log-reverse'>
+ <label for='cb-log-reverse'>Reverse log order?</label>
+ </div>
+ <div id='test-output'></div>
+ <script>
+ /*
+ 2025-02-03
+
+ 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 is a bugfix test for the OPFS SAHPool VFS. It requires
+ setting up a database created using v3.49.0 or older, then
+ running it again with a newer version. In that case, the newer
+ version should be able to read the older version's db files
+ just fine. Revering back to the old version should also still
+ work - it should be able to read databases modified by the
+ newer version. However, a database _created_ by a version with
+ this fix will _not_ be legible by a version which predates
+ this fix, in which case the older version will see that VFS
+ file slot as corrupt and will clear it for re-use.
+
+ This is unfortunately rather cumbersome to test properly,
+ and essentially impossible to automate.
+ */
+ (function(){
+ 'use strict';
+ document.querySelector('h1').innerHTML =
+ document.querySelector('title').innerHTML;
+ const mapToString = (v)=>{
+ switch(typeof v){
+ case 'number': case 'string': case 'boolean':
+ case 'undefined': case 'bigint':
+ return ''+v;
+ default: break;
+ }
+ if(null===v) return 'null';
+ if(v instanceof Error){
+ v = {
+ message: v.message,
+ stack: v.stack,
+ errorClass: v.name
+ };
+ }
+ return JSON.stringify(v,undefined,2);
+ };
+ const normalizeArgs = (args)=>args.map(mapToString);
+ const logTarget = document.querySelector('#test-output');
+ const logClass = function(cssClass,...args){
+ const ln = document.createElement('div');
+ if(cssClass){
+ for(const c of (Array.isArray(cssClass) ? cssClass : [cssClass])){
+ ln.classList.add(c);
+ }
+ }
+ ln.append(document.createTextNode(normalizeArgs(args).join(' ')));
+ logTarget.append(ln);
+ };
+ const cbReverse = document.querySelector('#cb-log-reverse');
+ //cbReverse.setAttribute('checked','checked');
+ const cbReverseKey = 'tester1:cb-log-reverse';
+ const cbReverseIt = ()=>{
+ logTarget.classList[cbReverse.checked ? 'add' : 'remove']('reverse');
+ //localStorage.setItem(cbReverseKey, cbReverse.checked ? 1 : 0);
+ };
+ cbReverse.addEventListener('change', cbReverseIt, true);
+ /*if(localStorage.getItem(cbReverseKey)){
+ cbReverse.checked = !!(+localStorage.getItem(cbReverseKey));
+ }*/
+ cbReverseIt();
+
+ const log = (...args)=>{
+ //console.log(...args);
+ logClass('',...args);
+ }
+ const warn = (...args)=>{
+ console.warn(...args);
+ logClass('warning',...args);
+ }
+ const error = (...args)=>{
+ console.error(...args);
+ logClass('error',...args);
+ };
+
+ const toss = (...args)=>{
+ error(...args);
+ throw new Error(args.join(' '));
+ };
+
+ const endOfWork = (passed=true)=>{
+ const eH = document.querySelector('#color-target');
+ const eT = document.querySelector('title');
+ if(passed){
+ log("End of work chain. If you made it this far, you win.");
+ eH.innerText = 'PASS: '+eH.innerText;
+ eH.classList.add('tests-pass');
+ eT.innerText = 'PASS: '+eT.innerText;
+ }else{
+ eH.innerText = 'FAIL: '+eH.innerText;
+ eH.classList.add('tests-fail');
+ eT.innerText = 'FAIL: '+eT.innerText;
+ }
+ };
+
+ log("Running opfs-sahpool digest tests...");
+ const W1 = new Worker('digest-worker.js?sqlite3.dir=../../../jswasm');
+ W1.onmessage = function({data}){
+ //log("onmessage:",data);
+ switch(data.type){
+ case 'log':
+ log('worker says:', ...data.payload);
+ break;
+ case 'error':
+ error('worker says:', ...data.payload);
+ endOfWork(false);
+ break;
+ case 'initialized':
+ log(data.workerId, ': Worker initialized',...data.payload);
+ break;
+ }
+ };
+ })();
+ </script>
+ </body>
+</html>
diff --git a/main.mk b/main.mk
index 2803e623a..93cfe4b7c 100644
--- a/main.mk
+++ b/main.mk
@@ -1107,7 +1107,7 @@ sqlite3.h: $(MAKE_SANITY_CHECK) $(TOP)/src/sqlite.h.in \
$(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)
+ $(B.tclsh) $(EXTRA_SRC)
$(B.tclsh) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_GEN_FLAGS) $(EXTRA_SRC)
cp tsrc/sqlite3ext.h .
cp $(TOP)/ext/session/sqlite3session.h .
@@ -2168,8 +2168,11 @@ fuzzcheck$(T.exe): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
fuzzy: fuzzcheck$(T.exe)
xbin: fuzzcheck$(T.exe)
+# -fsanitize=... flags for fuzzcheck-asan.
+CFLAGS.fuzzcheck-asan.fsanitize ?= -fsanitize=address
+
fuzzcheck-asan$(T.exe): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
- $(T.link) -o $@ -fsanitize=address $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) \
+ $(T.link) -o $@ $(CFLAGS.fuzzcheck-asan.fsanitize) $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) \
sqlite3.c $(LDFLAGS.libsqlite3)
fuzzy: fuzzcheck-asan$(T.exe)
xbin: fuzzcheck-asan$(T.exe)
@@ -2189,11 +2192,110 @@ xbin: fuzzcheck-ubsan$(T.exe)
#
# FUZZDB=test/fuzzdata*.db make run-fuzzcheck
#
-run-fuzzcheck: fuzzcheck$(T.exe) fuzzcheck-asan$(T.exe) fuzzcheck-ubsan$(T.exe)
+# The original rules for this target were like this:
+#
+# run-fuzzcheck: fuzzcheck$(T.exe) fuzzcheck-asan$(T.exe) fuzzcheck-ubsan$(T.exe)
+# @if test "$(FUZZDB)" = ""; then echo 'ERROR: No FUZZDB specified. Rerun with FUZZDB=filename'; exit 1; fi
+# ./fuzzcheck$(T.exe) --spinner $(FUZZDB)
+# ./fuzzcheck-asan$(T.exe) --spinner $(FUZZDB)
+# ./fuzzcheck-ubsan$(T.exe) --spinner $(FUZZDB)
+#
+# What follows is a decomposition of these rules in a way that allows make
+# to run things in parallel when using the -jN option.
+#
+FUZZDB-check:
@if test "$(FUZZDB)" = ""; then echo 'ERROR: No FUZZDB specified. Rerun with FUZZDB=filename'; exit 1; fi
- ./fuzzcheck$(T.exe) --spinner $(FUZZDB)
- ./fuzzcheck-asan$(T.exe) --spinner $(FUZZDB)
- ./fuzzcheck-ubsan$(T.exe) --spinner $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n0
+run-fuzzcheck-n0: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 0 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n1
+run-fuzzcheck-n1: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 1 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n2
+run-fuzzcheck-n2: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 2 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n3
+run-fuzzcheck-n3: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 3 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n4
+run-fuzzcheck-n4: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 4 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n5
+run-fuzzcheck-n5: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 5 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n6
+run-fuzzcheck-n6: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 6 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n7
+run-fuzzcheck-n7: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 7 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n8
+run-fuzzcheck-n8: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 8 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-n9
+run-fuzzcheck-n9: FUZZDB-check fuzzcheck$(T.exe)
+ ./fuzzcheck$(T.exe) --slice 9 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a0
+run-fuzzcheck-a0: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 0 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a1
+run-fuzzcheck-a1: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 1 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a2
+run-fuzzcheck-a2: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 2 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a3
+run-fuzzcheck-a3: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 3 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a4
+run-fuzzcheck-a4: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 4 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a5
+run-fuzzcheck-a5: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 5 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a6
+run-fuzzcheck-a6: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 6 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a7
+run-fuzzcheck-a7: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 7 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a8
+run-fuzzcheck-a8: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 8 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-a9
+run-fuzzcheck-a9: FUZZDB-check fuzzcheck-asan$(T.exe)
+ ./fuzzcheck-asan$(T.exe) --slice 9 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u0
+run-fuzzcheck-u0: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 0 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u1
+run-fuzzcheck-u1: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 1 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u2
+run-fuzzcheck-u2: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 2 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u3
+run-fuzzcheck-u3: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 3 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u4
+run-fuzzcheck-u4: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 4 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u5
+run-fuzzcheck-u5: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 5 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u6
+run-fuzzcheck-u6: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 6 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u7
+run-fuzzcheck-u7: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 7 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u8
+run-fuzzcheck-u8: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 8 10 $(FUZZDB)
+run-fuzzcheck: run-fuzzcheck-u9
+run-fuzzcheck-u9: FUZZDB-check fuzzcheck-ubsan$(T.exe)
+ ./fuzzcheck-ubsan$(T.exe) --slice 9 10 $(FUZZDB)
+
ossshell$(T.exe): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
$(T.link) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \
diff --git a/manifest b/manifest
index aa26f838b..3c191ceb9 100644
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Document\sthat\ssqlite_update_hook()\scan\sunset\sthe\scurrent\shook\sby\spassing\sa\sNULL\scallback,\sto\saddress\s[forum:652aef4747|forum\spost\s652aef4747].
-D 2025-03-12T11:41:12.314
+C Merge\strunk\sinto\sthe\scygwin-fixes\sbranch.
+D 2025-03-19T10:14:46.977
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
-F Makefile.in 88f74a1b9fcd903fe3414fe9f8484f8491dc403615dbf1c28c6f415f5220b8b2
+F Makefile.in 2c4d3c20e42ddd7596432c8d45feeaf709f93b37279e274ea413034912a4f840
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
F Makefile.msc bb2cc6f75bbcb2d690fbdd1489914a2febd5e99bad9c77538cb3330d304694c6
F README.md a953c0cffd6e4f2501a306c00ee2b6e1e6630c25031e094629307fe99dd003d1
@@ -14,13 +14,13 @@ F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F art/sqlite370.svg 40b7e2fe8aac3add5d56dd86ab8d427a4eca5bcb3fe4f8946cb3794e1821d531
-F auto.def 0612f87776956cff7ba1585ad3ca7ab7d2e88735da0e9b4321dbacb05479cb94
+F auto.def 23f0e7eb5eff4cf922963e667ed630793ed60300df59ef9d93c87a23e31c7232
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
-F autoconf/Makefile.in 6c98c82f52aa27a5c586080cf7c61c811174c2b6d8b8de33fd657d78d541dd7d
+F autoconf/Makefile.in b499f790938d5334a5e22fa9a91af603661e714dea40cd5fb60d03f500b3ae4f
F autoconf/Makefile.msc 5bc67d3912444c40c6f96d003e5c90663e51abb83d204a520110b1b2038dcd8b
F autoconf/README.first f1d3876e9a7852c22f275a6f06814e64934cecbc0b5b9617d64849094c1fd136
F autoconf/README.txt 1a32296d8bbdd67110c79d224c92c05545a0b5bd0c272950025fe3c7c7b49580
-F autoconf/auto.def 8d81c1d728d8462a9b6c1ca0714013bbb097aee0ae5e79309d7939cead98e295
+F autoconf/auto.def 42d239bda4feffe1cf8a431dae35f83d100f2c17ed4b189edeb12f067bd4fa90
F autoconf/tea/Makefile.in ba0556fee8da09c066bad85a4457904e46ee2c2eabaa309c0e83a78f2f151a8e
F autoconf/tea/README.txt 6c396709b45eb2b3be0ae6dc7e40a140d231962e3a2354da6c4dd48b1d9999bc
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
@@ -37,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 b306314e8a87ccf873cb5b2a360c4a27bbf841df5b76f3acbd65322cff165476
+F autosetup/README.md f98cc827a162a1da4877e9656d749d414ba3f408d457d30e029afc66590c00c3
F autosetup/autosetup 74a9782b68d07934510190fbd03fc6ad92e63f0ea3b5cbffa5f0bd271ad60f01 x
F autosetup/autosetup-config.guess dfa101c5e8220e864d5e9c72a85e87110df60260d36cb951ad0a85d6d9eaa463 x
F autosetup/autosetup-config.sub a38fb074d0dece01cf919e9fb534a26011608aa8fa606490864295328526cd73 x
@@ -49,8 +49,8 @@ F autosetup/cc-shared.tcl 4f024e94a47f427ba61de1739f6381ef0080210f9fae89112d5c1d
F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e45f
F autosetup/jimsh0.c a57c16e65dcffc9c76e496757cb3f7fb47e01ecbd1631a0a5e01751fc856f049
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
-F autosetup/proj.tcl e69b91f814ea510057ce7663845de703c3746d71cff9a0db6b2563ee3e7fd25e
-F autosetup/sqlite-config.tcl 831985320d98002fcd5ea064cae8a49f8afcd9685d83178ef1ebb79189b5045c
+F autosetup/proj.tcl bdf0489d4ce8110fc1d4a09b1e2e274e50dd51711637b55c7c63a6a7ecec2aa5
+F autosetup/sqlite-config.tcl a2eb8234de355233787ad7bc926d8a622ef9f97594749374c4360b63c37fc223
F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9
F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x
F contrib/sqlitecon.tcl eb4c6578e08dd353263958da0dc620f8400b869a50d06e271ab0be85a51a08d3
@@ -80,14 +80,14 @@ F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c fd2a8642fa4701ef5dd6bce7947ecb3c7ae472e1d44022772454a8b74a13155d
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h 75b9cf37c93d3c56d8e569d64527c927cb54a5279afb3823740ca1e29e481c15
+F ext/fts3/fts3Int.h ad51347fa5a5a49f6c3bd40a961eafd08f1e410f60b64dea06f115697a2ad9fe
F ext/fts3/fts3_aux.c 7eab82a9cf0830f6551ba3abfdbe73ed39e322a4d3940ee82fbf723674ecd9f3
-F ext/fts3/fts3_expr.c 673bf600655f5080239ff0e1e80eaae0176389f7e7d3af54c6d51491280ca360
+F ext/fts3/fts3_expr.c 5c13796638d8192c388777166075cdc8bc4b6712024cd5b72c31acdbefce5984
F ext/fts3/fts3_hash.c d9dba473741445789330c7513d4f65737c92df23c3212784312931641814672a
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
F ext/fts3/fts3_icu.c 305ce7fb6036484085b5556a9c8e62acdc7763f0f4cdf5fd538212a9f3720116
F ext/fts3/fts3_porter.c 024417020c57dd1ab39816f5fe6cf45222a857b78a1f6412f040ada1ceabd4ff
-F ext/fts3/fts3_snippet.c ac402ba81ce9503a54238f975d870384f8b9fb3680f6b86eb7a1be44829a1cee
+F ext/fts3/fts3_snippet.c 55506af9c656d06ad6acef0735b67749d199617421f2e66c5b7101745b9cf1ba
F ext/fts3/fts3_term.c 6a96027ad364001432545fe43322b6af04ed28bb5619ec51af1f59d0710d6d69
F ext/fts3/fts3_test.c cc329471e573f95a6ea9fbca87e89dcfa1d355591c80172ffcd759ac521d25d8
F ext/fts3/fts3_tokenize_vtab.c 7fd9ef364f257b97218b9c331f2378e307375c592f70fd541f714e747d944962
@@ -106,14 +106,14 @@ F ext/fts3/unicode/mkunicode.tcl cbf5f7b5c8ce8014bad731f246f2e520eece908465de477
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
F ext/fts5/extract_api_docs.tcl 009cf59c77afa86d137b0cca3e3b1a5efbe2264faa2df233f9a7aa8563926d15
F ext/fts5/fts5.h ff5d3cc88b29e41612bfb29eb723e29e38973de62ca75ba3e8f94ccb67f5b5f2
-F ext/fts5/fts5Int.h 6abff7dd770dc5969c994c281e6e77fc277ce414d56cc4a62c145cc7036b0b67
+F ext/fts5/fts5Int.h bffbd0acdcdf509899681f4e1cfeef1c955030acd9fe15ff9082410f80c3bead
F ext/fts5/fts5_aux.c da4a7a9a11ec15c6df0699d908915a209bcde48f0b04101461316b59f71abffb
F ext/fts5/fts5_buffer.c f1e6d0324d7c55329d340673befc26681a372a4d36086caa8d1ec7d7c53066c7
F ext/fts5/fts5_config.c e7d8dd062b44a66cd77e5a0f74f23a2354cd1f3f8575afb967b2773c3384f7f8
-F ext/fts5/fts5_expr.c 4a35c6edc4a36862597532ace43db20f5dfd4a2f789d4fa1dd7786b677b73036
+F ext/fts5/fts5_expr.c be9e5f7f11d87e7bd3680832c93c13050fe351994b5052b0215c2ef40312c23a
F ext/fts5/fts5_hash.c a6266cedd801ab7964fa9e74ebcdda6d30ec6a96107fa24148ec6b7b5b80f6e0
-F ext/fts5/fts5_index.c 2f35dd8408946f0e0bfea8f3bfbe8dfaafe90a5345885b43d678546c19266673
-F ext/fts5/fts5_main.c b0e95a793f3c649d313c536269403e1a413ee665223adb5f8196edd2bc1146f7
+F ext/fts5/fts5_index.c d171f2a507abccb3d524bf461b01f0d3971a9bf221be622ac7c671a991cb62ee
+F ext/fts5/fts5_main.c 57933c18efe1058d8871199875c7a59744dabc3904f3aefbf9ff4a4e11fc79e2
F ext/fts5/fts5_storage.c 1ad05dab4830a4e2eaf2900bb143477f93bc17437093582f36f4b818809e88d8
F ext/fts5/fts5_tcl.c 7fb5a3d3404099075aaa2457307cb459bbc257c0de3dbd52b1e80a5b503e0329
F ext/fts5/fts5_test_mi.c d35fdd50db99a775a040fb57127a45adc968e97da94ae784eec664256ac86db2
@@ -436,7 +436,7 @@ F ext/misc/regexp.c 388e7f237307c7dfbfb8dde44e097946f6c437801d63f0d7ad63f3320d4e
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
-F ext/misc/series.c 13c13768db923313c561851c7feb0adf5c456a40d01bf7c57051895f3e4b81c7
+F ext/misc/series.c 076a4c85dde2ae543d040f1080cdab74ebf3da7f3febfe38e0cd45a2217498bf
F ext/misc/sha1.c cb5002148c2661b5946f34561701e9105e9d339b713ec8ac057fd888b196dcb9
F ext/misc/shathree.c fd22d70620f86a0467acfdd3acd8435d5cb54eb1e2d9ff36ae44e389826993df
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
@@ -523,7 +523,7 @@ F ext/recover/recoverpgsz.test 88766fcb810e52ee05335c456d4e5fb06d02b73d3ccb48c52
F ext/recover/recoverrowid.test f948bf4024a5f41b0e21b8af80c60564c5b5d78c05a8d64fc00787715ff9f45f
F ext/recover/recoverslowidx.test c90d59c46bb8924a973ac6fbc38f3163cee38cc240256addcab1cf1a322c37dc
F ext/recover/recoversql.test e66d01f95302a223bcd3fd42b5ee58dc2b53d70afa90b0d00e41e4b8eab20486
-F ext/recover/sqlite3recover.c 0ecdcb4df8967c84aa4dfe786816998bf2ef5cce55f4ac85ad4079e76f271027
+F ext/recover/sqlite3recover.c 56c216332ea91233d6d820d429f3384adbec9ecedda67aa98186b691d427cc57
F ext/recover/sqlite3recover.h 011c799f02deb70ab685916f6f538e6bb32c4e0025e79bfd0e24ff9c74820959
F ext/recover/test_recover.c 3d0fb1df7823f5bc22a0b93955034d16a2dfa2eb1e443e9a0123a77f120599a3
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
@@ -537,7 +537,7 @@ F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c3350
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 734aa36238bcd2dee91db5dba107d5fcbdb02396612811377a8ad50f1272b1c1
F ext/rtree/geopoly.c f0573d5109fdc658a180db0db6eec86ab2a1cf5ce58ec66cbf3356167ea757eb
-F ext/rtree/rtree.c 980f84e9fecfa99f80ae066e13b198505790449542f802d6b6466ed839149af4
+F ext/rtree/rtree.c 99dade93b5ca1c1fa4a5ba1381140d88b27a52573a92897827d9eb2a8059a460
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test e0608db762b2aadca0ecb6f97396cf66244490adc3ba88f2a292b27be3e1da3e
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
@@ -645,7 +645,7 @@ F ext/wasm/api/sqlite3-api-worker1.c-pp.js f646a65257973b8c4481f8a6a216370b85644
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
-F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 16d80af915bfd2529824b999b304425503094eedf34fb113d0791e002b13e5cf
+F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 0f68a64e508598910e7c01214ae27d603dfc8baec6a184506fafac603a901931
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 4ab0704ee198de7d1059eccedc7703c931510b588d10af0ee36ea5b3ebbac284
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js e809739d71e8b35dfe1b55d24d91f02d04239e6aef7ca1ea92a15a29e704f616
F ext/wasm/api/sqlite3-wasm.c 6a4cd40267eaf08400895c5b9de39c56976c3b97b3c1bbe53fc2e80fa074e9c7
@@ -680,7 +680,7 @@ F ext/wasm/index-dist.html 56132399702b15d70c474c3f1952541e25cb0922942868f70daf1
F ext/wasm/index.html bcaa00eca521b372a6a62c7e7b17a870b0fcdf3e418a5921df1fd61e5344080d
F ext/wasm/jaccwabyt/jaccwabyt.js 6e4f26d0edb5c2e7d381b7eff1924832a040a12274afab2d1e1789027e9f6c5c
F ext/wasm/jaccwabyt/jaccwabyt.md 1128e3563e7eff90b5a373395251fc76cb32386fad1fea6075b0f34a8f1b9bdf
-F ext/wasm/mkwasmbuilds.c 082b7372db68c2d4cd9f55e7cde8eb1b83e9569e520984e6b08cb62606f3bf38
+F ext/wasm/mkwasmbuilds.c 6e0b22002bc520b7af053681571a96d30049a51f7f1389e81c524e8d420f5d40
F ext/wasm/module-symbols.html dc476b403369b26a1a23773e13b80f41b9a49f0825e81435fe3600a7cfbbe337
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
@@ -696,16 +696,18 @@ 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 f3a3cbf0207287c4caa9f84b4e2934804e4b5720c71eaf143f33c8122bd3c9f2
+F ext/wasm/tester1.c-pp.js 419717b16e12703487a7ccf3ea4e63d693bdfbf7657e55a7e6c559bbccf027d3
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/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79
+F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8
F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
F ext/wasm/wasmfs.make 68999f5bd8c489239592d59a420f8c627c99169bbd6fa16a404751f757b9f702
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
-F main.mk f2f6af216cf14ec010d317e2f75ed5dc2134a2f9d6be7df3a96ee11149598ca1
+F main.mk 7006135b902177f7c8bca2733a6820b72a0c6f5a47412b2a7c86668f0398f1fd
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
@@ -725,14 +727,14 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
F src/btree.c 00fcee37947641f48d4b529d96143e74d056b7afa8f26d61292c90ee59c056b2
F src/btree.h 18e5e7b2124c23426a283523e5f31a4bff029131b795bb82391f9d2f3136fc50
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
-F src/build.c 20793695ef64d2d0c147501e37f344f828f09f16d346a987b516316186030996
+F src/build.c 3fe9b9d0f411cc2139a2d5ffa1c9b555417f89332f4dbf7f8e311c2e69e40c81
F src/callback.c acae8c8dddda41ee85cfdf19b926eefe830f371069f8aadca3aa39adf5b1c859
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/date.c 9db4d604e699a73e10b8e85a44db074a1f04c0591a77e2abfd77703f50dce1e9
F src/dbpage.c 2e677acb658a29965e55398bbc61161cb7819da538057c8032adac7ab8e4a8c0
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
-F src/expr.c f27e2692e65f0600cf4c989ec2af36bdfab52ada6365c0cc0f434630157b877f
+F src/expr.c 61c3baab38f1b50eb4696e1f37c8f7ae1d1ecbfc1a35d446cfd1886624784131
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
F src/func.c 7686ea382b20e8bfe2ab9de76150c99ee7b6e83523561f3c7787e0f68cb435c2
@@ -745,7 +747,7 @@ F src/insert.c a5f0366266be993ebf533808f22cb7a788624805b55bc45424ceed3f48c54a16
F src/json.c 81e2012796a0e139b18c50ee3444c8ef86a020ab360511882216f5b610657e0c
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
-F src/main.c 5102588cbe7668d5ee19fd9945546e4f1fd99e41815432decf5dd29f01f55597
+F src/main.c 07f78d917ffcdf327982840cfd8e855fd000527a2ea5ace372ce4febcbd0bf97
F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -779,14 +781,14 @@ F src/pragma.c 30b535d0a66348df844ee36f890617b4cf45e9a22dcbc47ec3ca92909c50aaf1
F src/prepare.c 1832be043fce7d489959aae6f994c452d023914714c4d5457beaed51c0f3d126
F src/printf.c 33fc0d7643c848a098afdcb6e1db6de12379d47084b1cd0912cfce1d09345e44
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
-F src/resolve.c 626c24b258b111f75c22107aa5614ad89810df3026f5ca071116d3fe75925c75
+F src/resolve.c 20e1fbe8f840ffc0cd835e33f68a802a22e34faa918d7a269f3de242fda02f99
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c df63f64ef91c132dd12d37c876653f8b5493d2d5cf330a27158912ee5a065451
-F src/shell.c.in ad3cb02ead5551be11ecf1433899d7585ad3bed669de0de9a70dabfd6a8a7256
+F src/select.c bfe14cdfceba54744b1c6c29099313f5173a0793dfaff0cd484774e9d05dbeab
+F src/shell.c.in 248050551cad788f8bb4b4728e00d8e36a10130d2d101e55cd51cfee03df91ff
F src/sqlite.h.in fd70afd92948cf7cc93f687ac960bad1b0b6fbc436752419eff2fd65a1809380
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h 130217107c0425ab43d098c6eadf8aa2e1a037e26d79384127e2d950b27eec77
+F src/sqliteInt.h 96133c5b4371629b30644a88108a0ca99e6a95a55509cdfc8de9961fba4bbd26
F src/sqliteLimit.h 6d817c28a8f19af95e6f4921933b7fbbca48a962bce0eb0ec81e8bb3ef38e68b
F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -844,30 +846,30 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 3e37ac2b6cbb9b0abe33827b0153c27595269afd7152b48019808974481aca2c
F src/treeview.c d85ce76e6d1498d781957c07cb234da6d77ce0ed2d196480d516f54dabc62279
-F src/trigger.c da3c25786870d8bf97cd46b493374c2375d1abaf20a9b0f5f8629a3f2f2ce383
+F src/trigger.c 3ffb8ed6b64dbcc0ccae6e82435d01be3bf547e13b814e2d46f7df9bef84748e
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
F src/utf.c d4d55ca95106a2029ec1cdbd2497a34e69ea1d338f1a9d80ef15ebf4ff01690d
F src/util.c 36fb1150062957280777655976f3f9a75db236cb8207a0770ceae8d5ec17fcd3
F src/vacuum.c fbfc3e074c865d2b5b10b8a65a3783275b80c152653590690747a102bb6cc770
-F src/vdbe.c 014769c8f7e528d59f5a8e25d0035258396cc2c755673dee29885b6049725ee6
-F src/vdbe.h 3d26d5c7660c5c7bd33ffb0d8784615072d8b23c81f8110870efe2631136bc89
-F src/vdbeInt.h 078b1c15b26587b54c1c1879d0d2f4dec812b9de4c337fed9faf73fbcc3bf091
-F src/vdbeapi.c cb8eb9e41a16f5fa3ce5b8f3910edfbba336d10156cfb7a79f92cf7bf443977b
-F src/vdbeaux.c d7ef1a0a7233589d789eda1ba9ffa4b0ea61fca9651e4f47fb4250d03d62bcaf
-F src/vdbeblob.c 9166b6eb7054e5da82e35255892fb1ed551355a4716452539e8e3ac14f25fbe3
+F src/vdbe.c b5deed01000b3970cfca089dc531cf9342afd96d00cc8b4ad26d303f088116ee
+F src/vdbe.h 31eddcffc1d14c76c2a20fe4e137e1ee43d44f370896fae14a067052801a3625
+F src/vdbeInt.h 5446f60e89b2aa7cdf3ab0ec4e7b01b8732cd9d52d9092a0b8b1bf700768f784
+F src/vdbeapi.c a9ad72afed9aaec2acdde4daa5caa2f342b298f8c8859704143f6e3b78cb9966
+F src/vdbeaux.c 72a1c99d9300a5e0adff2c708074ac1355a619664301db474a48e147418fba05
+F src/vdbeblob.c b1b4032cac46b41e44b957c4d00aee9851f862dfd85ecb68116ba49884b03dfd
F src/vdbemem.c 571ae3116dbf840a62c4aaa6bc09d577dfef8ad4d3978cf37275bb5f9653217b
-F src/vdbesort.c f7ce6eb4c0e8b0273329d2f43b8b6e5ebe8f2d853fc323d5787dada702ea0b66
+F src/vdbesort.c 49e366d0216c782eba287bf602384e4330d2526a22f1275492d2785ce103c79b
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
F src/vtab.c 828221bdbeaaa6d62126ee6d07fd4ec0d09dcaea846f87ad01944d8b7e548859
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c 2c69a5f92270429db72d853691b0640c76c671d5b2465396dadb9d9873e1efce
+F src/wal.c 554a6b1afaaecb98cb47bb598bccf1374c9d3b624e5c4c3c4eb2ad364cc579f8
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
-F src/where.c 12cca5dfbe96e2589f951c43c0720fc58e52611787c37d85a0d9c10376202e8b
-F src/whereInt.h d20cddddb1d61b18d5cb1fcfa9b77fbeebbc4afe44d996e603452a23b3009ee1
-F src/wherecode.c 5baa06f0daae7d38aca1d4814030b82ad4f127fe6bad18f0644776a474f6088b
+F src/where.c e80177e452b4e436abc6ece0cb0249631000434f2a7425cc1df709015fce74ad
+F src/whereInt.h ecdbfb5551cf394f04ec7f0bc7ad963146d80eee3071405ac29aa84950128b8e
+F src/wherecode.c 0d3de258d7922aede028841c6e0060633c50be26737c92cc62ce8be280535430
F src/whereexpr.c 2415c8eee5ff89a8b709d7d83d71c1ff986cd720d0520057e1d8a5371339012a
F src/window.c d01227141f622f24fbe36ca105fbe6ef023f9fd98f1ccd65da95f88886565db5
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -973,7 +975,7 @@ F test/bind2.test 918bc35135f4141809ead7585909cde57d44db90a7a62aef540127148f91aa
F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0
F test/bitvec.test 75894a880520164d73b1305c1c3f96882615e142
F test/blob.test e7ac6c7d3a985cc4678c64f325292529a69ae252
-F test/bloom1.test cf613a27054bbaf61c5bfc440a5cfd3ff76798d0695f3fc5e5d1bbc819b8dab1
+F test/bloom1.test 04f3a17df8912bfdc292c41b59d79f93893fe69799f3089a64451f9112f9658f
F test/boundary1.tcl 6421b2d920d8b09539503a8673339d32f7609eb1
F test/boundary1.test 66d7f4706ccdb42d58eafdb081de07b0eb42d77b
F test/boundary2.tcl e34ef4e930cf1083150d4d2c603e146bd3b76bcb
@@ -1278,7 +1280,7 @@ F test/fuzz3.test 70ba57260364b83e964707b9d4b5625284239768ab907dd387c740c0370ce3
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
-F test/fuzzcheck.c 97eab1b916d576a0f734b921598bdac05ff04d1f15c494dbe40ca71a772c56bb
+F test/fuzzcheck.c 19f8af47a5c4ee2c3943fdee270f1f14e3d83fe968a9737a7557fb4e3c06efc1
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
@@ -1639,7 +1641,7 @@ F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test 573942b8d0e444956445993d5a5275c6912bc49b654441eec0b5e1e735f2e5b7
-F test/shell2.test 01a01f76ed98088ce598794fbf5b359e148271541a8ddbf79d21cc353cc67a24
+F test/shell2.test ac102ebc0a9ec166257600c4ee8bdefec242163afced295f10b004f4af3fc9dd
F test/shell3.test db1953a8e59d08e9240b7cc5948878e184f7eb2623591587f8fd1f1a5bd536d8
F test/shell4.test 522fdc628c55eff697b061504fb0a9e4e6dfc5d9087a633ab0f3dd11bcc4f807
F test/shell5.test 0e5f8ce08206b9998a778cfe1989e20e47839153c05af2da29198150172e22fc
@@ -1717,7 +1719,7 @@ F test/sync.test a619e407ede58a7b6e3e44375328628559fc9695a9c24c47cb5690a866b0031
F test/sync2.test 06152269ed73128782c450c355988fe8dd794d305833af75e1a5e79edd4dae47
F test/syscall.test a067468b43b8cb2305e9f9fe414e5f40c875bb5d2cba5f00b8154396e95fcf37
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
-F test/tabfunc01.test 7be82bd50c7ede7f01b2dd17cd1b84f352c516078222d0b067d858f081e3f9a7
+F test/tabfunc01.test 76da0509b01b9d12f4e71f8af28ee702d38166a5306bd77a955fb1a370dcd8b5
F test/table.test 7862a00b58b5541511a26757ea9c5c7c3f8298766e98aa099deec703d9c0a8e0
F test/tableapi.test e37c33e6be2276e3a96bb54b00eea7f321277115d10e5b30fdb52a112b432750
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
@@ -2149,7 +2151,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176
F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f005910876a
F tool/mkautoconfamal.sh c5e65fa1c922f2e3b3e4f6cd0331ec7d84bdef085f32cb1c46673cdf95ec8090
-F tool/mkccode.tcl 210159febe0ef0ecbc53c79833500663ceaba0115b2b374405818dc835b5f84b x
+F tool/mkccode.tcl c42a8f8cf78f92e83795d5447460dbce7aaf78a3bbf9082f1507dc71a3665f3c x
F tool/mkctimec.tcl f76dbfc74cefad8d126384ba3263677939f077bd184fcdf8c592a1daf64f50c3 x
F tool/mkkeywordhash.c 6b0be901c47f9ad42215fc995eb2f4384ac49213b1fba395102ec3e999acf559
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
@@ -2193,7 +2195,7 @@ F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d40618 x
F tool/split-sqlite3c.tcl 07e18a1d8cc3f6b3a4a1f3528e63c9b29a5c8a7bca0b8d394b231da464ce1247
F tool/sqldiff.c 134be7866be19f8beb32043d5aea5657f01aaeae2df8d33d758ff722c78666b9
-F tool/sqlite3_analyzer.c.in 51bb46e23ee549474f246094dc4f2fdf176b40a02d8ff84aaabebec3ba4cf0eb
+F tool/sqlite3_analyzer.c.in 14f02cb5ec3c264cd6107d1f1dad77092b1cf440fc196c30b69ae87b56a1a43b
F tool/sqlite3_rsync.c 9a1cca2ab1271c59b37a6493c15dc1bcd0ab9149197a9125926bc08dd26b83fb
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
@@ -2213,8 +2215,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 2861788e479aea12354f2d34d8e6a2706d193642674ef1f4f852f24c877e0140
-R 39ece01250415efbd73e452eb44cdc31
+P 2b582c0097e3374beb280dfa6b03e0dacb9911da1bceb0dce0468e6b7291e74f 77db4d85e70fbf358ae2321c2601966666bdb4d971d7c113ce30a3e541458ee8
+R 9b9d0869d79f691a2d44f05be20e722b
U stephan
-Z 0209cd6647f7cb13545ac5e22f3084f2
+Z 6468abdf425e00ebe7ee3dcb4f7ed502
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 0702ddd0a..5b4fc8d77 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-2b582c0097e3374beb280dfa6b03e0dacb9911da1bceb0dce0468e6b7291e74f
+34eadd374b3c0a8c9e1f5f4a1c60fda8f16b1c56213b8c4047f96390c676b695
diff --git a/src/build.c b/src/build.c
index 907494b19..267962666 100644
--- a/src/build.c
+++ b/src/build.c
@@ -3633,7 +3633,7 @@ void sqlite3CreateForeignKey(
}else{
nCol = pFromCol->nExpr;
}
- nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
+ nByte = SZ_FKEY(nCol) + pTo->n + 1;
if( pToCol ){
for(i=0; i<pToCol->nExpr; i++){
nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1;
@@ -4692,12 +4692,11 @@ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
sqlite3 *db = pParse->db;
int i;
if( pList==0 ){
- pList = sqlite3DbMallocZero(db, sizeof(IdList) );
+ pList = sqlite3DbMallocZero(db, SZ_IDLIST(1));
if( pList==0 ) return 0;
}else{
IdList *pNew;
- pNew = sqlite3DbRealloc(db, pList,
- sizeof(IdList) + pList->nId*sizeof(pList->a));
+ pNew = sqlite3DbRealloc(db, pList, SZ_IDLIST(pList->nId+1));
if( pNew==0 ){
sqlite3IdListDelete(db, pList);
return 0;
@@ -4796,8 +4795,7 @@ SrcList *sqlite3SrcListEnlarge(
return 0;
}
if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST;
- pNew = sqlite3DbRealloc(db, pSrc,
- sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
+ pNew = sqlite3DbRealloc(db, pSrc, SZ_SRCLIST(nAlloc));
if( pNew==0 ){
assert( db->mallocFailed );
return 0;
@@ -4872,7 +4870,7 @@ SrcList *sqlite3SrcListAppend(
assert( pParse->db!=0 );
db = pParse->db;
if( pList==0 ){
- pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) );
+ pList = sqlite3DbMallocRawNN(pParse->db, SZ_SRCLIST(1));
if( pList==0 ) return 0;
pList->nAlloc = 1;
pList->nSrc = 1;
@@ -5758,10 +5756,9 @@ With *sqlite3WithAdd(
}
if( pWith ){
- sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte);
- pNew = sqlite3DbRealloc(db, pWith, nByte);
+ pNew = sqlite3DbRealloc(db, pWith, SZ_WITH(pWith->nCte+1));
}else{
- pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
+ pNew = sqlite3DbMallocZero(db, SZ_WITH(1));
}
assert( (pNew!=0 && zName!=0) || db->mallocFailed );
diff --git a/src/expr.c b/src/expr.c
index a3c41a1f5..dd5ea2038 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1738,7 +1738,7 @@ static Expr *exprDup(
With *sqlite3WithDup(sqlite3 *db, With *p){
With *pRet = 0;
if( p ){
- sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
+ sqlite3_int64 nByte = SZ_WITH(p->nCte);
pRet = sqlite3DbMallocZero(db, nByte);
if( pRet ){
int i;
@@ -1865,11 +1865,9 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){
SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
SrcList *pNew;
int i;
- int nByte;
assert( db!=0 );
if( p==0 ) return 0;
- nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
- pNew = sqlite3DbMallocRawNN(db, nByte );
+ pNew = sqlite3DbMallocRawNN(db, SZ_SRCLIST(p->nSrc) );
if( pNew==0 ) return 0;
pNew->nSrc = pNew->nAlloc = p->nSrc;
for(i=0; i<p->nSrc; i++){
@@ -1931,7 +1929,7 @@ IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
int i;
assert( db!=0 );
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) );
+ pNew = sqlite3DbMallocRawNN(db, SZ_IDLIST(p->nId));
if( pNew==0 ) return 0;
pNew->nId = p->nId;
for(i=0; i<p->nId; i++){
@@ -2015,7 +2013,7 @@ SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew(
struct ExprList_item *pItem;
ExprList *pList;
- pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 );
+ pList = sqlite3DbMallocRawNN(db, SZ_EXPRLIST(4));
if( pList==0 ){
sqlite3ExprDelete(db, pExpr);
return 0;
@@ -2035,8 +2033,7 @@ SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow(
struct ExprList_item *pItem;
ExprList *pNew;
pList->nAlloc *= 2;
- pNew = sqlite3DbRealloc(db, pList,
- sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0]));
+ pNew = sqlite3DbRealloc(db, pList, SZ_EXPRLIST(pList->nAlloc));
if( pNew==0 ){
sqlite3ExprListDelete(db, pList);
sqlite3ExprDelete(db, pExpr);
diff --git a/src/main.c b/src/main.c
index ba2faf0b7..9b67de815 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3845,7 +3845,7 @@ int sqlite3_set_clientdata(
return SQLITE_OK;
}else{
size_t n = strlen(zName);
- p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
+ p = sqlite3_malloc64( SZ_DBCLIENTDATA(n+1) );
if( p==0 ){
if( xDestructor ) xDestructor(pData);
sqlite3_mutex_leave(db->mutex);
diff --git a/src/resolve.c b/src/resolve.c
index 54ce4fb1e..c3ab2d557 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -2277,20 +2277,22 @@ int sqlite3ResolveSelfReference(
Expr *pExpr, /* Expression to resolve. May be NULL. */
ExprList *pList /* Expression list to resolve. May be NULL. */
){
- SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
+ SrcList *pSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
int rc;
+ u8 srcSpace[SZ_SRCLIST_1]; /* Memory space for the fake SrcList */
assert( type==0 || pTab!=0 );
assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr
|| type==NC_GenCol || pTab==0 );
memset(&sNC, 0, sizeof(sNC));
- memset(&sSrc, 0, sizeof(sSrc));
+ pSrc = (SrcList*)srcSpace;
+ memset(pSrc, 0, SZ_SRCLIST_1);
if( pTab ){
- sSrc.nSrc = 1;
- sSrc.a[0].zName = pTab->zName;
- sSrc.a[0].pSTab = pTab;
- sSrc.a[0].iCursor = -1;
+ pSrc->nSrc = 1;
+ pSrc->a[0].zName = pTab->zName;
+ pSrc->a[0].pSTab = pTab;
+ pSrc->a[0].iCursor = -1;
if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
/* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
** schema elements */
@@ -2298,7 +2300,7 @@ int sqlite3ResolveSelfReference(
}
}
sNC.pParse = pParse;
- sNC.pSrcList = &sSrc;
+ sNC.pSrcList = pSrc;
sNC.ncFlags = type | NC_IsDDL;
if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc;
if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList);
diff --git a/src/select.c b/src/select.c
index 904290223..b2f2cc7fb 100644
--- a/src/select.c
+++ b/src/select.c
@@ -154,7 +154,7 @@ Select *sqlite3SelectNew(
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = 0;
- if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
+ if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1);
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
@@ -1537,8 +1537,8 @@ static void selectInnerLoop(
** X extra columns.
*/
KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
- int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
- KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
+ int nExtra = (N+X)*(sizeof(CollSeq*)+1);
+ KeyInfo *p = sqlite3DbMallocRawNN(db, SZ_KEYINFO(0) + nExtra);
if( p ){
p->aSortFlags = (u8*)&p->aColl[N+X];
p->nKeyField = (u16)N;
@@ -1546,7 +1546,7 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
p->enc = ENC(db);
p->db = db;
p->nRef = 1;
- memset(&p[1], 0, nExtra);
+ memset(p->aColl, 0, nExtra);
}else{
return (KeyInfo*)sqlite3OomFault(db);
}
@@ -3247,6 +3247,7 @@ static int multiSelect(
multi_select_end:
pDest->iSdst = dest.iSdst;
pDest->nSdst = dest.nSdst;
+ pDest->iSDParm2 = dest.iSDParm2;
if( pDelete ){
sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete);
}
@@ -6062,7 +6063,7 @@ static int selectExpander(Walker *pWalker, Select *p){
pEList = p->pEList;
if( pParse->pWith && (p->selFlags & SF_View) ){
if( p->pWith==0 ){
- p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With));
+ p->pWith = (With*)sqlite3DbMallocZero(db, SZ_WITH(1) );
if( p->pWith==0 ){
return WRC_Abort;
}
@@ -7250,7 +7251,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
pExpr = 0;
pSub = sqlite3SubqueryDetach(db, pFrom);
sqlite3SrcListDelete(db, p->pSrc);
- p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
+ p->pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1);
while( pSub ){
Expr *pTerm;
pPrior = pSub->pPrior;
diff --git a/src/shell.c.in b/src/shell.c.in
index 655982e73..93d73e6ac 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -13475,6 +13475,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
** the database filename.
*/
for(i=0; i<nCmd; i++){
+ echo_group_input(&data, azCmd[i]);
if( azCmd[i][0]=='.' ){
rc = do_meta_command(azCmd[i], &data);
if( rc ){
@@ -13483,7 +13484,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
}else{
open_db(&data, 0);
- echo_group_input(&data, azCmd[i]);
rc = shell_exec(&data, azCmd[i], &zErrMsg);
if( zErrMsg || rc ){
if( zErrMsg!=0 ){
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 034f98690..35e5b94d7 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -765,7 +765,17 @@
** ourselves.
*/
#ifndef offsetof
-#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
+#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+
+/*
+** Work around C99 "flex-array" syntax for pre-C99 compilers, so as
+** to avoid complaints from -fsanitize=strict-bounds.
+*/
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
#endif
/*
@@ -2577,9 +2587,13 @@ struct FKey {
struct sColMap { /* Mapping of columns in pFrom to columns in zTo */
int iFrom; /* Index of column in pFrom */
char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */
- } aCol[1]; /* One entry for each of nCol columns */
+ } aCol[FLEXARRAY]; /* One entry for each of nCol columns */
};
+/* The size (in bytes) of an FKey object holding N columns. The answer
+** does NOT include space to hold the zTo name. */
+#define SZ_FKEY(N) (offsetof(FKey,aCol)+(N)*sizeof(struct sColMap))
+
/*
** SQLite supports many different ways to resolve a constraint
** error. ROLLBACK processing means that a constraint violation
@@ -2641,9 +2655,12 @@ struct KeyInfo {
u16 nAllField; /* Total columns, including key plus others */
sqlite3 *db; /* The database connection */
u8 *aSortFlags; /* Sort order for each column. */
- CollSeq *aColl[1]; /* Collating sequence for each term of the key */
+ CollSeq *aColl[FLEXARRAY]; /* Collating sequence for each term of the key */
};
+/* The size (in bytes) of a KeyInfo object with up to N fields */
+#define SZ_KEYINFO(N) (offsetof(KeyInfo,aColl) + (N)*sizeof(CollSeq*))
+
/*
** Allowed bit values for entries in the KeyInfo.aSortFlags[] array.
*/
@@ -3216,9 +3233,14 @@ struct ExprList {
int iConstExprReg; /* Register in which Expr value is cached. Used only
** by Parse.pConstExpr */
} u;
- } a[1]; /* One slot for each expression in the list */
+ } a[FLEXARRAY]; /* One slot for each expression in the list */
};
+/* The size (in bytes) of an ExprList object that is big enough to hold
+** as many as N expressions. */
+#define SZ_EXPRLIST(N) \
+ (offsetof(ExprList,a) + (N)*sizeof(struct ExprList_item))
+
/*
** Allowed values for Expr.a.eEName
*/
@@ -3246,9 +3268,12 @@ struct IdList {
int nId; /* Number of identifiers on the list */
struct IdList_item {
char *zName; /* Name of the identifier */
- } a[1];
+ } a[FLEXARRAY];
};
+/* The size (in bytes) of an IdList object that can hold up to N IDs. */
+#define SZ_IDLIST(N) (offsetof(IdList,a)+(N)*sizeof(struct IdList_item))
+
/*
** Allowed values for IdList.eType, which determines which value of the a.u4
** is valid.
@@ -3368,11 +3393,19 @@ struct OnOrUsing {
**
*/
struct SrcList {
- int nSrc; /* Number of tables or subqueries in the FROM clause */
- u32 nAlloc; /* Number of entries allocated in a[] below */
- SrcItem a[1]; /* One entry for each identifier on the list */
+ int nSrc; /* Number of tables or subqueries in the FROM clause */
+ u32 nAlloc; /* Number of entries allocated in a[] below */
+ SrcItem a[FLEXARRAY]; /* One entry for each identifier on the list */
};
+/* Size (in bytes) of a SrcList object that can hold as many as N
+** SrcItem objects. */
+#define SZ_SRCLIST(N) (offsetof(SrcList,a)+(N)*sizeof(SrcItem))
+
+/* Size (in bytes( of a SrcList object that holds 1 SrcItem. This is a
+** special case of SZ_SRCITEM(1) that comes up often. */
+#define SZ_SRCLIST_1 (offsetof(SrcList,a)+sizeof(SrcItem))
+
/*
** Permitted values of the SrcList.a.jointype field
*/
@@ -4436,9 +4469,13 @@ struct With {
int nCte; /* Number of CTEs in the WITH clause */
int bView; /* Belongs to the outermost Select of a view */
With *pOuter; /* Containing WITH clause, or NULL */
- Cte a[1]; /* For each CTE in the WITH clause.... */
+ Cte a[FLEXARRAY]; /* For each CTE in the WITH clause.... */
};
+/* The size (in bytes) of a With object that can hold as many
+** as N different CTEs. */
+#define SZ_WITH(N) (offsetof(With,a) + (N)*sizeof(Cte))
+
/*
** The Cte object is not guaranteed to persist for the entire duration
** of code generation. (The query flattener or other parser tree
@@ -4467,9 +4504,13 @@ struct DbClientData {
DbClientData *pNext; /* Next in a linked list */
void *pData; /* The data */
void (*xDestructor)(void*); /* Destructor. Might be NULL */
- char zName[1]; /* Name of this client data. MUST BE LAST */
+ char zName[FLEXARRAY]; /* Name of this client data. MUST BE LAST */
};
+/* The size (in bytes) of a DbClientData object that can has a name
+** that is N bytes long, including the zero-terminator. */
+#define SZ_DBCLIENTDATA(N) (offsetof(DbClientData,zName)+(N))
+
#ifdef SQLITE_DEBUG
/*
** An instance of the TreeView object is used for printing the content of
diff --git a/src/trigger.c b/src/trigger.c
index 604c3ab42..779da5e5f 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -1039,7 +1039,8 @@ static void codeReturningTrigger(
ExprList *pNew;
Returning *pReturning;
Select sSelect;
- SrcList sFrom;
+ SrcList *pFrom;
+ u8 fromSpace[SZ_SRCLIST_1];
assert( v!=0 );
if( !pParse->bReturning ){
@@ -1055,13 +1056,14 @@ static void codeReturningTrigger(
return;
}
memset(&sSelect, 0, sizeof(sSelect));
- memset(&sFrom, 0, sizeof(sFrom));
+ pFrom = (SrcList*)fromSpace;
+ memset(pFrom, 0, SZ_SRCLIST_1);
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
- sSelect.pSrc = &sFrom;
- sFrom.nSrc = 1;
- sFrom.a[0].pSTab = pTab;
- sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
- sFrom.a[0].iCursor = -1;
+ sSelect.pSrc = pFrom;
+ pFrom->nSrc = 1;
+ pFrom->a[0].pSTab = pTab;
+ pFrom->a[0].zName = pTab->zName; /* tag-20240424-1 */
+ pFrom->a[0].iCursor = -1;
sqlite3SelectPrep(pParse, &sSelect, 0);
if( pParse->nErr==0 ){
assert( db->mallocFailed==0 );
diff --git a/src/vdbe.c b/src/vdbe.c
index ed5687f25..6ded15c79 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -278,9 +278,9 @@ static VdbeCursor *allocateCursor(
i64 nByte;
VdbeCursor *pCx = 0;
- nByte =
- ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
- (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
+ nByte = SZ_VDBECURSOR(nField);
+ assert( ROUND8(nByte)==nByte );
+ if( eCurType==CURTYPE_BTREE ) nByte += sqlite3BtreeCursorSize();
assert( iCur>=0 && iCur<p->nCursor );
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
@@ -313,8 +313,8 @@ static VdbeCursor *allocateCursor(
pCx->nField = nField;
pCx->aOffset = &pCx->aType[nField];
if( eCurType==CURTYPE_BTREE ){
- pCx->uc.pCursor = (BtCursor*)
- &pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
+ assert( ROUND8(SZ_VDBECURSOR(nField))==SZ_VDBECURSOR(nField) );
+ pCx->uc.pCursor = (BtCursor*)&pMem->z[SZ_VDBECURSOR(nField)];
sqlite3BtreeCursorZero(pCx->uc.pCursor);
}
return pCx;
@@ -7705,7 +7705,7 @@ case OP_AggStep: {
**
** Note: We could avoid this by using a regular memory cell from aMem[] for
** the accumulator, instead of allocating one here. */
- nAlloc = ROUND8P( sizeof(pCtx[0]) + (n-1)*sizeof(sqlite3_value*) );
+ nAlloc = ROUND8P( SZ_CONTEXT(n) );
pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem));
if( pCtx==0 ) goto no_mem;
pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc);
diff --git a/src/vdbe.h b/src/vdbe.h
index 476f1b4ea..dc98e270e 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -319,8 +319,8 @@ int sqlite3NotPureFunc(sqlite3_context*);
int sqlite3VdbeBytecodeVtabInit(sqlite3*);
#endif
-/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
-** each VDBE opcode.
+/* Use SQLITE_ENABLE_EXPLAIN_COMMENTS to enable generation of extra
+** comments on each VDBE opcode.
**
** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op
** comments in VDBE programs that show key decision points in the code
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 12af82726..13262cd4e 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -133,12 +133,19 @@ struct VdbeCursor {
#endif
VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */
- /* 2*nField extra array elements allocated for aType[], beyond the one
- ** static element declared in the structure. nField total array slots for
- ** aType[] and nField+1 array slots for aOffset[] */
- u32 aType[1]; /* Type values record decode. MUST BE LAST */
+ /* Space is allocated for aType to hold at least 2*nField+1 entries:
+ ** nField slots for aType[] and nField+1 array slots for aOffset[] */
+ u32 aType[FLEXARRAY]; /* Type values record decode. MUST BE LAST */
};
+/*
+** The size (in bytes) of a VdbeCursor object that has an nField value of N
+** or less. The value of SZ_VDBECURSOR(n) is guaranteed to be a multiple
+** of 8.
+*/
+#define SZ_VDBECURSOR(N) \
+ (ROUND8(offsetof(VdbeCursor,aType)) + ((N)+1)*sizeof(u64))
+
/* Return true if P is a null-only cursor
*/
#define IsNullCursor(P) \
@@ -395,9 +402,16 @@ struct sqlite3_context {
u8 enc; /* Encoding to use for results */
u8 skipFlag; /* Skip accumulator loading if true */
u16 argc; /* Number of arguments */
- sqlite3_value *argv[1]; /* Argument set */
+ sqlite3_value *argv[FLEXARRAY]; /* Argument set */
};
+/*
+** The size (in bytes) of an sqlite3_context object that holds N
+** argv[] arguments.
+*/
+#define SZ_CONTEXT(N) \
+ (offsetof(sqlite3_context,argv)+(N)*sizeof(sqlite3_value*))
+
/* The ScanStatus object holds a single value for the
** sqlite3_stmt_scanstatus() interface.
@@ -531,7 +545,7 @@ struct PreUpdate {
VdbeCursor *pCsr; /* Cursor to read old values from */
int op; /* One of SQLITE_INSERT, UPDATE, DELETE */
u8 *aRecord; /* old.* database record */
- KeyInfo keyinfo;
+ KeyInfo *pKeyinfo; /* Key information */
UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */
UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
int iNewReg; /* Register for new.* values */
@@ -543,6 +557,7 @@ struct PreUpdate {
Table *pTab; /* Schema object being updated */
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
sqlite3_value **apDflt; /* Array of default values, if required */
+ u8 keyinfoSpace[SZ_KEYINFO(0)]; /* Space to hold pKeyinfo[0] content */
};
/*
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 31880d85b..523f80097 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -2216,7 +2216,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
if( !aRec ) goto preupdate_old_out;
rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
if( rc==SQLITE_OK ){
- p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
+ p->pUnpacked = vdbeUnpackRecord(p->pKeyinfo, nRec, aRec);
if( !p->pUnpacked ) rc = SQLITE_NOMEM;
}
if( rc!=SQLITE_OK ){
@@ -2281,7 +2281,7 @@ int sqlite3_preupdate_count(sqlite3 *db){
#else
p = db->pPreUpdate;
#endif
- return (p ? p->keyinfo.nKeyField : 0);
+ return (p ? p->pKeyinfo->nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -2364,7 +2364,7 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
Mem *pData = &p->v->aMem[p->iNewReg];
rc = ExpandBlob(pData);
if( rc!=SQLITE_OK ) goto preupdate_new_out;
- pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
+ pUnpack = vdbeUnpackRecord(p->pKeyinfo, pData->n, pData->z);
if( !pUnpack ){
rc = SQLITE_NOMEM;
goto preupdate_new_out;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 6a8db6f39..6d36f7280 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -445,12 +445,10 @@ int sqlite3VdbeAddFunctionCall(
int eCallCtx /* Calling context */
){
Vdbe *v = pParse->pVdbe;
- int nByte;
int addr;
sqlite3_context *pCtx;
assert( v );
- nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*);
- pCtx = sqlite3DbMallocRawNN(pParse->db, nByte);
+ pCtx = sqlite3DbMallocRawNN(pParse->db, SZ_CONTEXT(nArg));
if( pCtx==0 ){
assert( pParse->db->mallocFailed );
freeEphemeralFunction(pParse->db, (FuncDef*)pFunc);
@@ -5526,10 +5524,11 @@ void sqlite3VdbePreUpdateHook(
preupdate.pCsr = pCsr;
preupdate.op = op;
preupdate.iNewReg = iReg;
- preupdate.keyinfo.db = db;
- preupdate.keyinfo.enc = ENC(db);
- preupdate.keyinfo.nKeyField = pTab->nCol;
- preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder;
+ preupdate.pKeyinfo = (KeyInfo*)&preupdate.keyinfoSpace;
+ preupdate.pKeyinfo->db = db;
+ preupdate.pKeyinfo->enc = ENC(db);
+ preupdate.pKeyinfo->nKeyField = pTab->nCol;
+ preupdate.pKeyinfo->aSortFlags = (u8*)&fakeSortOrder;
preupdate.iKey1 = iKey1;
preupdate.iKey2 = iKey2;
preupdate.pTab = pTab;
@@ -5539,8 +5538,8 @@ void sqlite3VdbePreUpdateHook(
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
db->pPreUpdate = 0;
sqlite3DbFree(db, preupdate.aRecord);
- vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
- vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
+ vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pUnpacked);
+ vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pNewUnpacked);
sqlite3VdbeMemRelease(&preupdate.oldipk);
if( preupdate.aNew ){
int i;
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index 79698d0af..42edcf7de 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -133,6 +133,7 @@ int sqlite3_blob_open(
char *zErr = 0;
Table *pTab;
Incrblob *pBlob = 0;
+ int iDb;
Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -178,7 +179,10 @@ int sqlite3_blob_open(
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
- if( !pTab ){
+ if( pTab==0
+ || ((iDb = sqlite3SchemaToIndex(db, pTab->pSchema))==1 &&
+ sqlite3OpenTempDatabase(&sParse))
+ ){
if( sParse.zErrMsg ){
sqlite3DbFree(db, zErr);
zErr = sParse.zErrMsg;
@@ -189,7 +193,7 @@ int sqlite3_blob_open(
goto blob_open_out;
}
pBlob->pTab = pTab;
- pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
+ pBlob->zDb = db->aDb[iDb].zDbSName;
/* Now search pTab for the exact column. */
iCol = sqlite3ColumnIndex(pTab, zColumn);
@@ -273,7 +277,6 @@ int sqlite3_blob_open(
{OP_Halt, 0, 0, 0}, /* 5 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
- int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
VdbeOp *aOp;
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
diff --git a/src/vdbesort.c b/src/vdbesort.c
index c9da88f6e..9a7e0760c 100644
--- a/src/vdbesort.c
+++ b/src/vdbesort.c
@@ -332,9 +332,12 @@ struct VdbeSorter {
u8 iPrev; /* Previous thread used to flush PMA */
u8 nTask; /* Size of aTask[] array */
u8 typeMask;
- SortSubtask aTask[1]; /* One or more subtasks */
+ SortSubtask aTask[FLEXARRAY]; /* One or more subtasks */
};
+/* Size (in bytes) of a VdbeSorter object that works with N or fewer subtasks */
+#define SZ_VDBESORTER(N) (offsetof(VdbeSorter,aTask)+(N)*sizeof(SortSubtask))
+
#define SORTER_TYPE_INTEGER 0x01
#define SORTER_TYPE_TEXT 0x02
@@ -966,8 +969,8 @@ int sqlite3VdbeSorterInit(
assert( pCsr->eCurType==CURTYPE_SORTER );
assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*)
< 0x7fffffff );
- szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
- sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
+ szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nKeyField+1);
+ sz = SZ_VDBESORTER(nWorker+1);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
pCsr->uc.pSorter = pSorter;
diff --git a/src/wal.c b/src/wal.c
index d374d6eb4..7f091a48c 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -597,9 +597,13 @@ struct WalIterator {
u32 *aPgno; /* Array of page numbers. */
int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
int iZero; /* Frame number associated with aPgno[0] */
- } aSegment[1]; /* One for every 32KB page in the wal-index */
+ } aSegment[FLEXARRAY]; /* One for every 32KB page in the wal-index */
};
+/* Size (in bytes) of a WalIterator object suitable for N or fewer segments */
+#define SZ_WALITERATOR(N) \
+ (offsetof(WalIterator,aSegment)*(N)*sizeof(struct WalSegment))
+
/*
** Define the parameters of the hash tables in the wal-index file. There
** is a hash-table following every HASHTABLE_NPAGE page numbers in the
@@ -1960,8 +1964,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
/* Allocate space for the WalIterator object. */
nSegment = walFramePage(iLast) + 1;
- nByte = sizeof(WalIterator)
- + (nSegment-1)*sizeof(struct WalSegment)
+ nByte = SZ_WALITERATOR(nSegment)
+ iLast*sizeof(ht_slot);
p = (WalIterator *)sqlite3_malloc64(nByte
+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
diff --git a/src/where.c b/src/where.c
index 127525006..ed6320349 100644
--- a/src/where.c
+++ b/src/where.c
@@ -35,11 +35,16 @@ struct HiddenIndexInfo {
int eDistinct; /* Value to return from sqlite3_vtab_distinct() */
u32 mIn; /* Mask of terms that are <col> IN (...) */
u32 mHandleIn; /* Terms that vtab will handle as <col> IN (...) */
- sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST
- ** because extra space is allocated to hold up
- ** to nTerm such values */
+ sqlite3_value *aRhs[FLEXARRAY]; /* RHS values for constraints. MUST BE LAST
+ ** Extra space is allocated to hold up
+ ** to nTerm such values */
};
+/* Size (in bytes) of a HiddenIndeInfo object sufficient to hold as
+** many as N constraints */
+#define SZ_HIDDENINDEXINFO(N) \
+ (offsetof(HiddenIndexInfo,aRhs) + (N)*sizeof(sqlite3_value*))
+
/* Forward declaration of methods */
static int whereLoopResize(sqlite3*, WhereLoop*, int);
@@ -1517,8 +1522,8 @@ static sqlite3_index_info *allocateIndexInfo(
*/
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
- + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden)
- + sizeof(sqlite3_value*)*nTerm );
+ + sizeof(*pIdxOrderBy)*nOrderBy
+ + SZ_HIDDENINDEXINFO(nTerm) );
if( pIdxInfo==0 ){
sqlite3ErrorMsg(pParse, "out of memory");
return 0;
@@ -6712,10 +6717,7 @@ WhereInfo *sqlite3WhereBegin(
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
- nByteWInfo = ROUND8P(sizeof(WhereInfo));
- if( nTabList>1 ){
- nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel));
- }
+ nByteWInfo = SZ_WHEREINFO(nTabList);
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
if( db->mallocFailed ){
sqlite3DbFree(db, pWInfo);
diff --git a/src/whereInt.h b/src/whereInt.h
index 8ba8a7072..40a720ab9 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -501,10 +501,15 @@ struct WhereInfo {
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
WhereClause sWC; /* Decomposition of the WHERE clause */
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
- WhereLevel a[1]; /* Information about each nest loop in WHERE */
+ WhereLevel a[FLEXARRAY]; /* Information about each nest loop in WHERE */
};
/*
+** The size (in bytes) of a WhereInfo object that holds N WhereLevels.
+*/
+#define SZ_WHEREINFO(N) ROUND8(offsetof(WhereInfo,a)+(N)*sizeof(WhereLevel))
+
+/*
** Private interfaces - callable only by other where.c routines.
**
** where.c:
diff --git a/src/wherecode.c b/src/wherecode.c
index 1a0cdc6d7..5fe230813 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -2313,8 +2313,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
- pOrTab = sqlite3DbMallocRawNN(db,
- sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
+ pOrTab = sqlite3DbMallocRawNN(db, SZ_SRCLIST(nNotReady+1));
if( pOrTab==0 ) return notReady;
pOrTab->nAlloc = (u8)(nNotReady + 1);
pOrTab->nSrc = pOrTab->nAlloc;
@@ -2857,7 +2856,8 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
WhereInfo *pSubWInfo;
WhereLoop *pLoop = pLevel->pWLoop;
SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
- SrcList sFrom;
+ SrcList *pFrom;
+ u8 fromSpace[SZ_SRCLIST_1];
Bitmask mAll = 0;
int k;
@@ -2901,13 +2901,14 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
}
}
- sFrom.nSrc = 1;
- sFrom.nAlloc = 1;
- memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));
- sFrom.a[0].fg.jointype = 0;
+ pFrom = (SrcList*)fromSpace;
+ pFrom->nSrc = 1;
+ pFrom->nAlloc = 1;
+ memcpy(&pFrom->a[0], pTabItem, sizeof(SrcItem));
+ pFrom->a[0].fg.jointype = 0;
assert( pParse->withinRJSubrtn < 100 );
pParse->withinRJSubrtn++;
- pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0,
+ pSubWInfo = sqlite3WhereBegin(pParse, pFrom, pSubWhere, 0, 0, 0,
WHERE_RIGHT_JOIN, 0);
if( pSubWInfo ){
int iCur = pLevel->iTabCur;
diff --git a/test/bloom1.test b/test/bloom1.test
index 151f364ae..f8efcc184 100644
--- a/test/bloom1.test
+++ b/test/bloom1.test
@@ -183,6 +183,47 @@ do_execsql_test 4.3 {
do_execsql_test 4.4 {
SELECT * FROM t0 LEFT JOIN t1 LEFT JOIN t2 ON (b NOTNULL)==(c IN ()) WHERE c;
} {xyz {} 7.0}
+
+reset_db
+do_execsql_test 5.0 {
+ CREATE TABLE t1 (c1);
+ INSERT INTO t1 VALUES (101);
+ CREATE TABLE t2 ( x );
+ INSERT INTO t2 VALUES(404);
+}
+
+do_execsql_test 5.1 {
+ SELECT 'val' in (
+ select 'val' from ( select 'valueB' from t1 order by 1 )
+ union all
+ select 'val'
+ );
+} {1}
+
+do_execsql_test 5.2 {
+ select * from t2
+ where 'val' in (
+ select 'val' from ( select 'valueB' from t1 order by 1 )
+ union all
+ select 'val'
+ );
+} {404}
+
+do_execsql_test 5.3 {
+ SELECT subq_1.c_0 as c_0
+ FROM ( SELECT 0 as c_0) as subq_1
+ WHERE (subq_1.c_0) IN (
+ SELECT subq_2.c_0 as c_0
+ FROM (
+ SELECT 0 as c_0
+ FROM t1 as ref_1
+ WHERE (ref_1.c1) = (2)
+ ORDER BY c_0 desc
+ ) as subq_2
+ UNION ALL
+ SELECT 0 as c_0
+ );
+} {0}
finish_test
diff --git a/test/fuzzcheck.c b/test/fuzzcheck.c
index 140ad6944..09898d7b3 100644
--- a/test/fuzzcheck.c
+++ b/test/fuzzcheck.c
@@ -88,6 +88,11 @@
#include "sqlite3recover.h"
#define ISSPACE(X) isspace((unsigned char)(X))
#define ISDIGIT(X) isdigit((unsigned char)(X))
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
#ifdef __unix__
@@ -129,9 +134,12 @@ struct Blob {
int id; /* Id of this Blob */
int seq; /* Sequence number */
int sz; /* Size of this Blob in bytes */
- unsigned char a[1]; /* Blob content. Extra space allocated as needed. */
+ unsigned char a[FLEXARRAY]; /* Blob content. Allocated as needed. */
};
+/* Size in bytes of a Blob object sufficient to store N byte of content */
+#define SZ_BLOB(N) (offsetof(Blob,a) + (((N)+7)&~7))
+
/*
** Maximum number of files in the in-memory virtual filesystem.
*/
@@ -384,6 +392,21 @@ static void renderDbSqlForCLI(
}
/*
+** Find the tail (the last component) of a pathname.
+*/
+static const char *pathTail(const char *zPath){
+ const char *zTail = zPath;
+ while( zPath[0] ){
+ if( zPath[0]=='/' && zPath[1]!=0 ) zTail = &zPath[1];
+#ifndef __unix__
+ if( zPath[0]=='\\' && zPath[1]!=0 ) zTail = &zPath[1];
+#endif
+ zPath++;
+ }
+ return zTail;
+}
+
+/*
** Read the complete content of a file into memory. Add a 0x00 terminator
** and return a pointer to the result.
**
@@ -512,13 +535,15 @@ static void blobListLoadFromDb(
int *pN, /* OUT: Write number of blobs loaded here */
Blob **ppList /* OUT: Write the head of the blob list here */
){
- Blob head;
+ Blob *head;
Blob *p;
sqlite3_stmt *pStmt;
int n = 0;
int rc;
char *z2;
+ unsigned char tmp[SZ_BLOB(8)];
+ head = (Blob*)tmp;
if( firstId>0 ){
z2 = sqlite3_mprintf("%s WHERE rowid BETWEEN %d AND %d", zSql,
firstId, lastId);
@@ -528,11 +553,11 @@ static void blobListLoadFromDb(
rc = sqlite3_prepare_v2(db, z2, -1, &pStmt, 0);
sqlite3_free(z2);
if( rc ) fatalError("%s", sqlite3_errmsg(db));
- head.pNext = 0;
- p = &head;
+ head->pNext = 0;
+ p = head;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
int sz = sqlite3_column_bytes(pStmt, 1);
- Blob *pNew = safe_realloc(0, sizeof(*pNew)+sz );
+ Blob *pNew = safe_realloc(0, SZ_BLOB(sz+1));
pNew->id = sqlite3_column_int(pStmt, 0);
pNew->sz = sz;
pNew->seq = n++;
@@ -544,7 +569,7 @@ static void blobListLoadFromDb(
}
sqlite3_finalize(pStmt);
*pN = n;
- *ppList = head.pNext;
+ *ppList = head->pNext;
}
/*
@@ -1837,6 +1862,7 @@ static void showHelp(void){
"Read databases and SQL scripts from SOURCE-DB and execute each script against\n"
"each database, checking for crashes and memory leaks.\n"
"Options:\n"
+" --brief Output only a summary of results at the end\n"
" --cell-size-check Set the PRAGMA cell_size_check=ON\n"
" --dbid M..N Use only the databases where dbid between M and N\n"
" \"M..\" for M and afterwards. Just \"M\" for M only\n"
@@ -1863,6 +1889,7 @@ static void showHelp(void){
" --result-trace Show the results of each SQL command\n"
" --script Output CLI script instead of running tests\n"
" --skip N Skip the first N test cases\n"
+" --slice M N Run only the M-th out of each group of N tests\n"
" --spinner Use a spinner to show progress\n"
" --sqlid M..N Use only SQL where sqlid between M..N\n"
" \"M..\" for M and afterwards. Just \"M\" for M only\n"
@@ -1877,6 +1904,7 @@ static void showHelp(void){
int main(int argc, char **argv){
sqlite3_int64 iBegin; /* Start time of this program */
int quietFlag = 0; /* True if --quiet or -q */
+ int briefFlag = 0; /* Output summary report at the end */
int verboseFlag = 0; /* True if --verbose or -v */
char *zInsSql = 0; /* SQL statement for --load-db or --load-sql */
int iFirstInsArg = 0; /* First argv[] for --load-db or --load-sql */
@@ -1924,6 +1952,8 @@ int main(int argc, char **argv){
int nV; /* How much to increase verbosity with -vvvv */
sqlite3_int64 tmStart; /* Start of each test */
int iEstTime = 0; /* LPF for the time-to-go */
+ int iSliceSz = 0; /* Divide the test space into this many pieces */
+ int iSliceIdx = 0; /* Only run the piece with this index */
sqlite3_config(SQLITE_CONFIG_URI,1);
registerOomSimulator();
@@ -1944,6 +1974,12 @@ int main(int argc, char **argv){
if( z[0]=='-' ){
z++;
if( z[0]=='-' ) z++;
+ if( strcmp(z,"brief")==0 ){
+ briefFlag = 1;
+ quietFlag = 1;
+ verboseFlag = 1;
+ eVerbosity = 0;
+ }else
if( strcmp(z,"cell-size-check")==0 ){
cellSzCkFlag = 1;
}else
@@ -2034,6 +2070,7 @@ int main(int argc, char **argv){
g.uRandom = atoi(argv[++i]);
}else
if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){
+ briefFlag = 0;
quietFlag = 1;
verboseFlag = 0;
eVerbosity = 0;
@@ -2052,12 +2089,19 @@ int main(int argc, char **argv){
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
nSkip = atoi(argv[++i]);
}else
+ if( strcmp(z,"slice")==0 ){
+ if( i>=argc-2 ) fatalError("missing arguments on %s", argv[i]);
+ iSliceIdx = integerValue(argv[++i]);
+ iSliceSz = integerValue(argv[++i]);
+ /* --slice implices --brief */
+ briefFlag = 1;
+ quietFlag = 1;
+ verboseFlag = 1;
+ eVerbosity = 0;
+ }else
if( strcmp(z,"spinner")==0 ){
bSpinner = 1;
}else
- if( strcmp(z,"timer")==0 ){
- bTimer = 1;
- }else
if( strcmp(z,"sqlid")==0 ){
const char *zDotDot;
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
@@ -2083,10 +2127,14 @@ int main(int argc, char **argv){
fatalError("timeout is not available on non-unix systems");
#endif
}else
+ if( strcmp(z,"timer")==0 ){
+ bTimer = 1;
+ }else
if( strcmp(z,"vdbe-debug")==0 ){
bVdbeDebug = 1;
}else
if( strcmp(z,"verbose")==0 ){
+ briefFlag = 0;
quietFlag = 0;
verboseFlag++;
eVerbosity++;
@@ -2153,6 +2201,12 @@ int main(int argc, char **argv){
fatalError("cannot import into more than one database");
}
}
+ if( iSliceSz<=iSliceIdx
+ || iSliceSz<=0
+ || iSliceIdx<0
+ ){
+ iSliceSz = iSliceIdx = 0;
+ }
/* Process each source database separately */
for(iSrcDb=0; iSrcDb<nSrcDb; iSrcDb++){
@@ -2442,6 +2496,10 @@ int main(int argc, char **argv){
for(pSql=g.pFirstSql; pSql; pSql=pSql->pNext){
tmStart = timeOfDay();
if( isDbSql(pSql->a, pSql->sz) ){
+ if( iSliceSz>0 && (nTest%iSliceSz)!=iSliceIdx ){
+ nTest++;
+ continue;
+ }
sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d",pSql->id);
if( bScript ){
/* No progress output */
@@ -2500,6 +2558,10 @@ int main(int argc, char **argv){
for(pDb=g.pFirstDb; pDb; pDb=pDb->pNext){
int openFlags;
const char *zVfs = "inmem";
+ if( iSliceSz>0 && (nTest%iSliceSz)!=iSliceIdx ){
+ nTest++;
+ continue;
+ }
sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d,dbid=%d",
pSql->id, pDb->id);
if( bScript ){
@@ -2606,7 +2668,20 @@ int main(int argc, char **argv){
}
}
}
- if( bScript ){
+ if( briefFlag ){
+ sqlite3_int64 iElapse = timeOfDay() - iBegin;
+ if( iSliceSz>0 ){
+ printf("%s %s: slice %d/%d of %d tests, %d.%03d seconds\n",
+ pathTail(argv[0]), pathTail(g.zDbFile),
+ iSliceIdx, iSliceSz, nTest,
+ (int)(iElapse/1000), (int)(iElapse%1000));
+ }else{
+ printf("%s %s: 0 errors, %d tests, %d.%03d seconds\n",
+ pathTail(argv[0]), pathTail(g.zDbFile), nTest,
+ (int)(iElapse/1000), (int)(iElapse%1000));
+ }
+ iBegin = timeOfDay();
+ }else if( bScript ){
/* No progress output */
}else if( bSpinner ){
int nTotal = g.nDb*g.nSql;
@@ -2624,6 +2699,7 @@ int main(int argc, char **argv){
} /* End loop over all source databases */
+
if( !quietFlag && !bScript ){
sqlite3_int64 iElapse = timeOfDay() - iBegin;
if( g.nInvariant ){
diff --git a/test/shell2.test b/test/shell2.test
index ee5ae4bdd..3f9fec9ef 100644
--- a/test/shell2.test
+++ b/test/shell2.test
@@ -224,24 +224,24 @@ do_test shell2-1.4.10 {
set res [catchcmd :memory: [string trim {
SELECT * FROM generate_series(9223372036854775807,9223372036854775807,1);
SELECT * FROM generate_series(9223372036854775807,9223372036854775807,-1);
- SELECT avg(rowid),min(value),max(value) FROM generate_series(
+ SELECT avg(value),min(value),max(value) FROM generate_series(
-9223372036854775808,9223372036854775807,1085102592571150095);
SELECT * FROM generate_series(-9223372036854775808,9223372036854775807,
9223372036854775807);
- SELECT value,rowid FROM generate_series(-4611686018427387904,
+ SELECT value FROM generate_series(-4611686018427387904,
4611686018427387904, 4611686018427387904) ORDER BY value DESC;
SELECT * FROM generate_series(0,-2,-1);
SELECT * FROM generate_series(0,-2);
SELECT * FROM generate_series(0,2) LIMIT 3;}]]
} {0 {9223372036854775807
9223372036854775807
-9.5|-9223372036854775808|9223372036854775807
+-0.5|-9223372036854775808|9223372036854775807
-9223372036854775808
-1
9223372036854775806
-4611686018427387904|3
-0|2
--4611686018427387904|1
+4611686018427387904
+0
+-4611686018427387904
0
-1
-2
diff --git a/test/tabfunc01.test b/test/tabfunc01.test
index b6797171e..c16fb9bec 100644
--- a/test/tabfunc01.test
+++ b/test/tabfunc01.test
@@ -61,10 +61,10 @@ do_execsql_test tabfunc01-1.8 {
} {30 25 20 15 10 5 0}
do_execsql_test tabfunc01-1.9 {
SELECT rowid, * FROM generate_series(0,32,5) ORDER BY value DESC;
-} {7 30 6 25 5 20 4 15 3 10 2 5 1 0}
+} {30 30 25 25 20 20 15 15 10 10 5 5 0 0}
do_execsql_test tabfunc01-1.10 {
SELECT rowid, * FROM generate_series(0,32,5) ORDER BY +value DESC;
-} {7 30 6 25 5 20 4 15 3 10 2 5 1 0}
+} {30 30 25 25 20 20 15 15 10 10 5 5 0 0}
do_execsql_test tabfunc01-1.20 {
CREATE VIEW v1(a,b) AS VALUES(1,2),(3,4);
@@ -181,6 +181,19 @@ do_execsql_test tabfunc01-4.4 {
SELECT * FROM (generate_series(1,5,2)) AS x LIMIT 10;
} {1 3 5}
+# 2025-03-13 forum post bf2dc8e909983511
+#
+do_execsql_test tabfunc01-5.1 {
+ SELECT value
+ FROM generate_series(60,73,6)
+ WHERE value=66;
+} 66
+do_execsql_test tabfunc01-5.2 {
+ SELECT value
+ FROM generate_series(73,60,-6)
+ WHERE value=67;
+} 67
+
# The next series of tests is verifying that virtual table are able
# to optimize the IN operator, even on terms that are not marked "omit".
# When the generate_series virtual table is compiled for the testfixture,
@@ -370,7 +383,18 @@ do_execsql_test 1100 {
where (ref_3.value) in (select 1);
} {1}
-
+# 2025-03-18 /forumpost/1e17219c88
+# The generate_series() table-valued function is modified so that its
+# rowid is always its value. That way it can be used on the RHS of a
+# RIGHT JOIN.
+#
+do_execsql_test 1200 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(value INT);
+ INSERT INTO t1 VALUES (1),(2),(3);
+ SELECT t1.value, t2.value
+ FROM t1 RIGHT JOIN generate_series(1,3,1) AS t2 USING(value);
+} {1 1 2 2 3 3}
# Free up memory allocations
intarray_addr
diff --git a/tool/mkccode.tcl b/tool/mkccode.tcl
index ecafbdadb..8b4fae82c 100755
--- a/tool/mkccode.tcl
+++ b/tool/mkccode.tcl
@@ -1,17 +1,16 @@
-#!/usr/bin/tclsh
+#!/bin/env tclsh
#
-# Use this script to build C-language source code for a program that uses
-# tclsqlite.c together with custom TCL scripts and/or C extensions for
-# either SQLite or TCL.
+# This script is used to amalgamate C source code files into a single
+# unit.
#
# Usage example:
#
# tclsh mkccode.tcl -DENABLE_FEATURE_XYZ demoapp.c.in >demoapp.c
#
# The demoapp.c.in file contains a mixture of C code, TCL script, and
-# processing directives used by mktclsqliteprog.tcl to build the final C-code
-# output file. Most lines of demoapp.c.in are copied straight through into
-# the output. The following control directives are recognized:
+# processing directives used by mkccode.tcl to build the final C-code
+# output file. Most lines of demoapp.c.in are copied straight through
+# into the output. The following control directives are recognized:
#
# BEGIN_STRING
#
diff --git a/tool/sqlite3_analyzer.c.in b/tool/sqlite3_analyzer.c.in
index 5aef4639b..9860c0b0f 100644
--- a/tool/sqlite3_analyzer.c.in
+++ b/tool/sqlite3_analyzer.c.in
@@ -61,6 +61,7 @@ static int subst_puts(
}
sqlite3_fputs(zOut, pOut);
if( addNewLine ) sqlite3_fputs("\n", pOut);
+ fflush(pOut);
return TCL_OK;
}
#endif /* defined(_WIN32) */