Compare commits
140 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b783ec950 | |||
| 847d2ed685 | |||
| 18a9bdd90a | |||
| 3e2ecc390b | |||
| a1dede1e58 | |||
| 982274b8e9 | |||
| e83ffd5c87 | |||
| 393a4d8ac5 | |||
| 987870a6a0 | |||
| a804a65617 | |||
| 5279cbd353 | |||
| c14ae9cd3b | |||
| ed7981ea3e | |||
| e1f7ec65fd | |||
| 505d8a43db | |||
| 408c991017 | |||
| 09cc9b5184 | |||
| 9bafbd122b | |||
| 7a796b702f | |||
| 8b34ce7d61 | |||
| 826bebdb31 | |||
| 388c1da56e | |||
| 9e6474c5a8 | |||
| 319870836c | |||
| a9025a5f1a | |||
| 237778289b | |||
| 57a533a7c3 | |||
| f47095a5a0 | |||
| 791b767b26 | |||
| ce53b80819 | |||
| b867030b1a | |||
| 7efded5edc | |||
| f07576429e | |||
| 14fcb8252a | |||
| a79f685533 | |||
| 240397bb03 | |||
| 4ac766cc05 | |||
| 73caea1764 | |||
| 998ebf1de7 | |||
| 051e942f5d | |||
| 4182294987 | |||
| c55d8262cf | |||
| 66b37e991b | |||
| 0aca0ccf2c | |||
| 748c0adb62 | |||
| e77530050e | |||
| 366e0ed80c | |||
| 201066302e | |||
| 29bdac3ee5 | |||
| 53ba0b80f2 | |||
| c2aa8e3875 | |||
| b799156a31 | |||
| 23e4ae2121 | |||
| abc23b5404 | |||
| e977440d79 | |||
| bb3b269ba9 | |||
| 1bf7eb3d49 | |||
| f1c37a357e | |||
| d95fffc9af | |||
| 4733884eae | |||
| 0dfa31d279 | |||
| 15c6d88381 | |||
| eaacb4ac37 | |||
| 0c747e1653 | |||
| e5c8467a8e | |||
| b2b8ab6bc8 | |||
| 7f70085071 | |||
| a183595edd | |||
| 63ab7c625c | |||
| 1c19c06246 | |||
| da17de532f | |||
| 1ed6441bb1 | |||
| c129de05bb | |||
| 6acd8d28fd | |||
| 139ec38ac8 | |||
| 41fda52f3c | |||
| 7fb2545905 | |||
| 3a61466a2f | |||
| 916fc1129c | |||
| a8a99becb5 | |||
| f3b396494f | |||
| 4ebf49168a | |||
| c6b86ba2ab | |||
| c5ff2aa7cf | |||
| cb36dc3f3e | |||
| bc5e0be7f8 | |||
| 7c86a0321e | |||
| d443f0a95f | |||
| 34b1bf16ec | |||
| 74cd3c53f9 | |||
| ffbfc27fab | |||
| 5a9ada593f | |||
| 9c0770537f | |||
| 6cc222c3be | |||
| db0d47b749 | |||
| e34f35c833 | |||
| 626351d444 | |||
| 6e27846323 | |||
| 8ce786f173 | |||
| 6b9230d2a1 | |||
| 241004f8fc | |||
| 89a9efe840 | |||
| 4f177f1d3e | |||
| d4ead9b9e4 | |||
| f57d368078 | |||
| 3fceae3b95 | |||
| 38113d392d | |||
| a105989856 | |||
| ecbeefecd0 | |||
| 2b24d8957e | |||
| 726e836108 | |||
| 7be565f0cc | |||
| c053b57716 | |||
| 0d859b4828 | |||
| ab29c24dc3 | |||
| dcc07d3ca6 | |||
| 234c6c4bf0 | |||
| 86319b841a | |||
| f4e66056ac | |||
| 76db3a6e66 | |||
| 003737d1dc | |||
| 02c5f3976f | |||
| be4d0c2e2f | |||
| aeb886bc53 | |||
| 2f9311c5cb | |||
| 093b26e8e0 | |||
| 63ee854264 | |||
| 3ba506d9cc | |||
| 67fa337744 | |||
| 033dbac510 | |||
| 9af334f54a | |||
| 4bb53ab2e4 | |||
| 7adc9a5978 | |||
| acdda1075d | |||
| bc2691d5c1 | |||
| 95c188d557 | |||
| 4043096408 | |||
| d06a0be514 | |||
| 984e446891 | |||
| 774ce0ba43 |
+10
-16
@@ -30,14 +30,12 @@ The public domain source files usually contain a header comment
|
||||
similar to the following to make it clear that the software is
|
||||
public domain.
|
||||
|
||||
> ~~~
|
||||
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.
|
||||
~~~
|
||||
> 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.
|
||||
|
||||
Almost every file you find in this source repository will be
|
||||
public domain. But there are a small number of exceptions:
|
||||
@@ -49,9 +47,7 @@ This repository contains a (relatively) small amount of non-public-domain
|
||||
code used to help implement the configuration and build logic. In other
|
||||
words, there are some non-public-domain files used to implement:
|
||||
|
||||
> ~~~
|
||||
./configure && make
|
||||
~~~
|
||||
> ./configure && make
|
||||
|
||||
In all cases, the non-public-domain files included with this
|
||||
repository have generous BSD-style licenses. So anyone is free to
|
||||
@@ -69,7 +65,7 @@ third-party build scripts in order to compile SQLite.
|
||||
Non-public-domain code included in this respository includes:
|
||||
|
||||
* The ["autosetup"](http://msteveb.github.io/autosetup/) configuration
|
||||
system that is contained (mostly) the autosetup/ directory, but also
|
||||
system that is contained (mostly) in the autosetup/ directory, but also
|
||||
includes the "./configure" script at the top-level of this archive.
|
||||
Autosetup has a separate BSD-style license. See the
|
||||
[autosetup/LICENSE](http://msteveb.github.io/autosetup/license/)
|
||||
@@ -79,13 +75,11 @@ Non-public-domain code included in this respository includes:
|
||||
software found in the legacy autoconf/ directory and its
|
||||
subdirectories.
|
||||
|
||||
The following unix shell command is can be run from the top-level
|
||||
The following unix shell command can be run from the top-level
|
||||
of this source repository in order to remove all non-public-domain
|
||||
code:
|
||||
|
||||
> ~~~
|
||||
rm -rf configure autosetup autoconf
|
||||
~~~
|
||||
> rm -rf configure autosetup autoconf
|
||||
|
||||
If you unpack this source repository and then run the command above, what
|
||||
is left will be 100% public domain.
|
||||
|
||||
@@ -1770,6 +1770,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_PERCENTILE=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
|
||||
!ENDIF
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
This repository contains the complete source code for the
|
||||
[SQLite database engine](https://sqlite.org/), including
|
||||
many test scripts. However, other test scripts
|
||||
and most of the documentation are managed separately.
|
||||
many tests. Additional tests and most documentation
|
||||
are managed separately.
|
||||
|
||||
See the [on-line documentation](https://sqlite.org/) for more information
|
||||
about what SQLite is and how it works from a user's perspective. This
|
||||
@@ -53,39 +53,32 @@ then no longer be fully in the public domain.
|
||||
|
||||
## Obtaining The SQLite Source Code
|
||||
|
||||
If you do not want to use Fossil, you can download tarballs or ZIP
|
||||
archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
|
||||
Source code tarballs or ZIP archives are available at:
|
||||
|
||||
* Latest trunk check-in as
|
||||
[Tarball](https://sqlite.org/src/tarball/sqlite.tar.gz),
|
||||
[ZIP-archive](https://sqlite.org/src/zip/sqlite.zip), or
|
||||
[SQLite-archive](https://sqlite.org/src/sqlar/sqlite.sqlar).
|
||||
* [Latest trunk check-in](https://sqlite.org/src/rchvdwnld/trunk).
|
||||
|
||||
* Latest release as
|
||||
[Tarball](https://sqlite.org/src/tarball/sqlite.tar.gz?r=release),
|
||||
[ZIP-archive](https://sqlite.org/src/zip/sqlite.zip?r=release), or
|
||||
[SQLite-archive](https://sqlite.org/src/sqlar/sqlite.sqlar?r=release).
|
||||
* [Latest release](https://sqlite.org/src/rchvdwnld/release)
|
||||
|
||||
* For other check-ins, substitute an appropriate branch name or
|
||||
tag or hash prefix in place of "release" in the URLs of the previous
|
||||
bullet. Or browse the [timeline](https://sqlite.org/src/timeline)
|
||||
to locate the check-in desired, click on its information page link,
|
||||
then click on the "Tarball" or "ZIP Archive" links on the information
|
||||
page.
|
||||
* For other check-ins, browse the
|
||||
[project timeline](https://sqlite.org/src/timeline?y=ci) and
|
||||
click on the check-in hash of the check-in you want to download.
|
||||
On the resulting "info" page, click one of the options to the
|
||||
right of the "**Downloads:**" label in the "**Overview**" section
|
||||
near the top.
|
||||
|
||||
To access sources directly using [Fossil](https://fossil-scm.org/home),
|
||||
first install Fossil version 2.0 or later.
|
||||
Source tarballs and precompiled binaries available at
|
||||
Source tarballs and precompiled binaries for Fossil are available at
|
||||
<https://fossil-scm.org/home/uv/download.html>. Fossil is
|
||||
a stand-alone program. To install, simply download or build the single
|
||||
executable file and put that file someplace on your $PATH.
|
||||
executable file and put that file someplace on your $PATH or %PATH%.
|
||||
Then run commands like this:
|
||||
|
||||
mkdir -p ~/sqlite
|
||||
cd ~/sqlite
|
||||
fossil open https://sqlite.org/src
|
||||
|
||||
The "fossil open" command will take two or three minutes. Afterwards,
|
||||
The initial "fossil open" command will take two or three minutes. Afterwards,
|
||||
you can do fast, bandwidth-efficient updates to the whatever versions
|
||||
of SQLite you like. Some examples:
|
||||
|
||||
@@ -152,7 +145,8 @@ show what changes are needed.
|
||||
## Compiling for Windows Using MSVC
|
||||
|
||||
On Windows, everything can be compiled with MSVC.
|
||||
You will also need a working installation of TCL.
|
||||
You will also need a working installation of TCL if you want to run tests.
|
||||
TCL is not required if you just want to build SQLite itself.
|
||||
See the [compile-for-windows.md](doc/compile-for-windows.md) document for
|
||||
additional information about how to install MSVC and TCL and configure your
|
||||
build environment.
|
||||
@@ -164,8 +158,8 @@ TCL library, using a command like this:
|
||||
|
||||
SQLite uses "tclsh.exe" as part of the build process, and so that
|
||||
program will need to be somewhere on your %PATH%. SQLite itself
|
||||
does not contain any TCL code, but it does use TCL to help with the
|
||||
build process and to run tests. You may need to install TCL development
|
||||
does not contain any TCL code, but it does use TCL to run tests.
|
||||
You may need to install TCL development
|
||||
libraries in order to successfully complete some makefile targets.
|
||||
It is helpful, but is not required, to install the SQLite TCL extension
|
||||
(the "tclextension-install" target) prior to running tests.
|
||||
|
||||
@@ -327,6 +327,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_CARRAY=1
|
||||
!ENDIF
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
!ENDIF
|
||||
@@ -349,6 +350,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
|
||||
# Always enable math functions on Windows
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PERCENTILE
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
|
||||
@@ -119,7 +119,7 @@ TCLLIBDIR = @TCLLIBDIR@
|
||||
# typically come from the ./configure command-line invocation).
|
||||
#
|
||||
CFLAGS.configure = @SH_CFLAGS@ @TEAISH_CFLAGS@ @CFLAGS@ @CPPFLAGS@ $(TCL_INCLUDE_SPEC)
|
||||
#CFLAGS.configure += -DUSE_TCL_STUBS=1
|
||||
CFLAGS.configure += -DUSE_TCL_STUBS=@TEAISH_USE_STUBS@
|
||||
|
||||
#
|
||||
# LDFLAGS.configure = LDFLAGS as known at configure-time.
|
||||
@@ -153,6 +153,7 @@ tx.src = @TEAISH_EXT_SRC@
|
||||
# gets set up via the configure script.
|
||||
#
|
||||
tx.CFLAGS =
|
||||
tx.CPPFLAGS =
|
||||
|
||||
#
|
||||
# tx.LDFLAGS is typically set by teaish.make, whereas TEAISH_LDFLAGS
|
||||
@@ -218,7 +219,7 @@ config.log: @TEAISH_TEST_TCL_IN@
|
||||
# CC variant for compiling Tcl-using sources.
|
||||
#
|
||||
CC.tcl = \
|
||||
$(CC) -o $@ $(CFLAGS.configure) $(CFLAGS) $(tx.CFLAGS)
|
||||
$(CC) -o $@ $(CFLAGS.configure) $(CFLAGS) $(tx.CFLAGS) $(tx.CPPFLAGS)
|
||||
|
||||
#
|
||||
# CC variant for linking $(tx.src) into an extension DLL. Note that
|
||||
|
||||
+1
-1
@@ -557,7 +557,7 @@ proc proj-opt-define-bool {args} {
|
||||
if {$invert} {
|
||||
set rc [expr {!$rc}]
|
||||
}
|
||||
msg-result $rc
|
||||
msg-result [string map {0 no 1 yes} $rc]
|
||||
define $defName $rc
|
||||
return $rc
|
||||
}
|
||||
|
||||
+19
-17
@@ -557,7 +557,25 @@ proc proc-debug {msg} {
|
||||
}
|
||||
|
||||
define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
|
||||
define OPT_SHELL {} ; # Feature-related CFLAGS for the sqlite3 CLI app
|
||||
#
|
||||
# OPT_SHELL = feature-related CFLAGS for the sqlite3 CLI app. The
|
||||
# list's initial values are defaults which are always applied and not
|
||||
# affected by --feature-flags. The list is appended to by various
|
||||
# --feature-flags.
|
||||
define OPT_SHELL {
|
||||
-DSQLITE_DQS=0
|
||||
-DSQLITE_ENABLE_FTS4
|
||||
-DSQLITE_ENABLE_RTREE
|
||||
-DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
-DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
-DSQLITE_ENABLE_STMTVTAB
|
||||
-DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
-DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
-DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
-DSQLITE_ENABLE_PERCENTILE
|
||||
-DSQLITE_STRICT_SUBTYPE=1
|
||||
}
|
||||
########################################################################
|
||||
# Adds $args, if not empty, to OPT_FEATURE_FLAGS. If the first arg is
|
||||
# -shell then it strips that arg and passes the remaining args the
|
||||
@@ -616,21 +634,6 @@ proc sqlite-check-common-bins {} {
|
||||
}
|
||||
}
|
||||
|
||||
# A workaround for the strchrnul() check on some Mac platforms:
|
||||
# https://sqlite.org/forum/forumpost/95edc7a8d7d1de59
|
||||
proc sqlite-check-strchrnul {} {
|
||||
msg-checking "Checking for strchrnul()... "
|
||||
if {[cctest -link 1 \
|
||||
-includes {string.h} \
|
||||
-code {(void)strchrnul("foo",'f');}]} {
|
||||
define HAVE_STRCHRNUL 1
|
||||
msg-result yes
|
||||
} else {
|
||||
define HAVE_STRCHRNUL 0
|
||||
msg-result no
|
||||
}
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Run checks for system-level includes and libs which are common to
|
||||
# both the canonical build and the "autoconf" bundle.
|
||||
@@ -647,7 +650,6 @@ proc sqlite-check-common-system-deps {} {
|
||||
# Check for needed/wanted functions
|
||||
cc-check-functions gmtime_r isnan localtime_r localtime_s \
|
||||
usleep utime pread pread64 pwrite pwrite64
|
||||
sqlite-check-strchrnul
|
||||
|
||||
apply {{} {
|
||||
set ldrt ""
|
||||
|
||||
@@ -220,7 +220,9 @@ proc teaish-configure-core {} {
|
||||
=> {Full pathname of tclsh to use. It is used for trying to find
|
||||
tclConfig.sh. Warning: if its containing dir has multiple tclsh
|
||||
versions, it may select the wrong tclConfig.sh!
|
||||
Defaults to the $TCLSH environment variable.}
|
||||
Defaults to the $TCLSH environment variable.}
|
||||
|
||||
tcl-stubs=0 => {Enable use of Tcl stubs library.}
|
||||
|
||||
# TEA has --with-tclinclude but it appears to only be useful for
|
||||
# building an extension against an uninstalled copy of TCL's own
|
||||
@@ -498,6 +500,8 @@ proc teaish__configure_phase1 {} {
|
||||
}
|
||||
teaish-checks-run -post
|
||||
|
||||
define TEAISH_USE_STUBS [opt-bool tcl-stubs]
|
||||
|
||||
apply {{} {
|
||||
# Set up "vsatisfies" code for pkgIndex.tcl.in,
|
||||
# _teaish.tester.tcl.in, and for a configure-time check. We would
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Notes On Compiling SQLite On Windows 11
|
||||
|
||||
Below are step-by-step instructions on how to build SQLite from
|
||||
canonical source on a new Windows 11 PC, as of 2024-10-09.
|
||||
canonical source on a new Windows 11 PC, as of 2025-10-31.
|
||||
See [](./compile-for-unix.md) for a similar guide for unix-like
|
||||
systems, including MacOS.
|
||||
|
||||
@@ -24,7 +24,8 @@ systems, including MacOS.
|
||||
application to your task bar, as you will use it a lot. Bring up
|
||||
an instance of this command prompt and do all of the subsequent steps
|
||||
in that "x64 Native Tools" command prompt. (Or use "x86" if you want
|
||||
a 32-bit build.) The subsequent steps will not work in a vanilla
|
||||
a 32-bit build. Or use "ARM64" if you want to do a build for Windows
|
||||
on ARM.) The subsequent steps will not work in a vanilla
|
||||
DOS prompt. Nor will they work in PowerShell.
|
||||
|
||||
3. *(Optional):* Install TCL development libraries.
|
||||
@@ -133,9 +134,7 @@ following minor changes:
|
||||
The command the developers use for building the deliverable DLL on the
|
||||
[download page](https://sqlite.org/download.html) is as follows:
|
||||
|
||||
> ~~~~
|
||||
nmake /f Makefile.msc sqlite3.dll USE_NATIVE_LIBPATHS=1 "OPTS=-DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 -DSQLITE_ENABLE_SERIALIZE=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
|
||||
~~~~
|
||||
> nmake /f Makefile.msc sqlite3.dll USE_NATIVE_LIBPATHS=1 "OPTS=-DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 -DSQLITE_ENABLE_SERIALIZE=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
|
||||
|
||||
That command generates both the sqlite3.dll and sqlite3.def files. The same
|
||||
command works for both 32-bit and 64-bit builds.
|
||||
@@ -147,9 +146,7 @@ with TCL in order to function. The [sqlite3_analyzer.exe program](https://sqlit
|
||||
is an example. You can build as described above, and then
|
||||
enter:
|
||||
|
||||
> ~~~~
|
||||
nmake /f Makefile.msc sqlite3_analyzer.exe
|
||||
~~~~
|
||||
> nmake /f Makefile.msc sqlite3_analyzer.exe
|
||||
|
||||
And you will end up with a working executable. However, that executable
|
||||
will depend on having the "tcl98.dll" library somewhere on your %PATH%.
|
||||
@@ -175,17 +172,11 @@ statically linked so that it does not depend on separate DLL:
|
||||
5. CD into your SQLite source code directory and build the desired
|
||||
utility program, but add the following extra argument to the
|
||||
nmake command line:
|
||||
<blockquote><pre>
|
||||
STATICALLY_LINK_TCL=1
|
||||
</pre></blockquote>
|
||||
<blockquote><pre>STATICALLY_LINK_TCL=1</pre></blockquote>
|
||||
<p>So, for example, to build a statically linked version of
|
||||
sqlite3_analyzer.exe, you might type:
|
||||
<blockquote><pre>
|
||||
nmake /f Makefile.msc STATICALLY_LINK_TCL=1 sqlite3_analyzer.exe
|
||||
</pre></blockquote>
|
||||
<blockquote><pre>nmake /f Makefile.msc STATICALLY_LINK_TCL=1 sqlite3_analyzer.exe</pre></blockquote>
|
||||
|
||||
6. After your executable is built, you can verify that it does not
|
||||
depend on the TCL DLL by running:
|
||||
<blockquote><pre>
|
||||
dumpbin /dependents sqlite3_analyzer.exe
|
||||
</pre></blockquote>
|
||||
<blockquote><pre>dumpbin /dependents sqlite3_analyzer.exe</pre></blockquote>
|
||||
|
||||
+22
-7
@@ -695,6 +695,7 @@ other than that, the order of directives in Lemon is arbitrary.</p>
|
||||
<li><tt><a href='#parse_failure'>%parse_failure</a></tt>
|
||||
<li><tt><a href='#pright'>%right</a></tt>
|
||||
<li><tt><a href='#reallc'>%realloc</a></tt>
|
||||
<li><tt><a href='#reallc'>%reallocx</a></tt>
|
||||
<li><tt><a href='#stack_overflow'>%stack_overflow</a></tt>
|
||||
<li><tt><a href='#stack_size'>%stack_size</a></tt>
|
||||
<li><tt><a href='#start_symbol'>%start_symbol</a></tt>
|
||||
@@ -1203,15 +1204,29 @@ the wildcard token and some other token, the other token is always used.
|
||||
The wildcard token is only matched if there are no alternatives.</p>
|
||||
|
||||
<a id='reallc'></a>
|
||||
<h4>4.4.26 The <tt>%realloc</tt> and <tt>%free</tt> directives</h4>
|
||||
<h4>4.4.26 The <tt>%realloc</tt>, <tt>%reallocx</tt>,
|
||||
and <tt>%free</tt> directives</h4>
|
||||
|
||||
<p>The <tt>%realloc</tt> and <tt>%free</tt> directives defines function
|
||||
that allocate and free heap memory. The signatures of these functions
|
||||
should be the same as the realloc() and free() functions from the standard
|
||||
C library.
|
||||
<p>The <tt>%realloc</tt>, <tt>%reallocx</tt>, and <tt>%free</tt>
|
||||
directives defines function that allocate and free heap memory.
|
||||
The signatures of th3 %realloc and %free are the same as
|
||||
realloc() and free() functions from the standard C library.
|
||||
The %reallocx function has the same semantics as %realloc but
|
||||
takes four parameters instead of two:
|
||||
<ol>
|
||||
<li> A pointer to the space to be reallocated, or NULL for a new allocation,
|
||||
<li> The number of elements to allocate,
|
||||
<li> The size of each element,
|
||||
<li> The %extra parameter.
|
||||
</ol>
|
||||
The extra parameters of %reallocx can be used, for example, to monitor
|
||||
the parser stack size and raise an error if it exceeds application-defined
|
||||
limits.
|
||||
If both %reallocx and %realloc are defined, then %reallocx is used
|
||||
and %realloc is ignored.
|
||||
|
||||
<p>If both of these functions are defined
|
||||
then these functions are used to allocate and free
|
||||
<p>If %free is defined and one of %realloc and %reallocx is
|
||||
defined then the functions are used to allocate and free
|
||||
memory for supplemental parser stack space, if the initial
|
||||
parse stack space is exceeded. The initial parser stack size
|
||||
is specified by either <tt>%stack_size</tt> or the
|
||||
|
||||
@@ -160,6 +160,7 @@ static char *intckMprintf(sqlite3_intck *p, const char *zFmt, ...){
|
||||
sqlite3_free(zRet);
|
||||
zRet = 0;
|
||||
}
|
||||
va_end(ap);
|
||||
return zRet;
|
||||
}
|
||||
|
||||
|
||||
+19
-16
@@ -13,11 +13,14 @@ Technical support is available in the forum:
|
||||
<https://sqlite.org/forum>
|
||||
|
||||
|
||||
> **FOREWARNING:** this subproject is very much in development and
|
||||
subject to any number of changes. Please do not rely on any
|
||||
information about its API until this disclaimer is removed. The JNI
|
||||
bindings released with version 3.43 are a "tech preview." Once
|
||||
finalized, strong backward compatibility guarantees will apply.
|
||||
> **FOREWARNING:** the JNI subproject is experimental and subject to
|
||||
any number of changes. This API is "feature-complete", with only a
|
||||
few difficult-to-reach corners of the C API not represented here,
|
||||
but it is not a supported deliverable of the project so does not
|
||||
have same backward compatibility guarantees which the C APIs
|
||||
do. That said: the [C-style API](#1to1ish) is especially resistent
|
||||
to compatibility breakage because it's designed to be as close to
|
||||
the C API as feasible.
|
||||
|
||||
Project goals/requirements:
|
||||
|
||||
@@ -162,11 +165,13 @@ or propagate exceptions and must return error information (if any) via
|
||||
result codes or `null`. The only cases where the C-style APIs may
|
||||
throw is through client-side misuse, e.g. passing in a null where it
|
||||
may cause a `NullPointerException`. The APIs clearly mark function
|
||||
parameters which should not be null, but does not generally actively
|
||||
defend itself against such misuse. Some C-style APIs explicitly accept
|
||||
`null` as a no-op for usability's sake, and some of the JNI APIs
|
||||
deliberately return an error code, instead of segfaulting, when passed
|
||||
a `null`.
|
||||
parameters which should not be null, and it internally uses the
|
||||
`SQLITE_API_ARMOR` mechanism to help product against such misuse. Some
|
||||
C-style APIs explicitly accept `null` as a no-op for usability's sake,
|
||||
and some of the JNI APIs deliberately return an error code, instead of
|
||||
segfaulting, when passed a `null`. There are no known cases where it
|
||||
will misuse memory if passed a `null` or out-of-range value from
|
||||
client code.
|
||||
|
||||
Client-defined callbacks _must never throw exceptions_ unless _very
|
||||
explicitly documented_ as being throw-safe. Exceptions are generally
|
||||
@@ -194,7 +199,8 @@ Some constructs, when modelled 1-to-1 from C to Java, are unduly
|
||||
clumsy to work with in Java because they try to shoehorn C's way of
|
||||
doing certain things into Java's wildly different ways. The following
|
||||
subsections cover those, starting with a verbose explanation and
|
||||
demonstration of where such changes are "really necessary"...
|
||||
demonstration of where such changes are "really necessary" for
|
||||
usability's sake...
|
||||
|
||||
### Custom Collations
|
||||
|
||||
@@ -286,12 +292,9 @@ binding. The Java API has only one core function-registration function:
|
||||
|
||||
```java
|
||||
int sqlite3_create_function(sqlite3 db, String funcName, int nArgs,
|
||||
int encoding, SQLFunction func);
|
||||
int flags, SQLFunction func);
|
||||
```
|
||||
|
||||
> Design question: does the encoding argument serve any purpose in
|
||||
Java? That's as-yet undetermined. If not, it will be removed.
|
||||
|
||||
`SQLFunction` is not used directly, but is instead instantiated via
|
||||
one of its three subclasses:
|
||||
|
||||
@@ -313,4 +316,4 @@ in-flux nature of this API.
|
||||
Various APIs which accept callbacks, e.g. `sqlite3_trace_v2()` and
|
||||
`sqlite3_update_hook()`, use interfaces similar to those shown above.
|
||||
Despite the changes in signature, the JNI layer makes every effort to
|
||||
provide the same semantics as the C API documentation suggests.
|
||||
provide the same semantics as the C API documentation describes.
|
||||
|
||||
+43
-51
@@ -133,11 +133,9 @@
|
||||
** Which sqlite3.c we're using needs to be configurable to enable
|
||||
** building against a custom copy, e.g. the SEE variant. We have to
|
||||
** include sqlite3.c, as opposed to sqlite3.h, in order to get access
|
||||
** to some internal details like SQLITE_MAX_... and friends. This
|
||||
** increases the rebuild time considerably but we need this in order
|
||||
** to access some internal functionality and keep the to-Java-exported
|
||||
** values of SQLITE_MAX_... and SQLITE_LIMIT_... in sync with the C
|
||||
** build.
|
||||
** to some internal details like SQLITE_MAX_... and friends, and keep
|
||||
** those consistent with this build. This increases the rebuild time
|
||||
** considerably, however.
|
||||
*/
|
||||
#ifndef SQLITE_C
|
||||
# define SQLITE_C sqlite3.c
|
||||
@@ -335,7 +333,7 @@ struct S3JniNphOp {
|
||||
const char * const zMember /* Name of member property */;
|
||||
const char * const zTypeSig /* JNI type signature of zMember */;
|
||||
/*
|
||||
** klazz is a global ref to the class represented by pRef.
|
||||
** klazz is a global ref to the class represented by zName.
|
||||
**
|
||||
** According to:
|
||||
**
|
||||
@@ -999,19 +997,20 @@ static S3JniEnv * S3JniEnv__get(JNIEnv * const env){
|
||||
** JNI bindings such as sqlite3_prepare_v2/v3(), and definitely not
|
||||
** from client code.
|
||||
**
|
||||
** Returns err_code.
|
||||
** Returns err_code _unless_ err_code is 0 and sqlite3_set_errmsg()
|
||||
** fails with OOM, in which case it may return SQLITE_OOM or fail
|
||||
** fatally.
|
||||
**
|
||||
** This function predates sqlite3_set_errmsg(), which is why it has a
|
||||
** slightly different interface. Before that function was introduced,
|
||||
** this code used the SQLite-internal APIs to do this.
|
||||
*/
|
||||
static int s3jni_db_error(sqlite3* const db, int err_code,
|
||||
const char * const zMsg){
|
||||
static int s3jni_db_error(JNIEnv * env, sqlite3* const db,
|
||||
int err_code, const char * const zMsg){
|
||||
if( db!=0 ){
|
||||
if( 0==zMsg ){
|
||||
sqlite3Error(db, err_code);
|
||||
}else{
|
||||
const int nMsg = sqlite3Strlen30(zMsg);
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
|
||||
sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
||||
}
|
||||
int const rc = sqlite3_set_errmsg(db, err_code, zMsg);
|
||||
s3jni_oom_fatal(0==rc);
|
||||
if( rc && !err_code ) err_code=rc;
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
@@ -1235,11 +1234,11 @@ static int s3jni__db_exception(JNIEnv * const env, sqlite3 * const pDb,
|
||||
char * zMsg;
|
||||
S3JniExceptionClear;
|
||||
zMsg = s3jni_exception_error_msg(env, ex);
|
||||
s3jni_db_error(pDb, errCode, zMsg ? zMsg : zDfltMsg);
|
||||
s3jni_db_error(env, pDb, errCode, zMsg ? zMsg : zDfltMsg);
|
||||
sqlite3_free(zMsg);
|
||||
S3JniUnrefLocal(ex);
|
||||
}else if( zDfltMsg ){
|
||||
s3jni_db_error(pDb, errCode, zDfltMsg);
|
||||
s3jni_db_error(env, pDb, errCode, zDfltMsg);
|
||||
}
|
||||
return errCode;
|
||||
}
|
||||
@@ -1956,15 +1955,6 @@ static void S3JniUdf_finalizer(void * s){
|
||||
S3JniUdf_free(s3jni_env(), (S3JniUdf*)s, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper for processing args to UDF handlers with signature
|
||||
** (sqlite3_context*,int,sqlite3_value**).
|
||||
*/
|
||||
typedef struct {
|
||||
jobject jcx /* sqlite3_context */;
|
||||
jobjectArray jargv /* sqlite3_value[] */;
|
||||
} udf_jargs;
|
||||
|
||||
/*
|
||||
** Converts the given (cx, argc, argv) into arguments for the given
|
||||
** UDF, writing the result (Java wrappers for cx and argv) in the
|
||||
@@ -2006,7 +1996,7 @@ error_oom:
|
||||
/*
|
||||
** Requires that jCx and jArgv are sqlite3_context
|
||||
** resp. array-of-sqlite3_value values initialized by udf_args(). The
|
||||
** latter will be 0-and-NULL for UDF types with no arguments. This
|
||||
** (argc,argv) are (0,NULL) for UDF types with no arguments. This
|
||||
** function zeroes out the nativePointer member of jCx and each entry
|
||||
** in jArgv. This is a safety-net precaution to avoid undefined
|
||||
** behavior if a Java-side UDF holds a reference to its context or one
|
||||
@@ -2099,19 +2089,19 @@ static int udf_xFSI(sqlite3_context* const pCx, int argc,
|
||||
sqlite3_value** const argv, S3JniUdf * const s,
|
||||
jmethodID xMethodID, const char * const zFuncType){
|
||||
S3JniDeclLocal_env;
|
||||
udf_jargs args = {0,0};
|
||||
int rc = udf_args(env, pCx, argc, argv, &args.jcx, &args.jargv);
|
||||
|
||||
jobject jcx = 0 /* sqlite3_context */;
|
||||
jobjectArray jargv = 0 /* sqlite3_value[] */;
|
||||
int rc = udf_args(env, pCx, argc, argv, &jcx, &jargv);
|
||||
if( 0 == rc ){
|
||||
(*env)->CallVoidMethod(env, s->jObj, xMethodID, args.jcx, args.jargv);
|
||||
(*env)->CallVoidMethod(env, s->jObj, xMethodID, jcx, jargv);
|
||||
S3JniIfThrew{
|
||||
rc = udf_report_exception(env, 'F'==zFuncType[1]/*xFunc*/, pCx,
|
||||
s->zFuncName, zFuncType);
|
||||
}
|
||||
udf_unargs(env, args.jcx, argc, args.jargv);
|
||||
udf_unargs(env, jcx, argc, jargv);
|
||||
}
|
||||
S3JniUnrefLocal(args.jcx);
|
||||
S3JniUnrefLocal(args.jargv);
|
||||
S3JniUnrefLocal(jcx);
|
||||
S3JniUnrefLocal(jargv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3300,7 +3290,7 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
|
||||
S3JniDb_mutex_enter;
|
||||
ps = S3JniDb_from_jlong(jpDb);
|
||||
if( !ps ){
|
||||
s3jni_db_error(ps->pDb, SQLITE_MISUSE, 0);
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_MISUSE, 0);
|
||||
S3JniDb_mutex_leave;
|
||||
return 0;
|
||||
}
|
||||
@@ -3320,13 +3310,14 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
|
||||
else sqlite3_rollback_hook(ps->pDb, 0, 0);
|
||||
}else{
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jHook);
|
||||
jmethodID const xCallback = (*env)->GetMethodID(env, klazz, "call",
|
||||
isCommit ? "()I" : "()V");
|
||||
jmethodID const xCallback =
|
||||
(*env)->GetMethodID(env, klazz, "call",
|
||||
isCommit ? "()I" : "()V");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionReport;
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching call() method in"
|
||||
"hook object.");
|
||||
}else{
|
||||
@@ -3606,7 +3597,7 @@ S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
|
||||
(*env)->GetMethodID(env, klazz, "call", "([B[B)I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew{
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
"Could not get call() method from "
|
||||
"CollationCallback object.");
|
||||
}else{
|
||||
@@ -3645,15 +3636,15 @@ S3JniApi(sqlite3_create_function() sqlite3_create_function_v2()
|
||||
|
||||
if( !pDb || !jFuncName ){
|
||||
return SQLITE_MISUSE;
|
||||
}else if( !encodingTypeIsValid(eTextRep) ){
|
||||
return s3jni_db_error(pDb, SQLITE_FORMAT,
|
||||
}else if( !encodingTypeIsValid(eTextRep & 0x0f) ){
|
||||
return s3jni_db_error(env, pDb, SQLITE_FORMAT,
|
||||
"Invalid function encoding option.");
|
||||
}
|
||||
s = S3JniUdf_alloc(env, jFunctor);
|
||||
if( !s ) return SQLITE_NOMEM;
|
||||
|
||||
if( UDF_UNKNOWN_TYPE==s->type ){
|
||||
rc = s3jni_db_error(pDb, SQLITE_MISUSE,
|
||||
rc = s3jni_db_error(env, pDb, SQLITE_MISUSE,
|
||||
"Cannot unambiguously determine function type.");
|
||||
S3JniUdf_free(env, s, 1);
|
||||
goto error_cleanup;
|
||||
@@ -4012,7 +4003,7 @@ S3JniApi(sqlite3_jni_db_error(), jint, 1jni_1db_1error)(
|
||||
zStr = jStr
|
||||
? s3jni_jstring_to_utf8( jStr, 0)
|
||||
: NULL;
|
||||
rc = s3jni_db_error( ps->pDb, (int)jRc, zStr );
|
||||
rc = s3jni_db_error(env, ps->pDb, (int)jRc, zStr );
|
||||
sqlite3_free(zStr);
|
||||
}
|
||||
return rc;
|
||||
@@ -4321,7 +4312,7 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
|
||||
jTable = jDbName ? s3jni_utf8_to_jstring( zTable, -1) : 0;
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_NOMEM, 0);
|
||||
}else{
|
||||
assert( hook.jObj );
|
||||
assert( hook.midCallback );
|
||||
@@ -4423,7 +4414,7 @@ static jobject s3jni_updatepre_hook(JNIEnv * env, int isPre, jlong jpDb, jobject
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching callback on "
|
||||
"(pre)update hook object.");
|
||||
}else{
|
||||
@@ -4532,7 +4523,7 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching xCallback() on "
|
||||
"ProgressHandler object.");
|
||||
}else{
|
||||
@@ -4906,8 +4897,9 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
|
||||
")I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Error setting up Java parts of authorizer hook.");
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
"Error setting up Java parts of "
|
||||
"authorizer hook.");
|
||||
}else{
|
||||
rc = sqlite3_set_authorizer(ps->pDb, s3jni_xAuth, ps);
|
||||
}
|
||||
@@ -5191,7 +5183,7 @@ S3JniApi(sqlite3_trace_v2(),jint,1trace_1v2)(
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching call() on "
|
||||
"TracerCallback object.");
|
||||
}else{
|
||||
|
||||
@@ -245,8 +245,10 @@ extern "C" {
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_CACHE_USED_SHARED 11L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_CACHE_SPILL
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_CACHE_SPILL 12L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_TEMPBUF_SPILL
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_TEMPBUF_SPILL 13L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_MAX
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_MAX 12L
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_MAX 13L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_UTF8
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_UTF8 1L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_UTF16LE
|
||||
|
||||
@@ -115,8 +115,9 @@ public final class CApi {
|
||||
JNIEnv is not cached, else returns true, but this information is
|
||||
primarily for testing of the JNI bindings and is not information
|
||||
which client-level code can use to make any informed
|
||||
decisions. Its return type and semantics are not considered
|
||||
stable and may change at any time.
|
||||
decisions. The semantics of its return type and value are not
|
||||
considered stable and may change at any time. i.e. act as if it
|
||||
returns null.
|
||||
*/
|
||||
public static native boolean sqlite3_java_uncache_thread();
|
||||
|
||||
@@ -2585,7 +2586,8 @@ public final class CApi {
|
||||
public static final int SQLITE_DBSTATUS_DEFERRED_FKS = 10;
|
||||
public static final int SQLITE_DBSTATUS_CACHE_USED_SHARED = 11;
|
||||
public static final int SQLITE_DBSTATUS_CACHE_SPILL = 12;
|
||||
public static final int SQLITE_DBSTATUS_MAX = 12;
|
||||
public static final int SQLITE_DBSTATUS_TEMPBUF_SPILL = 13;
|
||||
public static final int SQLITE_DBSTATUS_MAX = 13;
|
||||
|
||||
// encodings
|
||||
public static final int SQLITE_UTF8 = 1;
|
||||
|
||||
@@ -815,7 +815,9 @@ public class Tester1 implements Runnable {
|
||||
};
|
||||
|
||||
// Register and use the function...
|
||||
int rc = sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func);
|
||||
int rc = sqlite3_create_function(db, "myfunc", -1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS,
|
||||
func);
|
||||
affirm(0 == rc);
|
||||
affirm(0 == xFuncAccum.value);
|
||||
final sqlite3_stmt stmt = prepare(db, "SELECT myfunc(1,2,3)");
|
||||
|
||||
@@ -171,6 +171,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
public static final int DBSTATUS_DEFERRED_FKS = CApi.SQLITE_DBSTATUS_DEFERRED_FKS;
|
||||
public static final int DBSTATUS_CACHE_USED_SHARED = CApi.SQLITE_DBSTATUS_CACHE_USED_SHARED;
|
||||
public static final int DBSTATUS_CACHE_SPILL = CApi.SQLITE_DBSTATUS_CACHE_SPILL;
|
||||
public static final int DBSTATUS_TEMPBUF_SPILL = CApi.SQLITE_DBSTATUS_TEMPBUF_SPILL;
|
||||
|
||||
// Limits
|
||||
public static final int LIMIT_LENGTH = CApi.SQLITE_LIMIT_LENGTH;
|
||||
|
||||
+5
-5
@@ -514,7 +514,7 @@ struct amatch_cursor {
|
||||
sqlite3_int64 iRowid; /* The rowid of the current word */
|
||||
amatch_langid iLang; /* Use this language ID */
|
||||
amatch_cost rLimit; /* Maximum cost of any term */
|
||||
int nBuf; /* Space allocated for zBuf */
|
||||
sqlite3_int64 nBuf; /* Space allocated for zBuf */
|
||||
int oomErr; /* True following an OOM error */
|
||||
int nWord; /* Number of amatch_word objects */
|
||||
char *zBuf; /* Temp-use buffer space */
|
||||
@@ -1039,7 +1039,7 @@ static void amatchAddWord(
|
||||
nTail = (int)strlen(zWordTail);
|
||||
if( nBase+nTail+3>pCur->nBuf ){
|
||||
pCur->nBuf = nBase+nTail+100;
|
||||
pCur->zBuf = sqlite3_realloc(pCur->zBuf, pCur->nBuf);
|
||||
pCur->zBuf = sqlite3_realloc64(pCur->zBuf, pCur->nBuf);
|
||||
if( pCur->zBuf==0 ){
|
||||
pCur->nBuf = 0;
|
||||
return;
|
||||
@@ -1105,13 +1105,13 @@ static int amatchNext(sqlite3_vtab_cursor *cur){
|
||||
amatch_avl *pNode;
|
||||
int isMatch = 0;
|
||||
amatch_vtab *p = pCur->pVtab;
|
||||
int nWord;
|
||||
sqlite3_int64 nWord;
|
||||
int rc;
|
||||
int i;
|
||||
const char *zW;
|
||||
amatch_rule *pRule;
|
||||
char *zBuf = 0;
|
||||
char nBuf = 0;
|
||||
sqlite3_int64 nBuf = 0;
|
||||
char zNext[8];
|
||||
char zNextIn[8];
|
||||
int nNextIn;
|
||||
@@ -1158,7 +1158,7 @@ static int amatchNext(sqlite3_vtab_cursor *cur){
|
||||
nWord = (int)strlen(pWord->zWord+2);
|
||||
if( nWord+20>nBuf ){
|
||||
nBuf = (char)(nWord+100);
|
||||
zBuf = sqlite3_realloc(zBuf, nBuf);
|
||||
zBuf = sqlite3_realloc64(zBuf, nBuf);
|
||||
if( zBuf==0 ) return SQLITE_NOMEM;
|
||||
}
|
||||
amatchStrcpy(zBuf, pWord->zWord+2);
|
||||
|
||||
+1
-9
@@ -760,7 +760,7 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){
|
||||
pCur->zPath = 0;
|
||||
pLvl->pDir = opendir(pLvl->zDir);
|
||||
if( pLvl->pDir==0 ){
|
||||
fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
|
||||
fsdirSetErrmsg(pCur, "cannot read directory: %s", pLvl->zDir);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -1122,11 +1122,3 @@ int sqlite3_fileio_init(
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
|
||||
/* To allow a standalone DLL, make test_windirent.c use the same
|
||||
* redefined SQLite API calls as the above extension code does.
|
||||
* Just pull in this .c to accomplish this. As a beneficial side
|
||||
* effect, this extension becomes a single translation unit. */
|
||||
# include "test_windirent.c"
|
||||
#endif
|
||||
|
||||
@@ -297,8 +297,9 @@ static const unsigned char sqlite3CtypeMap[256] = {
|
||||
** Return the length (in bytes) of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
*/
|
||||
static int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
int i, c;
|
||||
static sqlite3_int64 sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
sqlite3_int64 i;
|
||||
int c;
|
||||
switch( aiClass[*z] ){ /* Switch on the character-class of the first byte
|
||||
** of the token. See the comment on the CC_ defines
|
||||
** above. */
|
||||
@@ -559,7 +560,7 @@ char *sqlite3_normalize(const char *zSql){
|
||||
int i; /* Next character to read from zSql[] */
|
||||
int j; /* Next slot to fill in on z[] */
|
||||
int tokenType; /* Type of the next token */
|
||||
int n; /* Size of the next token */
|
||||
sqlite3_int64 n; /* Size of the next token */
|
||||
int k; /* Loop counter */
|
||||
|
||||
nSql = strlen(zSql);
|
||||
|
||||
+10
-1
@@ -650,6 +650,15 @@ static void re_free(ReCompiled *pRe){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Version of re_free() that accepts a pointer of type (void*). Required
|
||||
** to satisfy sanitizers when the re_free() function is called via a
|
||||
** function pointer.
|
||||
*/
|
||||
static void re_free_voidptr(void *p){
|
||||
re_free((ReCompiled*)p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compile a textual regular expression in zIn[] into a compiled regular
|
||||
** expression suitable for us by re_match() and return a pointer to the
|
||||
@@ -781,7 +790,7 @@ static void re_sql_func(
|
||||
sqlite3_result_int(context, re_match(pRe, zStr, -1));
|
||||
}
|
||||
if( setAux ){
|
||||
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
|
||||
sqlite3_set_auxdata(context, 0, pRe, re_free_voidptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,325 +0,0 @@
|
||||
/*
|
||||
** 2025-10-20
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
** A simple command-line program for testing the Result-Format or "resfmt"
|
||||
** utility library for SQLite.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "sqlite3.h"
|
||||
#include "resfmt.h"
|
||||
|
||||
#define COUNT(X) (sizeof(X)/sizeof(X[0]))
|
||||
|
||||
/* Report out-of-memory and die if the argument is NULL */
|
||||
static void checkOOM(void *p){
|
||||
if( p==0 ){
|
||||
fprintf(stdout, "out-of-memory\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* A block of memory */
|
||||
typedef struct memblock memblock;
|
||||
struct memblock {
|
||||
memblock *pNext;
|
||||
};
|
||||
|
||||
/* List of all memory to be freed */
|
||||
static memblock *pToFree = 0;
|
||||
|
||||
/* Free all memory at exit */
|
||||
static void tempFreeAll(void){
|
||||
while( pToFree ){
|
||||
memblock *pNext = pToFree->pNext;
|
||||
sqlite3_free(pToFree);
|
||||
pToFree = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory that will be freed all at once by freeall() */
|
||||
static void *tempMalloc(size_t n){
|
||||
memblock *p;
|
||||
if( n>0x10000000 ) checkOOM(0);
|
||||
p = sqlite3_malloc64( n+sizeof(memblock) );
|
||||
checkOOM(p);
|
||||
p->pNext = pToFree;
|
||||
pToFree = p;
|
||||
return (void*)&pToFree[1];
|
||||
}
|
||||
|
||||
/* Make a copy of a string using tempMalloc() */
|
||||
static char *tempStrdup(char *zIn){
|
||||
size_t n;
|
||||
char *z;
|
||||
if( zIn==0 ) zIn = "";
|
||||
n = strlen(zIn);
|
||||
if( n>0x10000000 ) checkOOM(0);
|
||||
z = tempMalloc( n+1 );
|
||||
checkOOM(z);
|
||||
memcpy(z, zIn, n+1);
|
||||
return z;
|
||||
}
|
||||
|
||||
/* Function used for writing to the console */
|
||||
static ssize_t testWriter(void *pContext, const unsigned char *p, size_t n){
|
||||
return fwrite(p,1,n,stdout);
|
||||
}
|
||||
|
||||
/* Render BLOB values as "(%d-byte-blob)". */
|
||||
static char *testBlobRender(void *pNotUsed, sqlite3_value *pVal){
|
||||
if( sqlite3_value_type(pVal)!=SQLITE_BLOB ) return 0;
|
||||
return sqlite3_mprintf("(%d-byte-blob)",sqlite3_value_bytes(pVal));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
char *zSrc;
|
||||
FILE *pSrc;
|
||||
sqlite3_str *pBuf;
|
||||
sqlite3 *db = 0;
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
int lineNum = 0;
|
||||
int bUseWriter = 1;
|
||||
sqlite3_resfmt_spec spec;
|
||||
char zLine[1000];
|
||||
|
||||
if( argc<2 ){
|
||||
zSrc = "<stdin>";
|
||||
pSrc = stdin;
|
||||
}else{
|
||||
zSrc = argv[1];
|
||||
pSrc = fopen(zSrc, "rb");
|
||||
if( pSrc==0 ){
|
||||
fprintf(stderr, "cannot open \"%s\" for reading\n", zSrc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
memset(&spec, 0, sizeof(spec));
|
||||
spec.iVersion = 1;
|
||||
spec.eFormat = RESFMT_List;
|
||||
spec.xWrite = testWriter;
|
||||
pBuf = sqlite3_str_new(0);
|
||||
rc = sqlite3_open(":memory:", &db);
|
||||
if( rc ){
|
||||
fprintf(stderr, "unable to open an in-memory database: %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
exit(1);
|
||||
}
|
||||
while( fgets(zLine, sizeof(zLine), pSrc) ){
|
||||
size_t n = strlen(zLine);
|
||||
lineNum++;
|
||||
while( n>0 && zLine[n-1]>0 && zLine[n-1]<=' ' ) n--;
|
||||
zLine[n] = 0;
|
||||
printf("%s\n", zLine);
|
||||
if( strncmp(zLine, "--open=", 7)==0 ){
|
||||
if( db ) sqlite3_close(db);
|
||||
db = 0;
|
||||
rc = sqlite3_open(&zLine[7], &db);
|
||||
if( rc!=SQLITE_OK ){
|
||||
fprintf(stderr, "%s:%d: cannot open \"%s\": %s\n",
|
||||
zSrc, lineNum, &zLine[7],
|
||||
sqlite3_errmsg(db));
|
||||
exit(1);
|
||||
}
|
||||
}else
|
||||
if( strcmp(zLine, "--go")==0 ){
|
||||
const char *zSql, *zTail;
|
||||
char *zErr = 0;
|
||||
int n;
|
||||
if( db==0 ){
|
||||
fprintf(stderr, "%s:%d: database not open\n", zSrc, lineNum);
|
||||
exit(1);
|
||||
}
|
||||
zSql = sqlite3_str_value(pBuf);
|
||||
pStmt = 0;
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zTail);
|
||||
if( rc || pStmt==0 ){
|
||||
fprintf(stderr, "%s:%d: sqlite3_prepare() fails: %s\n",
|
||||
zSrc, lineNum, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
break;
|
||||
}
|
||||
zSql = sqlite3_sql(pStmt);
|
||||
while( isspace(zSql[0]) ) zSql++;
|
||||
n = (int)strlen(zSql);
|
||||
while( n>0 && isspace(zSql[n-1]) ) n--;
|
||||
if( n>0 ){
|
||||
char *zOut = 0;
|
||||
printf("/* %.*s */\n", n, zSql);
|
||||
if( bUseWriter ){
|
||||
spec.pzOutput = 0;
|
||||
spec.xWrite = testWriter;
|
||||
}else{
|
||||
spec.pzOutput = &zOut;
|
||||
spec.xWrite = 0;
|
||||
}
|
||||
rc = sqlite3_format_query_result(pStmt, &spec, &zErr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
fprintf(stderr, "%s:%d: Error %d: %s\n", zSrc, lineNum,
|
||||
rc, zErr);
|
||||
}else{
|
||||
if( !bUseWriter && zOut ){
|
||||
fputs(zOut, stdout);
|
||||
sqlite3_free(zOut);
|
||||
}
|
||||
}
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
zSql = zTail;
|
||||
}
|
||||
sqlite3_str_reset(pBuf);
|
||||
}else
|
||||
if( strncmp(zLine, "--eFormat=", 10)==0 ){
|
||||
const struct { const char *z; int e; } aFmt[] = {
|
||||
{ "box", RESFMT_Box, },
|
||||
{ "column", RESFMT_Column, },
|
||||
{ "count", RESFMT_Count, },
|
||||
{ "eqp", RESFMT_EQP, },
|
||||
{ "explain", RESFMT_Explain, },
|
||||
{ "html", RESFMT_Html, },
|
||||
{ "insert", RESFMT_Insert, },
|
||||
{ "json", RESFMT_Json, },
|
||||
{ "line", RESFMT_Line, },
|
||||
{ "list", RESFMT_List, },
|
||||
{ "markdown", RESFMT_Markdown, },
|
||||
{ "off", RESFMT_Off, },
|
||||
{ "table", RESFMT_Table, },
|
||||
{ "scanexp", RESFMT_ScanExp, },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<COUNT(aFmt); i++){
|
||||
if( strcmp(aFmt[i].z,&zLine[10])==0 ){
|
||||
spec.eFormat = aFmt[i].e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=COUNT(aFmt) ){
|
||||
sqlite3_str *pMsg = sqlite3_str_new(0);
|
||||
for(i=0; i<COUNT(aFmt); i++){
|
||||
sqlite3_str_appendf(pMsg, " %s", aFmt[i].z);
|
||||
}
|
||||
fprintf(stderr, "%s:%d: no such format: \"%s\"\nChoices: %s\n",
|
||||
zSrc, lineNum, &zLine[10], sqlite3_str_value(pMsg));
|
||||
sqlite3_free(sqlite3_str_finish(pMsg));
|
||||
}
|
||||
}else
|
||||
if( strncmp(zLine, "--eQuote=", 9)==0 ){
|
||||
const struct { const char *z; int e; } aQuote[] = {
|
||||
{ "csv", RESFMT_Q_Csv },
|
||||
{ "html", RESFMT_Q_Html },
|
||||
{ "json", RESFMT_Q_Json },
|
||||
{ "off", RESFMT_Q_Off },
|
||||
{ "sql", RESFMT_Q_Sql },
|
||||
{ "tcl", RESFMT_Q_Tcl },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<COUNT(aQuote); i++){
|
||||
if( strcmp(aQuote[i].z,&zLine[9])==0 ){
|
||||
spec.eQuote = aQuote[i].e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=COUNT(aQuote) ){
|
||||
sqlite3_str *pMsg = sqlite3_str_new(0);
|
||||
for(i=0; i<COUNT(aQuote); i++){
|
||||
sqlite3_str_appendf(pMsg, " %s", aQuote[i].z);
|
||||
}
|
||||
fprintf(stderr, "%s:%d: no such quoting style: \"%s\"\nChoices: %s\n",
|
||||
zSrc, lineNum, &zLine[9], sqlite3_str_value(pMsg));
|
||||
sqlite3_free(sqlite3_str_finish(pMsg));
|
||||
}
|
||||
}else
|
||||
if( strncmp(zLine, "--eBlob=", 8)==0 ){
|
||||
const struct { const char *z; int e; } aBlob[] = {
|
||||
{ "auto", RESFMT_B_Auto },
|
||||
{ "hex", RESFMT_B_Hex },
|
||||
{ "json", RESFMT_B_Json },
|
||||
{ "tcl", RESFMT_B_Tcl },
|
||||
{ "text", RESFMT_B_Text },
|
||||
{ "sql", RESFMT_B_Sql },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<COUNT(aBlob); i++){
|
||||
if( strcmp(aBlob[i].z,&zLine[8])==0 ){
|
||||
spec.eBlob = aBlob[i].e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=COUNT(aBlob) ){
|
||||
sqlite3_str *pMsg = sqlite3_str_new(0);
|
||||
for(i=0; i<COUNT(aBlob); i++){
|
||||
sqlite3_str_appendf(pMsg, " %s", aBlob[i].z);
|
||||
}
|
||||
fprintf(stderr, "%s:%d: no such blob style: \"%s\"\nChoices: %s\n",
|
||||
zSrc, lineNum, &zLine[8], sqlite3_str_value(pMsg));
|
||||
sqlite3_free(sqlite3_str_finish(pMsg));
|
||||
}
|
||||
}else
|
||||
if( strncmp(zLine, "--eEscape=", 10)==0 ){
|
||||
const struct { const char *z; int e; } aEscape[] = {
|
||||
{ "ascii", RESFMT_E_Ascii },
|
||||
{ "off", RESFMT_E_Off },
|
||||
{ "symbol", RESFMT_E_Symbol },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<COUNT(aEscape); i++){
|
||||
if( strcmp(aEscape[i].z,&zLine[10])==0 ){
|
||||
spec.eEscape = aEscape[i].e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=COUNT(aEscape) ){
|
||||
sqlite3_str *pMsg = sqlite3_str_new(0);
|
||||
for(i=0; i<COUNT(aEscape); i++){
|
||||
sqlite3_str_appendf(pMsg, " %s", aEscape[i].z);
|
||||
}
|
||||
fprintf(stderr, "%s:%d: no such escape mode: \"%s\"\nChoices: %s\n",
|
||||
zSrc, lineNum, &zLine[10], sqlite3_str_value(pMsg));
|
||||
sqlite3_free(sqlite3_str_finish(pMsg));
|
||||
}
|
||||
}else
|
||||
if( strncmp(zLine, "--bShowCNames=", 14)==0 ){
|
||||
spec.bShowCNames = atoi(&zLine[14])!=0;
|
||||
}else
|
||||
if( strncmp(zLine, "--zNull=", 8)==0 ){
|
||||
spec.zNull = tempStrdup(&zLine[8]);
|
||||
}else
|
||||
if( strncmp(zLine, "--zColumnSep=", 13)==0 ){
|
||||
spec.zColumnSep = tempStrdup(&zLine[13]);
|
||||
}else
|
||||
if( strncmp(zLine, "--zRowSep=", 10)==0 ){
|
||||
spec.zRowSep = tempStrdup(&zLine[10]);
|
||||
}else
|
||||
if( strcmp(zLine, "--exit")==0 ){
|
||||
break;
|
||||
}else
|
||||
if( strncmp(zLine, "--use-writer=",13)==0 ){
|
||||
bUseWriter = atoi(&zLine[13])!=0;
|
||||
}else
|
||||
if( strncmp(zLine, "--use-render=",13)==0 ){
|
||||
spec.xRender = (atoi(&zLine[13])!=0) ? testBlobRender : 0;
|
||||
}else
|
||||
{
|
||||
if( sqlite3_str_length(pBuf) ) sqlite3_str_append(pBuf, "\n", 1);
|
||||
sqlite3_str_appendall(pBuf, zLine);
|
||||
}
|
||||
}
|
||||
if( db ) sqlite3_close(db);
|
||||
sqlite3_free(sqlite3_str_finish(pBuf));
|
||||
tempFreeAll();
|
||||
if( pSrc!=stdin ) fclose(pSrc);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,510 +0,0 @@
|
||||
/*
|
||||
** 2025-10-20
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
** Implementation of the Result-Format or "resfmt" utility library for SQLite.
|
||||
** See the resfmt.md documentation for additional information.
|
||||
*/
|
||||
#include "resfmt.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Private state information. Subject to change from one release to the
|
||||
** next.
|
||||
*/
|
||||
typedef struct sqlite3_resfmt sqlite3_resfmt;
|
||||
struct sqlite3_resfmt {
|
||||
sqlite3_stmt *pStmt; /* The statement whose output is to be rendered */
|
||||
sqlite3 *db; /* The corresponding database connection */
|
||||
char **pzErr; /* Write error message here, if not NULL */
|
||||
sqlite3_str *pOut; /* Accumulated output */
|
||||
int iErr; /* Error code */
|
||||
int nCol; /* Number of output columns */
|
||||
sqlite3_int64 nRow; /* Number of rows handled so far */
|
||||
sqlite3_resfmt_spec spec; /* Copy of the original spec */
|
||||
};
|
||||
|
||||
/*
|
||||
** Set an error code and error message.
|
||||
*/
|
||||
static void resfmtError(
|
||||
sqlite3_resfmt *p, /* Query result state */
|
||||
int iCode, /* Error code */
|
||||
const char *zFormat, /* Message format (or NULL) */
|
||||
...
|
||||
){
|
||||
p->iErr = iCode;
|
||||
if( p->pzErr!=0 ){
|
||||
sqlite3_free(*p->pzErr);
|
||||
*p->pzErr = 0;
|
||||
if( zFormat ){
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
*p->pzErr = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Out-of-memory error.
|
||||
*/
|
||||
static void resfmtOom(sqlite3_resfmt *p){
|
||||
resfmtError(p, SQLITE_NOMEM, "out of memory");
|
||||
}
|
||||
|
||||
/*
|
||||
** If xWrite is defined, send all content of pOut to xWrite and
|
||||
** reset pOut.
|
||||
*/
|
||||
static void resfmtWrite(sqlite3_resfmt *p){
|
||||
int n;
|
||||
if( p->spec.xWrite && (n = sqlite3_str_length(p->pOut))>0 ){
|
||||
p->spec.xWrite(p->spec.pWriteArg,
|
||||
(const unsigned char*)sqlite3_str_value(p->pOut),
|
||||
(size_t)n);
|
||||
sqlite3_str_reset(p->pOut);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Escape the input string if it is needed and in accordance with
|
||||
** eEscape, which is either RESFMT_E_Ascii or RESFMT_E_Symbol.
|
||||
**
|
||||
** Escaping is needed if the string contains any control characters
|
||||
** other than \t, \n, and \r\n
|
||||
**
|
||||
** If no escaping is needed (the common case) then set *ppOut to NULL
|
||||
** and return 0. If escaping is needed, write the escaped string into
|
||||
** memory obtained from sqlite3_malloc64() and make *ppOut point to that
|
||||
** memory and return 0. If an error occurs, return non-zero.
|
||||
**
|
||||
** The caller is responsible for freeing *ppFree if it is non-NULL in order
|
||||
** to reclaim memory.
|
||||
*/
|
||||
static void resfmtEscape(
|
||||
int eEscape, /* RESFMT_E_Ascii or RESFMT_E_Symbol */
|
||||
sqlite3_str *pStr, /* String to be escaped */
|
||||
int iStart /* Begin escapding on this byte of pStr */
|
||||
){
|
||||
sqlite3_int64 i, j; /* Loop counters */
|
||||
sqlite3_int64 sz; /* Size of the string prior to escaping */
|
||||
sqlite3_int64 nCtrl = 0;/* Number of control characters to escape */
|
||||
unsigned char *zIn; /* Text to be escaped */
|
||||
unsigned char c; /* A single character of the text */
|
||||
unsigned char *zOut; /* Where to write the results */
|
||||
|
||||
/* Find the text to be escaped */
|
||||
zIn = (unsigned char*)sqlite3_str_value(pStr);
|
||||
if( zIn==0 ) return;
|
||||
zIn += iStart;
|
||||
|
||||
/* Count the control characters */
|
||||
for(i=0; (c = zIn[i])!=0; i++){
|
||||
if( c<=0x1f
|
||||
&& c!='\t'
|
||||
&& c!='\n'
|
||||
&& (c!='\r' || zIn[i+1]!='\n')
|
||||
){
|
||||
nCtrl++;
|
||||
}
|
||||
}
|
||||
if( nCtrl==0 ) return; /* Early out if no control characters */
|
||||
|
||||
/* Make space to hold the escapes. Copy the original text to the end
|
||||
** of the available space. */
|
||||
sz = sqlite3_str_length(pStr) - iStart;
|
||||
if( eEscape==RESFMT_E_Symbol ) nCtrl *= 2;
|
||||
sqlite3_str_appendchar(pStr, nCtrl, ' ');
|
||||
zOut = (unsigned char*)sqlite3_str_value(pStr);
|
||||
if( zOut==0 ) return;
|
||||
zOut += iStart;
|
||||
zIn = zOut + nCtrl;
|
||||
memmove(zIn,zOut,sz);
|
||||
|
||||
/* Convert the control characters */
|
||||
for(i=j=0; (c = zIn[i])!=0; i++){
|
||||
if( c>0x1f
|
||||
|| c=='\t'
|
||||
|| c=='\n'
|
||||
|| (c=='\r' && zIn[i+1]=='\n')
|
||||
){
|
||||
continue;
|
||||
}
|
||||
if( i>0 ){
|
||||
memmove(&zOut[j], zIn, i);
|
||||
j += i;
|
||||
}
|
||||
zIn += i+1;
|
||||
i = -1;
|
||||
if( eEscape==RESFMT_E_Symbol ){
|
||||
zOut[j++] = 0xe2;
|
||||
zOut[j++] = 0x90;
|
||||
zOut[j++] = 0x80+c;
|
||||
}else{
|
||||
zOut[j++] = '^';
|
||||
zOut[j++] = 0x40+c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If a field contains any character identified by a 1 in the following
|
||||
** array, then the string must be quoted for CSV.
|
||||
*/
|
||||
static const char resfmtCsvQuote[] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
/*
|
||||
** Encode text appropriately and append it to p->pOut.
|
||||
*/
|
||||
static void resfmtEncodeText(sqlite3_resfmt *p, const char *zTxt){
|
||||
int iStart = sqlite3_str_length(p->pOut);
|
||||
switch( p->spec.eQuote ){
|
||||
case RESFMT_Q_Sql: {
|
||||
sqlite3_str_appendf(p->pOut, "%Q", zTxt);
|
||||
break;
|
||||
}
|
||||
case RESFMT_Q_Csv: {
|
||||
unsigned int i;
|
||||
for(i=0; zTxt[i]; i++){
|
||||
if( resfmtCsvQuote[((const unsigned char*)zTxt)[i]] ){
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i==0 || strstr(zTxt, p->spec.zColumnSep)!=0 ){
|
||||
sqlite3_str_appendf(p->pOut, "\"%w\"", zTxt);
|
||||
}else{
|
||||
sqlite3_str_appendall(p->pOut, zTxt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESFMT_Q_Html: {
|
||||
const unsigned char *z = (const unsigned char*)zTxt;
|
||||
while( *z ){
|
||||
unsigned int i = 0;
|
||||
unsigned char c;
|
||||
while( (c=z[i])>'>'
|
||||
|| (c && c!='<' && c!='>' && c!='&' && c!='\"' && c!='\'')
|
||||
){
|
||||
i++;
|
||||
}
|
||||
if( i>0 ){
|
||||
sqlite3_str_append(p->pOut, (const char*)z, i);
|
||||
}
|
||||
switch( z[i] ){
|
||||
case '>': sqlite3_str_append(p->pOut, "<", 4); break;
|
||||
case '&': sqlite3_str_append(p->pOut, "&", 5); break;
|
||||
case '<': sqlite3_str_append(p->pOut, "<", 4); break;
|
||||
case '"': sqlite3_str_append(p->pOut, """, 6); break;
|
||||
case '\'': sqlite3_str_append(p->pOut, "'", 5); break;
|
||||
default: i--;
|
||||
}
|
||||
z += i + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESFMT_Q_Tcl:
|
||||
case RESFMT_Q_Json: {
|
||||
const unsigned char *z = (const unsigned char*)zTxt;
|
||||
sqlite3_str_append(p->pOut, "\"", 1);
|
||||
while( *z ){
|
||||
unsigned int i;
|
||||
for(i=0; z[i]>=0x20 && z[i]!='\\' && z[i]!='"'; i++){}
|
||||
if( i>0 ){
|
||||
sqlite3_str_append(p->pOut, (const char*)z, i);
|
||||
}
|
||||
switch( z[i] ){
|
||||
case '"': sqlite3_str_append(p->pOut, "\\\"", 2); break;
|
||||
case '\\': sqlite3_str_append(p->pOut, "\\\\", 2); break;
|
||||
case '\b': sqlite3_str_append(p->pOut, "\\b", 2); break;
|
||||
case '\f': sqlite3_str_append(p->pOut, "\\f", 2); break;
|
||||
case '\n': sqlite3_str_append(p->pOut, "\\n", 2); break;
|
||||
case '\r': sqlite3_str_append(p->pOut, "\\r", 2); break;
|
||||
case '\t': sqlite3_str_append(p->pOut, "\\t", 2); break;
|
||||
default: {
|
||||
if( p->spec.eQuote==RESFMT_Q_Json ){
|
||||
sqlite3_str_appendf(p->pOut, "\\u%04x", z[i]);
|
||||
}else{
|
||||
sqlite3_str_appendf(p->pOut, "\\%03o", z[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
z += i + 1;
|
||||
}
|
||||
sqlite3_str_append(p->pOut, "\"", 1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sqlite3_str_appendall(p->pOut, zTxt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( p->spec.eEscape!=RESFMT_E_Off ){
|
||||
resfmtEscape(p->spec.eEscape, p->pOut, iStart);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Render value pVal into p->pOut
|
||||
*/
|
||||
static void resfmtRenderValue(sqlite3_resfmt *p, int iCol){
|
||||
if( p->spec.xRender ){
|
||||
sqlite3_value *pVal;
|
||||
char *z;
|
||||
pVal = sqlite3_value_dup(sqlite3_column_value(p->pStmt,iCol));
|
||||
z = p->spec.xRender(p->spec.pRenderArg, pVal);
|
||||
sqlite3_value_free(pVal);
|
||||
if( z ){
|
||||
sqlite3_str_appendall(p->pOut, z);
|
||||
sqlite3_free(z);
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch( sqlite3_column_type(p->pStmt,iCol) ){
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_str_appendf(p->pOut, "%lld", sqlite3_column_int64(p->pStmt,iCol));
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
if( p->spec.zFloatFmt ){
|
||||
double r = sqlite3_column_double(p->pStmt,iCol);
|
||||
sqlite3_str_appendf(p->pOut, p->spec.zFloatFmt, r);
|
||||
}else{
|
||||
const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
|
||||
sqlite3_str_appendall(p->pOut, zTxt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
switch( p->spec.eBlob ){
|
||||
case RESFMT_B_Hex:
|
||||
case RESFMT_B_Sql: {
|
||||
int iStart;
|
||||
int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
|
||||
int i, j;
|
||||
char *zVal;
|
||||
const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol);
|
||||
if( p->spec.eBlob==RESFMT_B_Sql ){
|
||||
sqlite3_str_append(p->pOut, "x'", 2);
|
||||
}
|
||||
iStart = sqlite3_str_length(p->pOut);
|
||||
sqlite3_str_appendchar(p->pOut, nBlob, ' ');
|
||||
sqlite3_str_appendchar(p->pOut, nBlob, ' ');
|
||||
if( p->spec.eBlob==RESFMT_B_Sql ){
|
||||
sqlite3_str_appendchar(p->pOut, 1, '\'');
|
||||
}
|
||||
if( sqlite3_str_errcode(p->pOut) ) return;
|
||||
zVal = sqlite3_str_value(p->pOut);
|
||||
for(i=0, j=iStart; i<nBlob; i++, j+=2){
|
||||
unsigned char c = a[i];
|
||||
zVal[j] = "0123456789abcdef"[(c>>4)&0xf];
|
||||
zVal[j+1] = "0123456789abcdef"[(c)&0xf];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESFMT_B_Tcl:
|
||||
case RESFMT_B_Json: {
|
||||
int iStart;
|
||||
int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
|
||||
int i, j;
|
||||
char *zVal;
|
||||
const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol);
|
||||
int szC = p->spec.eBlob==RESFMT_B_Json ? 6 : 4;
|
||||
sqlite3_str_append(p->pOut, "\"", 1);
|
||||
iStart = sqlite3_str_length(p->pOut);
|
||||
for(i=szC; i>0; i--){
|
||||
sqlite3_str_appendchar(p->pOut, nBlob, ' ');
|
||||
}
|
||||
sqlite3_str_appendchar(p->pOut, 1, '"');
|
||||
if( sqlite3_str_errcode(p->pOut) ) return;
|
||||
zVal = sqlite3_str_value(p->pOut);
|
||||
for(i=0, j=iStart; i<nBlob; i++, j+=szC){
|
||||
unsigned char c = a[i];
|
||||
zVal[j] = '\\';
|
||||
if( szC==4 ){
|
||||
zVal[j+1] = '0' + ((c>>6)&3);
|
||||
zVal[j+2] = '0' + ((c>>3)&7);
|
||||
zVal[j+3] = '0' + (c&7);
|
||||
}else{
|
||||
zVal[j+1] = 'u';
|
||||
zVal[j+2] = '0';
|
||||
zVal[j+3] = '0';
|
||||
zVal[j+4] = "0123456789abcdef"[(c>>4)&0xf];
|
||||
zVal[j+5] = "0123456789abcdef"[(c)&0xf];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
|
||||
resfmtEncodeText(p, zTxt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_NULL: {
|
||||
sqlite3_str_appendall(p->pOut, p->spec.zNull);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
|
||||
resfmtEncodeText(p, zTxt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the internal sqlite3_resfmt object.
|
||||
*/
|
||||
static void resfmtInitialize(
|
||||
sqlite3_resfmt *p, /* State object to be initialized */
|
||||
sqlite3_stmt *pStmt, /* Query whose output to be formatted */
|
||||
const sqlite3_resfmt_spec *pSpec, /* Format specification */
|
||||
char **pzErr /* Write errors here */
|
||||
){
|
||||
size_t sz; /* Size of pSpec[], based on pSpec->iVersion */
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->pzErr = pzErr;
|
||||
if( pSpec->iVersion!=1 ){
|
||||
resfmtError(p, SQLITE_ERROR,
|
||||
"unusable sqlite3_resfmt_spec.iVersion (%d)",
|
||||
pSpec->iVersion);
|
||||
return;
|
||||
}
|
||||
p->pStmt = pStmt;
|
||||
p->db = sqlite3_db_handle(pStmt);
|
||||
p->pOut = sqlite3_str_new(p->db);
|
||||
if( p->pOut==0 ){
|
||||
resfmtOom(p);
|
||||
return;
|
||||
}
|
||||
p->iErr = 0;
|
||||
p->nCol = sqlite3_column_count(p->pStmt);
|
||||
p->nRow = 0;
|
||||
sz = sizeof(sqlite3_resfmt_spec);
|
||||
memcpy(&p->spec, pSpec, sz);
|
||||
if( p->spec.zNull==0 ) p->spec.zNull = "";
|
||||
if( p->spec.eBlob==RESFMT_B_Auto ){
|
||||
switch( p->spec.eQuote ){
|
||||
case RESFMT_Q_Sql: p->spec.eBlob = RESFMT_B_Sql; break;
|
||||
case RESFMT_Q_Csv: p->spec.eBlob = RESFMT_B_Tcl; break;
|
||||
case RESFMT_Q_Tcl: p->spec.eBlob = RESFMT_B_Tcl; break;
|
||||
case RESFMT_Q_Json: p->spec.eBlob = RESFMT_B_Json; break;
|
||||
default: p->spec.eBlob = RESFMT_B_Text; break;
|
||||
}
|
||||
}
|
||||
switch( p->spec.eFormat ){
|
||||
case RESFMT_List: {
|
||||
if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = "|";
|
||||
if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Render a single row of output.
|
||||
*/
|
||||
static void resfmtDoOneRow(sqlite3_resfmt *p){
|
||||
int i;
|
||||
switch( p->spec.eFormat ){
|
||||
case RESFMT_Off:
|
||||
case RESFMT_Count: {
|
||||
/* No-op */
|
||||
break;
|
||||
}
|
||||
default: { /* RESFMT_List */
|
||||
if( p->nRow==0 && p->spec.bShowCNames ){
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zCName = sqlite3_column_name(p->pStmt, i);
|
||||
if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
|
||||
resfmtEncodeText(p, zCName);
|
||||
}
|
||||
sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
|
||||
resfmtWrite(p);
|
||||
}
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
|
||||
resfmtRenderValue(p, i);
|
||||
}
|
||||
sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
|
||||
resfmtWrite(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->nRow++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Finish rendering the results
|
||||
*/
|
||||
static void resfmtFinalize(sqlite3_resfmt *p){
|
||||
switch( p->spec.eFormat ){
|
||||
case RESFMT_Count: {
|
||||
sqlite3_str_appendf(p->pOut, "%lld\n", p->nRow);
|
||||
resfmtWrite(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( p->spec.pzOutput ){
|
||||
*p->spec.pzOutput = sqlite3_str_finish(p->pOut);
|
||||
}else if( p->pOut ){
|
||||
sqlite3_free(sqlite3_str_finish(p->pOut));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run the prepared statement pStmt and format the results according
|
||||
** to the specification provided in pSpec. Return an error code.
|
||||
** If pzErr is not NULL and if an error occurs, write an error message
|
||||
** into *pzErr.
|
||||
*/
|
||||
int sqlite3_format_query_result(
|
||||
sqlite3_stmt *pStmt, /* Statement to evaluate */
|
||||
const sqlite3_resfmt_spec *pSpec, /* Format specification */
|
||||
char **pzErr /* Write error message here */
|
||||
){
|
||||
sqlite3_resfmt fmt; /* The new sqlite3_resfmt being created */
|
||||
|
||||
if( pStmt==0 ) return SQLITE_OK; /* No-op */
|
||||
if( pSpec==0 ) return SQLITE_MISUSE;
|
||||
resfmtInitialize(&fmt, pStmt, pSpec, pzErr);
|
||||
while( fmt.iErr==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
resfmtDoOneRow(&fmt);
|
||||
}
|
||||
if( fmt.iErr==SQLITE_OK ){
|
||||
int rc = sqlite3_reset(fmt.pStmt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
resfmtError(&fmt, rc, "%s", sqlite3_errmsg(fmt.db));
|
||||
}
|
||||
}
|
||||
resfmtFinalize(&fmt);
|
||||
return fmt.iErr;
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
** 2025-10-20
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
** Header file for the Result-Format or "resfmt" utility library for SQLite.
|
||||
** See the resfmt.md documentation for additional information.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** Specification used by clients to define the output format they want
|
||||
*/
|
||||
typedef struct sqlite3_resfmt_spec sqlite3_resfmt_spec;
|
||||
struct sqlite3_resfmt_spec {
|
||||
unsigned char iVersion; /* Version number of this structure */
|
||||
unsigned char eFormat; /* Output format */
|
||||
unsigned char bShowCNames; /* True to show column names */
|
||||
unsigned char eEscape; /* How to deal with control characters */
|
||||
unsigned char eQuote; /* Quoting style for text */
|
||||
unsigned char eBlob; /* Quoting style for BLOBs */
|
||||
unsigned char bWordWrap; /* Try to wrap on word boundaries */
|
||||
short int mxWidth; /* Maximum width of any column */
|
||||
int nWidth; /* Number of column width parameters */
|
||||
short int *aWidth; /* Column widths */
|
||||
const char *zColumnSep; /* Alternative column separator */
|
||||
const char *zRowSep; /* Alternative row separator */
|
||||
const char *zTableName; /* Output table name */
|
||||
const char *zNull; /* Rendering of NULL */
|
||||
const char *zFloatFmt; /* printf-style string for rendering floats */
|
||||
char *(*xRender)(void*,sqlite3_value*); /* Render a value */
|
||||
ssize_t (*xWrite)(void*,const unsigned char*,size_t); /* Write callback */
|
||||
void *pRenderArg; /* First argument to the xRender callback */
|
||||
void *pWriteArg; /* First argument to the xWrite callback */
|
||||
char **pzOutput; /* Storage location for output string */
|
||||
/* Additional fields may be added in the future */
|
||||
};
|
||||
|
||||
/*
|
||||
** Interfaces
|
||||
*/
|
||||
int sqlite3_format_query_result(
|
||||
sqlite3_stmt *pStmt, /* SQL statement to run */
|
||||
const sqlite3_resfmt_spec *pSpec, /* Result format specification */
|
||||
char **pzErr /* OUT: Write error message here */
|
||||
);
|
||||
|
||||
/*
|
||||
** Output styles:
|
||||
*/
|
||||
#define RESFMT_List 0 /* One record per line with a separator */
|
||||
#define RESFMT_Line 1 /* One column per line. */
|
||||
#define RESFMT_Html 2 /* Generate an XHTML table */
|
||||
#define RESFMT_Json 3 /* Output is a list of JSON objects */
|
||||
#define RESFMT_Insert 4 /* Generate SQL "insert" statements */
|
||||
#define RESFMT_Explain 5 /* EXPLAIN output */
|
||||
#define RESFMT_ScanExp 6 /* EXPLAIN output with vm stats */
|
||||
#define RESFMT_EQP 7 /* Converts EXPLAIN QUERY PLAN output into a graph */
|
||||
#define RESFMT_Markdown 8 /* Markdown formatting */
|
||||
#define RESFMT_Column 9 /* One record per line in neat columns */
|
||||
#define RESFMT_Table 10 /* MySQL-style table formatting */
|
||||
#define RESFMT_Box 11 /* Unicode box-drawing characters */
|
||||
#define RESFMT_Count 12 /* Output only a count of the rows of output */
|
||||
#define RESFMT_Off 13 /* No query output shown */
|
||||
|
||||
/*
|
||||
** Quoting styles for text.
|
||||
** Allowed values for sqlite3_resfmt_spec.eQuote
|
||||
*/
|
||||
#define RESFMT_Q_Off 0 /* Literal text */
|
||||
#define RESFMT_Q_Sql 1 /* Quote as an SQL literal */
|
||||
#define RESFMT_Q_Csv 2 /* CSV-style quoting */
|
||||
#define RESFMT_Q_Html 3 /* HTML-style quoting */
|
||||
#define RESFMT_Q_Tcl 4 /* C/Tcl quoting */
|
||||
#define RESFMT_Q_Json 5 /* JSON quoting */
|
||||
|
||||
/*
|
||||
** Quoting styles for BLOBs
|
||||
** Allowed values for sqlite3_resfmt_spec.eBlob
|
||||
*/
|
||||
#define RESFMT_B_Auto 0 /* Determine BLOB quoting using eQuote */
|
||||
#define RESFMT_B_Text 1 /* Display content exactly as it is */
|
||||
#define RESFMT_B_Sql 2 /* Quote as an SQL literal */
|
||||
#define RESFMT_B_Hex 3 /* Hexadecimal representation */
|
||||
#define RESFMT_B_Tcl 4 /* "\000" notation */
|
||||
#define RESFMT_B_Json 5 /* A JSON string */
|
||||
|
||||
/*
|
||||
** Control-character escape modes.
|
||||
** Allowed values for sqlite3_resfmt_spec.eEscape
|
||||
*/
|
||||
#define RESFMT_E_Off 0 /* Do not escape control characters */
|
||||
#define RESFMT_E_Ascii 1 /* Unix-style escapes. Ex: U+0007 shows ^G */
|
||||
#define RESFMT_E_Symbol 2 /* Unicode escapes. Ex: U+0007 shows U+2407 */
|
||||
@@ -1,293 +0,0 @@
|
||||
# SQLite Result Formatting Subsystem
|
||||
|
||||
The "resfmt" subsystem is a set of C-language subroutines that work
|
||||
together to format the output from an SQLite query. The output format
|
||||
is configurable. The application can request CSV, or a table, or
|
||||
any of several other formats, according to needs.
|
||||
|
||||
## 1.0 Overview Of Operation
|
||||
|
||||
Suppose `pStmt` is a pointer to an SQLite prepared statement
|
||||
(a pointer to an `sqlite3_stmt` object) that has been reset and
|
||||
bound and is ready to run. Then to format the output from this
|
||||
prepared statement, use code similar to the following:
|
||||
|
||||
> ~~~
|
||||
sqlite3_resfmt_spec spec; /* Formatter spec */
|
||||
sqlite3_resfmt *pFmt; /* Formatter object */
|
||||
int errCode; /* Error code */
|
||||
char *zErrMsg; /* Text error message (optional) */
|
||||
|
||||
memset(&spec, 0, sizeof(spec));
|
||||
// Additional spec initialization here
|
||||
pFmt = sqlite3_resfmt_begin(pStmt, &spec);
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
sqlite3_resfmt_row(pFmt, pStmt);
|
||||
}
|
||||
sqlite3_resfmt_finish(pFmt, &errCode, &zErrMsg);
|
||||
// Do something with errcode and zErrMsg
|
||||
sqlite3_free(zErrMsg);
|
||||
~~~
|
||||
|
||||
The `sqlite3_resfmt_spec` structure (defined below) describes the desired
|
||||
output format. The `pFmt` variable is a pointer to an opaque sqlite3_resfmt
|
||||
object that maintains the statement of the formatter.
|
||||
The pFmt object is used as the first parameter to two other
|
||||
routines, `sqlite3_resfmt_row()` and `sqlite3_resfmt_finish()`, and
|
||||
is not usable for any other purpose by the caller. The
|
||||
`sqlite3_resfmt_finish()` interface serves as a destructor for
|
||||
the pFmt object.
|
||||
|
||||
## 2.0 The `sqlite3_resfmt_spec` object
|
||||
|
||||
A pointer to an instance of the following structure is the second
|
||||
parameter to the `sqlite3_resfmt_begin()` interface. This structure
|
||||
defines how the rules of the statement are to be formatted.
|
||||
|
||||
> ~~~
|
||||
typedef struct sqlite3_resfmt_spec sqlite3_resfmt_spec;
|
||||
struct sqlite3_resfmt_spec {
|
||||
int iVersion; /* Version number of this structure */
|
||||
int eFormat; /* Output format */
|
||||
unsigned char bShowCNames; /* True to show column names */
|
||||
unsigned char eEscMode; /* How to deal with control characters */
|
||||
unsigned char bQuote; /* Quote output values as SQL literals */
|
||||
unsigned char bWordWrap; /* Try to wrap on word boundaries */
|
||||
int mxWidth; /* Maximum column width in columnar modes */
|
||||
const char *zColumnSep; /* Alternative column separator */
|
||||
const char *zRowSep; /* Alternative row separator */
|
||||
const char *zTableName; /* Output table name */
|
||||
const char *zNull; /* Rendering of NULL */
|
||||
const char *zFloatFmt; /* printf-style string for rendering floats */
|
||||
int nWidth; /* Number of column width parameters */
|
||||
short int *aWidth; /* Column widths */
|
||||
char *(*xRender)(void*,sqlite3_value*); /* Render a value */
|
||||
ssize_t (*xWrite)(void*,const unsigned char*,ssize_t); /* Write callback */
|
||||
void *pRenderArg; /* First argument to the xRender callback */
|
||||
void *pWriteArg; /* First argument to the xWrite callback */
|
||||
char **pzOutput; /* Storage location for output string */
|
||||
/* Additional fields may be added in the future */
|
||||
};
|
||||
~~~
|
||||
|
||||
The sqlite3_resfmt_spec object must be fully initialized prior
|
||||
to calling `sqlite3_resfmt_begin()` and its value must not change
|
||||
by the application until after the corresponding call to
|
||||
`sqlite3_resfmt_finish()`. Note that the result formatter itself
|
||||
might change values in the sqlite3_resfmt_spec object as it runs.
|
||||
But the application should not try to change or use any fields of
|
||||
the sqlite3_resfmt_spec object while the formatter is running.
|
||||
|
||||
### 2.1 Structure Version Number
|
||||
|
||||
The sqlite3_resfmt_spec.iVersion field must be 1. Future enhancements to this
|
||||
subsystem might add new fields onto the bottom of the sqlite3_resfmt_spec
|
||||
object. Those new fields will only be accessible if the iVersion is greater
|
||||
than 1. Thus the iVersion field is used to support upgradability.
|
||||
|
||||
### 2.2 Output Deposition
|
||||
|
||||
The formatted output can either be sent to a callback function
|
||||
or accumulated into an output buffer in memory obtained
|
||||
from system malloc(). If the sqlite3_resfmt_spec.xWrite column is not NULL,
|
||||
then that function is invoked (using sqlite3_resfmt_spec.xWriteArg as its
|
||||
first argument) to transmit the formatted output. Or, if
|
||||
sqlite3_resfmt_spec.pzOutput points to a pointer to a character, then that
|
||||
pointer is made to point to memory obtained from malloc() that
|
||||
contains the complete text of the formatted output.
|
||||
|
||||
When `sqlite3_resfmt_begin()` is called,
|
||||
one of sqlite3_resfmt_spec.xWrite and sqlite3_resfmt_spec.pzOutput must be
|
||||
non-NULL and the other must be NULL.
|
||||
|
||||
Output might be generated row by row, on each call to
|
||||
`sqlite3_resfmt_row()` or it might be written all at once
|
||||
on the final call to `sqlite3_resfmt_finish()`, depending
|
||||
on the output format.
|
||||
|
||||
### 2.3 Output Format
|
||||
|
||||
The sqlite3_resfmt_spec.eFormat field is an integer code that defines the
|
||||
specific output format that will be generated. See the
|
||||
output format describes below for additional detail.
|
||||
|
||||
### 2.4 Show Column Names
|
||||
|
||||
The sqlite3_resfmt_spec.bShowCNames field is a boolean. If true, then column
|
||||
names appear in the output. If false, column names are omitted.
|
||||
|
||||
### 2.5 Control Character Escapes
|
||||
|
||||
The sqlite3_resfmt_spec.eEscMode determines how ASCII control characters are
|
||||
formatted in the output. If this value is zero, then the control character
|
||||
with value X is displayed as ^Y where Y is X+0x40. Hence, a
|
||||
backspace character (U+0008) is shown as "^H". This is the default.
|
||||
If eEscMode is one, then control characters in the range of U+0001
|
||||
through U+001f are mapped into U+2401 through U+241f, respectively.
|
||||
If eEscMode is 2, then control characters are output directly, with
|
||||
no translation.
|
||||
|
||||
The TAB (U+0009), LF (U+000a) and CR-LF (U+000d,U+000a) character
|
||||
sequence are always output literally and are not mapped to alternative
|
||||
display values, regardless of this setting.
|
||||
|
||||
### 2.6 Render output as SQL literals
|
||||
|
||||
If the sqlite3_resfmt_spec.bQuote field is non-zero (true), then outputs
|
||||
are rendered as SQL literal values. String are written within `'...'`
|
||||
with appropriate escapes. BLOBs are of the form `x'...'`. NULL values
|
||||
come out as "NULL".
|
||||
|
||||
### 2.7 Word Wrapping In Columnar Modes
|
||||
|
||||
For output modes that attempt to display equal-width columns, the
|
||||
sqlite3_resfmt_spec.bWordWrap boolean determines whether long values
|
||||
are broken at word boundaries, or at arbitrary characters. The
|
||||
sqlite3_resfmt_spec.mxWidth determines the maximum width of an output column.
|
||||
|
||||
### 2.8 Row and Column Separator Strings
|
||||
|
||||
The sqlite3_resfmt_spec.zColumnSep and sqlite3_resfmt_spec.zRowSep strings
|
||||
are alternative column and row separator character sequences. If not
|
||||
specified (if these pointers are left as NULL) then appropriate defaults
|
||||
are used.
|
||||
|
||||
### 2.9 The Output Table Name
|
||||
|
||||
The sqlite3_resfmt_spec.zTableName value is the name of the output table
|
||||
when the MODE_Insert output mode is used.
|
||||
|
||||
### 2.10 The Rendering Of NULL
|
||||
|
||||
If a value is NULL and sqlite3_resfmt_spec.xRender() does not exist
|
||||
or declines to provide a rendering, then show the NULL using the string
|
||||
found in sqlite3_resfmt_spec.zNull. If zNull is itself a NULL pointer
|
||||
then NULL values are rendered as an empty string.
|
||||
|
||||
### 2.11 Floating Point Value Format
|
||||
|
||||
If a value is a floating-point number other than Infinity or NaN, then
|
||||
the value is rendered using the printf-style format given by the
|
||||
sqlite3_resfmt_spec.zFloatFmt string.
|
||||
|
||||
### 2.12 Column Widths And Alignments
|
||||
|
||||
The sqlite3_resfmt_spec.aWidth[] array, if specified, is an array of
|
||||
16-bit signed integers that specify the minimum column width and
|
||||
the alignment for all columns in columnar output modes. Negative
|
||||
values mean right-justify. The
|
||||
absolute value is the minimum of the corresponding column.
|
||||
These widths are deliberately stored in a 16-bit signed integer
|
||||
as no good can come from having column widths greater than 32767.
|
||||
|
||||
The sqlite3_resfmt_spec.nWidth field is the number of values in the aWidth[]
|
||||
array. Any column beyond the nWidth-th column are assumed to have
|
||||
a minimum width of 0.
|
||||
|
||||
### 2.13 Optional Value Rendering Callback
|
||||
|
||||
If the sqlite3_resfmt_spec.xRender field is not NULL, then each rendered
|
||||
sqlite3_value is first passed to the xRender function, giving it
|
||||
an opportunity to render the results. If xRender chooses to render,
|
||||
it should write the rendering into memory obtained from sqlite3_malloc()
|
||||
and return a pointer to that memory. The xRender function can decline
|
||||
to render (for example, based on the sqlite3_value_type() or other
|
||||
characteristics of the value) in which case it can simply return a
|
||||
NULL pointer and the usual default rendering will be used instead.
|
||||
|
||||
The result rendering subsystem will take responsibility for the
|
||||
returned string and will pass the returned string to sqlite3_free()
|
||||
when it has finished with it.
|
||||
|
||||
The bQuote and eEscMode settings above become no-ops if the xRender
|
||||
routine returns non-NULL. In other words, the application-supplied
|
||||
xRender routine is expected to do its own bQuote and eEscMode processing
|
||||
if it chooses to render values.
|
||||
|
||||
## 3.0 The `sqlite3_resfmt_begin()` Interface
|
||||
|
||||
Invoke the `sqlite3_resfmt_begin(P,S)` interface to begin formatting
|
||||
the output of prepared statement P using format specification S.
|
||||
This routine returns a pointer to an opaque sqlite3_resfmt object that is
|
||||
the current state of the formatter. The `sqlite3_resfmt_finish()`
|
||||
routine is the destructor for the sqlite3_resfmt object and must be called
|
||||
to prevent a memory leak.
|
||||
|
||||
If an out-of-memory fault occurs while allocating space for the
|
||||
sqlite3_resfmt object, then `sqlite3_resfmt_begin()` will return a NULL
|
||||
pointer. The application need not check for this case as the
|
||||
other routines that use a pointer to the sqlite3_resfmt object all
|
||||
interpret a NULL parameter in place of the sqlite3_resfmt pointer as
|
||||
a harmless no-op.
|
||||
|
||||
## 4.0 The `sqlite3_resfmt_step()` Interface
|
||||
|
||||
Invoke the `sqlite3_resfmt_step(F)` interface for each row
|
||||
in the prepared statement that is to be output.
|
||||
|
||||
The formatter might choose to output some content as each row
|
||||
is processed, or it might accumulate the output and send it all
|
||||
at once when `sqlite3_resfmt_finish()` is called. This is at
|
||||
the discretion of the output formatter. Generally, rows are
|
||||
output one-by-one on each call to `sqlite3_resfmt_row()` when the
|
||||
output format is such that the row can be computed without knowing
|
||||
the value of subsequence, such as in CSV output mode, and
|
||||
the output is accumulated and sent all at once in columnar output
|
||||
modes where the complete output content is needed to compute column
|
||||
widths.
|
||||
|
||||
### 5.0 The `sqlite3_resfmt_finish()` Interface
|
||||
|
||||
Invoke the `sqlite3_resfmt_finish(F,C,E)` interface to finish
|
||||
the formatting. C is an optional pointer to an integer. If C
|
||||
is not a NULL pointer, then any error code associated with the
|
||||
formatting operation is written into *C. E is an optional pointer
|
||||
to a human-readable text error message. If E is not a NULL pointer,
|
||||
then an error message held in memory obtained from sqlite3_malloc()
|
||||
is written into *E. It is the responsibility of the calling
|
||||
application to invoke sqlite3_free() on this error message to
|
||||
reclaim the space.
|
||||
|
||||
If the F argument to `sqlite3_resfmt_finish(F,C,E)` is a NULL pointer,
|
||||
then this interface is a harmless no-op.
|
||||
|
||||
### 6.0 Output Modes
|
||||
|
||||
The result formatter supports a variety of output modes. The
|
||||
set of supported output modes might increase in future versions.
|
||||
The following output modes are currently defined:
|
||||
|
||||
> ~~~
|
||||
#define RESFMT_Line 0 /* One column per line. */
|
||||
#define RESFMT_Column 1 /* One record per line in neat columns */
|
||||
#define RESFMT_List 2 /* One record per line with a separator */
|
||||
#define RESFMT_Html 3 /* Generate an XHTML table */
|
||||
#define RESFMT_Insert 4 /* Generate SQL "insert" statements */
|
||||
#define RESFMT_Tcl 5 /* Generate ANSI-C or TCL quoted elements */
|
||||
#define RESFMT_Csv 6 /* Quote strings, numbers are plain */
|
||||
#define RESFMT_Explain 7 /* Like RESFMT_Column, but do not truncate data */
|
||||
#define RESFMT_Pretty 8 /* Pretty-print schemas */
|
||||
#define RESFMT_EQP 9 /* Converts EXPLAIN QUERY PLAN output into a graph */
|
||||
#define RESFMT_Json 10 /* Output JSON */
|
||||
#define RESFMT_Markdown 11 /* Markdown formatting */
|
||||
#define RESFMT_Table 12 /* MySQL-style table formatting */
|
||||
#define RESFMT_Box 13 /* Unicode box-drawing characters */
|
||||
#define RESFMT_Count 14 /* Output only a count of the rows of output */
|
||||
#define RESFMT_Off 15 /* No query output shown */
|
||||
#define RESFMT_ScanExp 16 /* Like RESFMT_Explain, but for ".scanstats vm" */
|
||||
#define RESFMT_Www 17 /* Full web-page output */
|
||||
~~~
|
||||
|
||||
Additional detail about the meaning of each of these output modes
|
||||
is pending.
|
||||
|
||||
### 7.0 Source Code Files
|
||||
|
||||
The SQLite result formatter is implemented in three source code files:
|
||||
|
||||
* `resfmt.c` → The implementation, written in portable C99
|
||||
* `resfmt.h` → A header file defining interfaces
|
||||
* `resfmt.md` → This documentation, in Markdown
|
||||
|
||||
To use the SQLite result formatter, include the "`resfmt.h`" header file
|
||||
and link the application against the "`resfmt.c`" source file.
|
||||
@@ -206,6 +206,10 @@ static int vtablogConnectCreate(
|
||||
}
|
||||
if( zSchema==0 ){
|
||||
zSchema = sqlite3_mprintf("%s","CREATE TABLE x(a,b);");
|
||||
if( zSchema==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto vtablog_end_connect;
|
||||
}
|
||||
}
|
||||
printf(" schema = '%s'\n", zSchema);
|
||||
rc = sqlite3_declare_vtab(db, zSchema);
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
#else
|
||||
#include "sqlite3.h"
|
||||
#endif
|
||||
int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
|
||||
sqlite3_int64 sqlite3GetToken(const unsigned char*,int*); /* In SQLite core */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
_fiddle_db_arg
|
||||
_fiddle_db_filename
|
||||
_fiddle_exec
|
||||
_fiddle_experiment
|
||||
_fiddle_interrupt
|
||||
_fiddle_main
|
||||
_fiddle_reset_db
|
||||
_fiddle_db_handle
|
||||
_fiddle_db_vfs
|
||||
_fiddle_export_db
|
||||
+220
-171
@@ -1,5 +1,6 @@
|
||||
#######################################################################
|
||||
# This GNU makefile creates the canonical sqlite3 WASM builds.
|
||||
#
|
||||
# This GNU makefile creates the canonical sqlite3 WASM builds. Plus some
|
||||
# others.
|
||||
#
|
||||
# This build assumes a Linux platform and is not intended for
|
||||
# general-purpose client-level use, except for creating builds with
|
||||
@@ -10,28 +11,33 @@
|
||||
#
|
||||
# default, all = build in dev mode
|
||||
#
|
||||
# o0, o1, o2, o3, os, oz = full clean/rebuild with the -Ox level indicated
|
||||
# by the target name. Rebuild is necessary for all components to get
|
||||
# the desired optimization level.
|
||||
# o0, o1, o2, o3, os, oz = full clean/rebuild with the -Ox level
|
||||
# indicated by the target name. A clean rebuild is necessary for
|
||||
# all components to get the desired optimization level.
|
||||
#
|
||||
# dist = create end user deliverables. Add dist.build=oX to build
|
||||
# with a specific optimization level, where oX is one of the
|
||||
# above-listed o? or qo? target names.
|
||||
# with a specific optimization level, where oX is one of the
|
||||
# above-listed o? target names.
|
||||
#
|
||||
# snapshot = like dist, but uses a zip file name which clearly
|
||||
# marks it as a prerelease/snapshot build.
|
||||
# marks it as a prerelease/snapshot build.
|
||||
#
|
||||
# clean = clean up
|
||||
#
|
||||
# Required tools beyond those needed for the canonical builds:
|
||||
#
|
||||
# - Emscripten SDK: https://emscripten.org/docs/getting_started/downloads.html
|
||||
#
|
||||
# - The bash shell
|
||||
#
|
||||
# - GNU make, GNU sed, GNU awk, GNU grep (all in the $PATH and without
|
||||
# a "g" prefix like they have on some non-GNU systems)
|
||||
# - wasm-strip for release builds: https://github.com/WebAssembly/wabt
|
||||
#
|
||||
# - wasm-strip for release builds: https://github.com/WebAssembly/wabt.
|
||||
# It will build without this but the .wasm files will be huge.
|
||||
#
|
||||
# - InfoZip for 'dist' zip file
|
||||
########################################################################
|
||||
#
|
||||
default: all
|
||||
MAKEFILE = $(lastword $(MAKEFILE_LIST))
|
||||
CLEAN_FILES =
|
||||
@@ -213,9 +219,8 @@ b.cp = $(call b.mkdir@); \
|
||||
# $4 = optional $(bin.c-pp) flags
|
||||
define b.c-pp.shcmd
|
||||
$(call b.mkdir@); \
|
||||
$(call b.echo,$(1),$(emo.disk)$(emo.lock) $(bin.c-pp) $(4) $(if $(loud.if),$(2))); \
|
||||
rm -f $(3); \
|
||||
$(bin.c-pp) -o $(3) $(4) $(2) || exit; \
|
||||
$(call b.echo,$(1),$(emo.disk)$(emo.lock)[$(3)] $(4)); \
|
||||
rm -f $(3); $(bin.c-pp) -o $(3) $(4) $(2) || exit; \
|
||||
chmod -w $(3)
|
||||
endef
|
||||
|
||||
@@ -227,10 +232,38 @@ endef
|
||||
# Args: as for $(b.c-pp.shcmd).
|
||||
define b.c-pp.target
|
||||
$(3): $$(MAKEFILE_LIST) $$(bin.c-pp) $(2)
|
||||
@$$(call b.c-pp.shcmd,$(1),$(2),$(3),$(4))
|
||||
@$$(call b.mkdir@)
|
||||
@$$(call b.c-pp.shcmd,$(1),$(2),$(3),$(4) $$(b.c-pp.target.flags))
|
||||
CLEAN_FILES += $(3)
|
||||
endef
|
||||
|
||||
|
||||
#
|
||||
# The various -D... values used by *.c-pp.js include:
|
||||
#
|
||||
# -Dtarget:es6-module: for all ESM module builds
|
||||
#
|
||||
# -Dtarget:node: for node.js builds
|
||||
#
|
||||
# -Dtarget:es6-module -Dtarget:es6-bundler-friendly: intended for
|
||||
# "bundler-friendly" ESM module build. These have some restrictions
|
||||
# on how URL() objects are constructed in some contexts: URLs which
|
||||
# refer to files which are part of this project must be referenced
|
||||
# as string literals so that bundlers' static-analysis tools can
|
||||
# find those files and include them in their bundles.
|
||||
#
|
||||
# -Dtarget:es6-module -Dtarget:node: is intended for use by node.js
|
||||
# for node.js, as opposed to by node.js on behalf of a
|
||||
# browser. Mixing -sENVIRONMENT=web and -sENVIRONMENT=node leads to
|
||||
# ambiguity and confusion on node's part, as it's unable to
|
||||
# reliably determine whether the target is a browser or node.
|
||||
#
|
||||
# To repeat: all node.js builds are 100% untested and unsupported.
|
||||
#
|
||||
# Most c-pp.D.X are set via $(bin.mkwb) and X is a build name.
|
||||
# Those make rules reference c-pp.D.64bit, so it should be defined in
|
||||
# advance.
|
||||
#
|
||||
c-pp.D.64bit = -Dbits64
|
||||
|
||||
#
|
||||
@@ -248,39 +281,21 @@ c-pp.D.64bit = -Dbits64
|
||||
#
|
||||
# This is intended to be used in makefile targets which generate an
|
||||
# Emscripten module and where $@ is the module's .js/.mjs file.
|
||||
#
|
||||
# This is inherently fragile and has been broken by Emscripten updates
|
||||
# before.
|
||||
#
|
||||
ifeq (1,1)
|
||||
define b.strip-js-emcc-bindings
|
||||
echo "$(1) $(emo.garbage) Stripping export wrappers."; \
|
||||
sed -i -e '/var _sqlite3.*makeInvalidEarly.*;/d' \
|
||||
-e '/assert.*sqlite3.*missing.*;/d' \
|
||||
-e '/_sqlite.*createExportWrapper.*;/d' $@
|
||||
endef
|
||||
else
|
||||
b.strip-js-emcc-bindings = \
|
||||
sed -i -e '/^.*= \(_sqlite3\|_fiddle\)[^=]*=.*createExportWrapper/d' \
|
||||
-e '/^var \(_sqlite3\|_fiddle\)[^=]*=.*makeInvalidEarlyAccess/d' $@ || exit; \
|
||||
echo '$(1) $(emo.garbage) (Probably) /createExportWrapper()/d and /makeInvalidEarlyAccess()/d'
|
||||
|
||||
|
||||
#
|
||||
# bin.version-info = binary to output various sqlite3 version info for
|
||||
# embedding in the JS files and in building the distribution zip file.
|
||||
# It must NOT be in $(dir.tmp) because we need it to survive the
|
||||
# cleanup process for the dist build to work properly.
|
||||
#
|
||||
# Slight caveat: this uses the version info from the in-tree
|
||||
# sqlite3.c/h, which may diff from a user-provided $(sqlite3.c). The
|
||||
# end result is that the generated JS files may have static version
|
||||
# info from $(bin.version-info) which differ from their runtime-emitted
|
||||
# version info (e.g. from sqlite3_libversion()).
|
||||
bin.version-info = $(dir.top)/version-info
|
||||
$(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
|
||||
$(MAKE) -C $(dir.top) version-info
|
||||
t-version-info: $(bin.version-info)
|
||||
#
|
||||
# bin.stripcomments is used for stripping C/C++-style comments from JS
|
||||
# files. The JS files contain large chunks of documentation which we
|
||||
# don't need for all builds. That app's -k flag is of particular
|
||||
# importance here, as it allows us to retain the opening comment
|
||||
# block(s), which contain the license header and version info.
|
||||
bin.stripccomments = $(dir.tool)/stripccomments
|
||||
$(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
|
||||
$(CC) -o $@ $<
|
||||
t-stripccomments: $(bin.stripccomments)
|
||||
DISTCLEAN_FILES += $(bin.stripccomments)
|
||||
|
||||
echo '$(1) $(emo.bug) (disabled because it breaks emsdk 4.0.16+)'
|
||||
endif
|
||||
|
||||
#
|
||||
# Set up sqlite3.c and sqlite3.h...
|
||||
@@ -299,9 +314,35 @@ DISTCLEAN_FILES += $(bin.stripccomments)
|
||||
# $(sqlite3.canonical.c) must point to the sqlite3.c in
|
||||
# the sqlite3 canonical source tree, as that source file
|
||||
# is required for certain utility and test code.
|
||||
#
|
||||
sqlite3.canonical.c = $(dir.top)/sqlite3.c
|
||||
sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c))
|
||||
sqlite3.h = $(dir.top)/sqlite3.h
|
||||
sqlite3.h = $(dir $(sqlite3.c))/sqlite3.h
|
||||
|
||||
#
|
||||
# bin.version-info = binary to output various sqlite3 version info for
|
||||
# embedding in the JS files and in building the distribution zip file.
|
||||
# It must NOT be in $(dir.tmp) because we need it to survive the
|
||||
# cleanup process for the dist build to work properly.
|
||||
#
|
||||
bin.version-info = ./version-info
|
||||
$(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
|
||||
$(CC) -o $@ -I$(dir $(sqlite3.h)) $(dir.tool)/version-info.c
|
||||
t-version-info: $(bin.version-info)
|
||||
DISTCLEAN_FILES += $(bin.version-info)
|
||||
|
||||
#
|
||||
# bin.stripcomments is used for stripping C/C++-style comments from JS
|
||||
# files. The JS files contain large chunks of documentation which we
|
||||
# don't need for all builds. That app's -k flag is of particular
|
||||
# importance here, as it allows us to retain the opening comment
|
||||
# block(s), which contain the license header and version info.
|
||||
#
|
||||
bin.stripccomments = $(dir.tool)/stripccomments
|
||||
$(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
|
||||
$(CC) -o $@ $<
|
||||
t-stripccomments: $(bin.stripccomments)
|
||||
DISTCLEAN_FILES += $(bin.stripccomments)
|
||||
|
||||
ifeq (1,$(MAKING_CLEAN))
|
||||
SQLITE_C_IS_SEE = 0
|
||||
@@ -314,7 +355,6 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# barebones=1 disables all "extraneous" stuff from sqlite3-wasm.c, the
|
||||
# goal being to create a WASM file with only the core APIs.
|
||||
@@ -331,7 +371,7 @@ endif
|
||||
# undefine barebones # relatively new gmake feature, not ubiquitous
|
||||
|
||||
#
|
||||
# It's important that sqlite3.h be built to completion before any
|
||||
# It's important that sqlite3.[ch] be built to completion before any
|
||||
# other parts of the build run, thus we use .NOTPARALLEL to disable
|
||||
# parallel build of that file and its dependants. However, that makes
|
||||
# the whole build non-parallelizable because everything has a dep on
|
||||
@@ -348,8 +388,10 @@ $(sqlite3.h):
|
||||
# $(MAKE) -C $(dir.top) sqlite3.c
|
||||
$(sqlite3.c): $(sqlite3.h)
|
||||
|
||||
#
|
||||
# Common options for building sqlite3-wasm.c and speedtest1.c.
|
||||
# Explicit ENABLEs...
|
||||
#
|
||||
SQLITE_OPT.common = \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_TEMP_STORE=2 \
|
||||
@@ -366,11 +408,15 @@ SQLITE_OPT.common = \
|
||||
# removing them from this list will serve only to break the speedtest1
|
||||
# builds.
|
||||
|
||||
#
|
||||
# Currently always needed but TODO is paring tester1.c-pp.js down
|
||||
# to be able to run without this:
|
||||
#
|
||||
SQLITE_OPT.common += -DSQLITE_WASM_ENABLE_C_TESTS
|
||||
|
||||
#
|
||||
# Extra flags for full-featured builds...
|
||||
#
|
||||
SQLITE_OPT.full-featured = \
|
||||
-DSQLITE_ENABLE_BYTECODE_VTAB \
|
||||
-DSQLITE_ENABLE_DBPAGE_VTAB \
|
||||
@@ -427,13 +473,14 @@ else
|
||||
# -DSQLITE_OMIT_WINDOWFUNC
|
||||
endif
|
||||
|
||||
#
|
||||
#SQLITE_OPT += -DSQLITE_DEBUG
|
||||
# Enabling SQLITE_DEBUG will break sqlite3_wasm_vfs_create_file()
|
||||
# (and thus sqlite3_js_vfs_create_file()). Those functions are
|
||||
# deprecated and alternatives are in place, but this crash behavior
|
||||
# can be used to find errant uses of sqlite3_js_vfs_create_file()
|
||||
# in client code.
|
||||
########################################################################
|
||||
#
|
||||
# The following flags are hard-coded into sqlite3-wasm.c and cannot be
|
||||
# modified via the build process:
|
||||
#
|
||||
@@ -442,10 +489,9 @@ endif
|
||||
# SQLITE_OMIT_DEPRECATED
|
||||
# SQLITE_OMIT_UTF16
|
||||
# SQLITE_OMIT_SHARED_CACHE
|
||||
########################################################################
|
||||
#
|
||||
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Adding custom C code via sqlite3_wasm_extra_init.c:
|
||||
#
|
||||
# If the canonical build process finds the file
|
||||
@@ -466,7 +512,7 @@ endif
|
||||
# make sqlite3_wasm_extra_init.c=my_custom_stuff.c
|
||||
#
|
||||
# See example_extra_init.c for an example implementation.
|
||||
########################################################################
|
||||
#
|
||||
sqlite3_wasm_extra_init.c ?= $(wildcard sqlite3_wasm_extra_init.c)
|
||||
cflags.wasm_extra_init =
|
||||
ifneq (,$(sqlite3_wasm_extra_init.c))
|
||||
@@ -487,7 +533,7 @@ endif
|
||||
#
|
||||
WASM_CUSTOM_INSTANTIATE = 1
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# $(bin.c-pp): a minimal text file preprocessor. Like C's but much
|
||||
# less so.
|
||||
#
|
||||
@@ -518,6 +564,7 @@ WASM_CUSTOM_INSTANTIATE = 1
|
||||
#
|
||||
# -D... flags which should be included in all invocations should be
|
||||
# appended to $(b.c-pp.target.flags).
|
||||
#
|
||||
bin.c-pp = ./c-pp-lite
|
||||
$(bin.c-pp): c-pp-lite.c $(sqlite3.c) $(MAKEFILE)
|
||||
$(CC) -O0 -o $@ c-pp-lite.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top) \
|
||||
@@ -529,7 +576,12 @@ b.c-pp.target.flags ?=
|
||||
ifeq (1,$(SQLITE_C_IS_SEE))
|
||||
b.c-pp.target.flags += -Denable-see
|
||||
endif
|
||||
api.oo1 ?= 1
|
||||
ifeq (0,$(api.oo1))
|
||||
b.c-pp.target.flags += -Domit-oo1
|
||||
endif
|
||||
|
||||
#
|
||||
# cflags.common = C compiler flags for all builds
|
||||
cflags.common = -I. -I$(dir $(sqlite3.c)) -std=c99 -fPIC
|
||||
# emcc.WASM_BIGINT = 1 for BigInt (C int64) support, else 0. The API
|
||||
@@ -537,13 +589,14 @@ cflags.common = -I. -I$(dir $(sqlite3.c)) -std=c99 -fPIC
|
||||
# _are not tested_ on any regular basis.
|
||||
emcc.WASM_BIGINT ?= 1
|
||||
emcc.MEMORY64 ?= 0
|
||||
########################################################################
|
||||
#
|
||||
# https://emscripten.org/docs/tools_reference/settings_reference.html#memory64
|
||||
#
|
||||
# 64-bit build requires wasm-strip 1.0.36 (maybe 1.0.35, but not
|
||||
# 1.0.34) or will fail to strip with "tables may not be 64-bit".
|
||||
########################################################################
|
||||
#
|
||||
|
||||
#
|
||||
# emcc_opt = optimization-related flags. These are primarily used by
|
||||
# the various oX targets. build times for -O levels higher than 0 are
|
||||
# painful at dev-time.
|
||||
@@ -555,14 +608,17 @@ emcc.MEMORY64 ?= 0
|
||||
# -O2 (which consistently creates the fastest-running deliverables).
|
||||
# Build time suffers greatly compared to -O0, which is why -O0 is the
|
||||
# default.
|
||||
#
|
||||
ifeq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
|
||||
emcc_opt ?= -O0
|
||||
else
|
||||
emcc_opt ?= -Oz
|
||||
endif
|
||||
|
||||
#
|
||||
# When passing emcc_opt from the CLI, += and re-assignment have no
|
||||
# effect, so emcc_opt+=-g3 doesn't work. So...
|
||||
#
|
||||
emcc_opt_full = $(emcc_opt) -g3
|
||||
# ^^^ ALWAYS use -g3. See below for why.
|
||||
#
|
||||
@@ -589,26 +645,26 @@ emcc_opt_full = $(emcc_opt) -g3
|
||||
# Much practice has demonstrated that -O2 consistently gives the best
|
||||
# runtime speeds, but not by a large enough factor to rule out use of
|
||||
# -Oz when smaller deliverable size is a priority.
|
||||
########################################################################
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# EXPORTED_FUNCTIONS.* = files for use with Emscripten's
|
||||
# -sEXPORTED_FUNCTION flag.
|
||||
EXPORTED_FUNCTIONS.api.core = $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core
|
||||
EXPORTED_FUNCTIONS.api.in = $(EXPORTED_FUNCTIONS.api.core)
|
||||
ifeq (1,$(SQLITE_C_IS_SEE))
|
||||
EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see
|
||||
endif
|
||||
ifeq (0,$(wasm-bare-bones))
|
||||
EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras
|
||||
endif
|
||||
#
|
||||
EXPORTED_FUNCTIONS.api.in = $(dir.api)/EXPORTED_FUNCTIONS.c-pp
|
||||
EXPORTED_FUNCTIONS.api = $(dir.tmp)/EXPORTED_FUNCTIONS.api
|
||||
$(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE)
|
||||
@$(call b.mkdir@)
|
||||
cat $(EXPORTED_FUNCTIONS.api.in) > $@
|
||||
EXPORTED_FUNCTIONS.c-pp.flags =
|
||||
ifeq (1,$(wasm-bare-bones))
|
||||
EXPORTED_FUNCTIONS.c-pp.flags += -Dbare-bones
|
||||
endif
|
||||
$(eval $(call b.c-pp.target,filter,\
|
||||
$(EXPORTED_FUNCTIONS.api.in),\
|
||||
$(EXPORTED_FUNCTIONS.api),\
|
||||
$(EXPORTED_FUNCTIONS.c-pp.flags)))
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# emcc flags for .c/.o/.wasm/.js.
|
||||
#
|
||||
emcc.flags =
|
||||
ifeq (1,$(emcc.verbose))
|
||||
emcc.flags += -v
|
||||
@@ -696,9 +752,9 @@ ifeq (,$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY)))
|
||||
$(error emcc.INITIAL_MEMORY must be one of: 4, 8, 16, 32, 64, 96, 128 (megabytes))
|
||||
endif
|
||||
emcc.jsflags += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
|
||||
#
|
||||
# /INITIAL_MEMORY
|
||||
########################################################################
|
||||
#emcc.jsflags += -sMEMORY64=$(emcc.MEMORY64)
|
||||
#
|
||||
|
||||
emcc.jsflags += $(emcc.environment)
|
||||
emcc.jsflags += -sSTACK_SIZE=512KB
|
||||
@@ -707,7 +763,8 @@ emcc.jsflags += -sSTACK_SIZE=512KB
|
||||
# VFS, which requires twice that for its xRead() and xWrite() methods.
|
||||
# 2023-03: those methods have since been adapted to use a malloc()'d
|
||||
# buffer.
|
||||
########################################################################
|
||||
|
||||
#
|
||||
# $(sqlite3.js.init-func) is the name Emscripten assigns our exported
|
||||
# module init/load function. This symbol name is hard-coded in
|
||||
# $(extern-post-js.js) as well as in numerous docs.
|
||||
@@ -747,7 +804,7 @@ emcc.jsflags += -sLLD_REPORT_UNDEFINED
|
||||
#emcc.jsflags += --experimental-pic --unresolved-symbols=ingore-all --import-undefined
|
||||
#emcc.jsflags += --unresolved-symbols=ignore-all
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# -sSINGLE_FILE:
|
||||
# https://github.com/emscripten-core/emscripten/blob/main/src/settings.js
|
||||
#
|
||||
@@ -756,12 +813,7 @@ emcc.jsflags += -sLLD_REPORT_UNDEFINED
|
||||
# cannot wasm-strip the binary before it gets encoded into the JS
|
||||
# file. The result is that the generated JS file is, because of the
|
||||
# -g3 debugging info, _huge_.
|
||||
########################################################################
|
||||
|
||||
|
||||
sqlite3.wasm = $(dir.dout)/sqlite3.wasm
|
||||
sqlite3-wasm.c = $(dir.api)/sqlite3-wasm.c
|
||||
sqlite3-wasm.c.in = $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
|
||||
#
|
||||
|
||||
#
|
||||
# b.call.patch-export-default is used by mkwasmbuilds.c and the
|
||||
@@ -804,51 +856,6 @@ if [ x1 = x$(1) ]; then \
|
||||
fi
|
||||
endef
|
||||
|
||||
#
|
||||
# The various -D... values used by *.c-pp.js include:
|
||||
#
|
||||
# -Dtarget:es6-module: for all ESM module builds
|
||||
#
|
||||
# -Dtarget:node: for node.js builds
|
||||
#
|
||||
# -Dtarget:es6-module -Dtarget:es6-bundler-friendly: intended for
|
||||
# "bundler-friendly" ESM module build. These have some restrictions
|
||||
# on how URL() objects are constructed in some contexts: URLs which
|
||||
# refer to files which are part of this project must be referenced
|
||||
# as string literals so that bundlers' static-analysis tools can
|
||||
# find those files and include them in their bundles.
|
||||
#
|
||||
# -Dtarget:es6-module -Dtarget:node: is intended for use by node.js
|
||||
# for node.js, as opposed to by node.js on behalf of a
|
||||
# browser. Mixing -sENVIRONMENT=web and -sENVIRONMENT=node leads to
|
||||
# ambiguity and confusion on node's part, as it's unable to
|
||||
# reliably determine whether the target is a browser or node.
|
||||
#
|
||||
# To repeat: all node.js builds are 100% untested and unsupported.
|
||||
#
|
||||
########################################################################
|
||||
|
||||
#
|
||||
# Inputs/outputs for the sqlite3-api.js family.
|
||||
#
|
||||
# sqlite3-api.jses = the list of JS files which make up
|
||||
# sqlite3-api.js, in the order they need to be assembled.
|
||||
sqlite3-api.jses = $(sqlite3-license-version.js)
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-prologue.js
|
||||
sqlite3-api.jses += $(dir.common)/whwasmutil.js
|
||||
sqlite3-api.jses += $(dir.jacc)/jaccwabyt.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-glue.c-pp.js
|
||||
sqlite3-api.jses += $(sqlite3-api-build-version.js)
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.c-pp.js
|
||||
ifeq (0,$(wasm-bare-bones))
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vtab-helper.c-pp.js
|
||||
endif
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
|
||||
|
||||
#
|
||||
# $(sqlite3-license-version.js) contains the license header and
|
||||
# in-comment build version info.
|
||||
@@ -858,9 +865,8 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
|
||||
#
|
||||
sqlite3-license-version.js = $(dir.tmp)/sqlite3-license-version.js
|
||||
$(sqlite3-license-version.js): $(bin.version-info) \
|
||||
$(dir.api)/sqlite3-license-version-header.js
|
||||
@echo '$(logtag.@) $(emo.disk)'; { \
|
||||
$(call b.mkdir@); \
|
||||
$(dir.api)/sqlite3-license-version-header.js $(MAKEFILE)
|
||||
@$(call b.mkdir@); echo '$(logtag.@) $(emo.disk)'; { \
|
||||
cat $(dir.api)/sqlite3-license-version-header.js || exit $$?; \
|
||||
echo '/*'; \
|
||||
echo '** This code was built from sqlite3 version...'; \
|
||||
@@ -868,7 +874,7 @@ $(sqlite3-license-version.js): $(bin.version-info) \
|
||||
awk '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
awk '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
echo '**'; echo '** Emscripten SDK: $(emcc.version)'; \
|
||||
echo '**'; \
|
||||
echo '**'; echo '** Preprocessed by:'; echo '** @c-pp::ARGV@'; \
|
||||
echo '*/'; \
|
||||
} > $@
|
||||
|
||||
@@ -887,6 +893,33 @@ $(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE)
|
||||
echo '});'; \
|
||||
} > $@
|
||||
|
||||
#
|
||||
# Inputs/outputs for the sqlite3-api.js family.
|
||||
#
|
||||
# sqlite3-api.jses = the list of JS files which make up
|
||||
# sqlite3-api.js, in the order they need to be assembled.
|
||||
sqlite3-api.jses = $(sqlite3-license-version.js)
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-prologue.js
|
||||
sqlite3-api.jses += $(sqlite3-api-build-version.js)
|
||||
sqlite3-api.jses += $(dir.common)/whwasmutil.js
|
||||
sqlite3-api.jses += $(dir.jacc)/jaccwabyt.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-glue.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.c-pp.js
|
||||
ifeq (0,$(wasm-bare-bones))
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vtab-helper.c-pp.js
|
||||
endif
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
|
||||
|
||||
# Parallel builds can fail if $(sqlite3-license-version.js) is not
|
||||
# created early enough, so make all files in $(sqlite-api.jses) except
|
||||
# for $(sqlite3-license-version.js) depend on
|
||||
# $(sqlite3-license-version.js).
|
||||
deps.jses = $(filter-out $(sqlite3-license-version.js),$(sqlite3-api.jses))
|
||||
$(deps.jses): $(sqlite3-license-version.js)
|
||||
|
||||
#
|
||||
# extern-post-js* and extern-pre-js* are files for use with
|
||||
# Emscripten's --extern-pre-js and --extern-post-js flags.
|
||||
@@ -924,7 +957,7 @@ $(post-js.in.js): $(MKDIR.bld) $(post-jses.js) $(MAKEFILE)
|
||||
done > $@
|
||||
|
||||
#
|
||||
# speedtest1 decls needed before the $(bin.mkws)-generated makefile
|
||||
# speedtest1 decls needed before the $(bin.mkwb)-generated makefile
|
||||
# is included.
|
||||
#
|
||||
bin.speedtest1 = ../../speedtest1
|
||||
@@ -964,9 +997,10 @@ endif
|
||||
########################################################################
|
||||
|
||||
EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
|
||||
$(EXPORTED_FUNCTIONS.fiddle): $(fiddle.EXPORTED_FUNCTIONS.in) $(MAKEFILE_LIST)
|
||||
@$(b.mkdir@)
|
||||
@sort -u $(fiddle.EXPORTED_FUNCTIONS.in) > $@
|
||||
$(EXPORTED_FUNCTIONS.fiddle): $(EXPORTED_FUNCTIONS.api.in) $(MAKEFILE_LIST)
|
||||
@$(call b.mkdir@)
|
||||
@$(call b.c-pp.shcmd,filter,$(EXPORTED_FUNCTIONS.api.in),\
|
||||
$@,$(EXPORTED_FUNCTIONS.c-pp.flags) -Dfiddle)
|
||||
@echo $(logtag.@) $(emo.disk)
|
||||
|
||||
emcc.flags.fiddle = \
|
||||
@@ -999,7 +1033,7 @@ clean-fiddle:
|
||||
$(dir.fiddle)/*.wasm \
|
||||
$(dir.fiddle)/sqlite3-opfs-*.js \
|
||||
$(dir.fiddle)/*.gz \
|
||||
EXPORTED_FUNCTIONS.fiddle
|
||||
$(EXPORTED_FUNCTIONS.fiddle)
|
||||
rm -fr $(dir.fiddle-debug)
|
||||
|
||||
emcc.flags.fiddle.debug = $(emcc.flags.fiddle) \
|
||||
@@ -1007,11 +1041,6 @@ emcc.flags.fiddle.debug = $(emcc.flags.fiddle) \
|
||||
-DSQLITE_ENABLE_SELECTTRACE \
|
||||
-DSQLITE_ENABLE_WHERETRACE
|
||||
|
||||
fiddle.EXPORTED_FUNCTIONS.in = \
|
||||
EXPORTED_FUNCTIONS.fiddle.in \
|
||||
$(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core \
|
||||
$(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras
|
||||
|
||||
fiddle.c.in = $(dir.top)/shell.c $(sqlite3-wasm.c)
|
||||
|
||||
#
|
||||
@@ -1034,6 +1063,14 @@ cflags.wasmfs = -DSQLITE_ENABLE_WASMFS
|
||||
# end wasmfs (the rest is in mkwasmbuilds.c)
|
||||
#
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
sqlite3-wasm.c = $(dir.api)/sqlite3-wasm.c
|
||||
# List of input files for compiling $(sqlite3-wasm.c). That file
|
||||
# #include's sqlite3.c directly, so it's implicitly includes here.
|
||||
sqlite3-wasm.c.in = $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
|
||||
|
||||
#
|
||||
# $(bin.mkwb) is used for generating much of the makefile code for the
|
||||
# various wasm builds. It used to be generated in this makefile via a
|
||||
@@ -1089,10 +1126,10 @@ sqlite3.ext.js =
|
||||
define gen-worker1
|
||||
# $1 = X.ext part of sqlite3-worker1X.ext
|
||||
# $2 = $(c-pp.D.NAME)
|
||||
$(call b.c-pp.target,filter,$(dir.api)/sqlite3-worker1.c-pp.js,\
|
||||
$(dir.dout)/sqlite3-worker1$(1),$(2))
|
||||
sqlite3.ext.js += $(dir.dout)/sqlite3-worker1$(1)
|
||||
all: $(dir.dout)/sqlite3-worker1$(1)
|
||||
$(call b.c-pp.target,filter,$$(dir.api)/sqlite3-worker1.c-pp.js,\
|
||||
$$(dir.dout)/sqlite3-worker1$(1),$(2))
|
||||
sqlite3.ext.js += $$(dir.dout)/sqlite3-worker1$(1)
|
||||
all: $$(dir.dout)/sqlite3-worker1$(1)
|
||||
endef
|
||||
|
||||
$(eval $(call gen-worker1,.js,$(c-pp.D.vanilla)))
|
||||
@@ -1106,10 +1143,10 @@ $(eval $(call gen-worker1,-bundler-friendly.mjs,$(c-pp.D.bundler)))
|
||||
define gen-promiser
|
||||
# $1 = X.ext part of sqlite3-worker1-promiserX.ext
|
||||
# $2 = $(c-pp.D.NAME)
|
||||
$(call b.c-pp.target,filter,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
|
||||
$(dir.dout)/sqlite3-worker1-promiser$(1),$(2))
|
||||
sqlite3.ext.js += $(dir.dout)/sqlite3-worker1-promiser$(1)
|
||||
all: $(dir.dout)/sqlite3-worker1-promiser$(1)
|
||||
$(call b.c-pp.target,filter,$$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
|
||||
$$(dir.dout)/sqlite3-worker1-promiser$(1),$(2))
|
||||
sqlite3.ext.js += $$(dir.dout)/sqlite3-worker1-promiser$(1)
|
||||
all: $$(dir.dout)/sqlite3-worker1-promiser$(1)
|
||||
endef
|
||||
|
||||
$(eval $(call gen-promiser,.js,$(c-pp.D.vanilla)))
|
||||
@@ -1151,12 +1188,19 @@ $(dir.dout)/sqlite3-opfs-async-proxy.js: $(dir.api)/sqlite3-opfs-async-proxy.js
|
||||
# we don't otherwise have a great place to attach them such that
|
||||
# they're always copied when we need them.
|
||||
#
|
||||
# The var $(out.$(B).js) comes from $(bin.mkwb) and $(B) is the name
|
||||
# of a build set up by that tool, e.g. b-vanilla or b-esm64.
|
||||
#
|
||||
$(foreach B,$(b.names),$(eval $(out.$(B).js): $(sqlite3.ext.js)))
|
||||
|
||||
#
|
||||
# b-all: builds all available js/wasm builds.
|
||||
#
|
||||
$(foreach B,$(b.names),$(eval b-all: $(out.$(B).js)))
|
||||
|
||||
#$(foreach B,$(b.names),$(eval pre: $(pre-js.$(B).js)))
|
||||
$(foreach B,$(b.names),$(eval post: $(post-js.$(B).js)))
|
||||
|
||||
#
|
||||
# speedtest1 is our primary benchmarking tool.
|
||||
#
|
||||
@@ -1205,10 +1249,9 @@ speedtest1.exit-runtime1 = -sEXIT_RUNTIME=1
|
||||
# -sEXIT_RUNTIME=1 but we need EXIT_RUNTIME=0 for the worker-based app
|
||||
# which runs speedtest1 multiple times.
|
||||
|
||||
$(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api.core)
|
||||
@$(call b.echo,@,$(emo.disk)); \
|
||||
$(call b.mkdir@); \
|
||||
{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.core); } > $@ || exit
|
||||
$(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api)
|
||||
@$(call b.mkdir@); $(call b.echo,@,$(emo.disk)); \
|
||||
{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api); } > $@ || exit
|
||||
speedtest1: b-speedtest1
|
||||
|
||||
#
|
||||
@@ -1250,9 +1293,11 @@ $(eval $(call gen-st64,speedtest1-worker.js,speedtest1-worker-64bit.js,speedtest
|
||||
#
|
||||
# To create those, we filter tester1.c-pp.js/html with $(bin.c-pp)...
|
||||
|
||||
#
|
||||
# tester1.js variants:
|
||||
#
|
||||
define gen-tester1.js
|
||||
# $1 = build name to have dep on
|
||||
# $1 = build name to have a dep on
|
||||
# $2 = suffix for tester1SUFFIX JS
|
||||
# $3 = $(bin.c-pp) flags
|
||||
$(call b.c-pp.target,test,tester1.c-pp.js,tester1$(2),$(3))
|
||||
@@ -1261,20 +1306,18 @@ tester1-$(1): tester1$(2)
|
||||
tester1: tester1$(2)
|
||||
endef
|
||||
|
||||
$(eval $(call gen-tester1.js,vanilla,.js, \
|
||||
$(c-pp.D.vanilla) \
|
||||
-Dsqlite3.js=$(dir.dout)/sqlite3.js))
|
||||
$(eval $(call gen-tester1.js,vanilla64,-64bit.js, \
|
||||
$(c-pp.D.vanilla64) \
|
||||
-Dsqlite3.js=$(dir.dout)/sqlite3-64bit.js))
|
||||
$(eval $(call gen-tester1.js,esm,.mjs, \
|
||||
$(c-pp.D.esm) \
|
||||
-Dsqlite3.js=$(dir.dout)/sqlite3.mjs))
|
||||
$(eval $(call gen-tester1.js,esm64,-64bit.mjs, \
|
||||
$(c-pp.D.esm64) \
|
||||
-Dsqlite3.js=$(dir.dout)/sqlite3-64bit.mjs))
|
||||
$(eval $(call gen-tester1.js,vanilla,.js,\
|
||||
$(c-pp.D.vanilla) -Dsqlite3.js=$(dir.dout)/sqlite3.js))
|
||||
$(eval $(call gen-tester1.js,vanilla64,-64bit.js,\
|
||||
$(c-pp.D.vanilla64) -Dsqlite3.js=$(dir.dout)/sqlite3-64bit.js))
|
||||
$(eval $(call gen-tester1.js,esm,.mjs,\
|
||||
$(c-pp.D.esm) -Dsqlite3.js=$(dir.dout)/sqlite3.mjs))
|
||||
$(eval $(call gen-tester1.js,esm64,-64bit.mjs,\
|
||||
$(c-pp.D.esm64) -Dsqlite3.js=$(dir.dout)/sqlite3-64bit.mjs))
|
||||
|
||||
#
|
||||
# tester1.html variants:
|
||||
#
|
||||
define gen-tester1.html
|
||||
# $1 = build name to have a dep on
|
||||
# $2 = filename suffix: empty, -64bit, -esm, esm-64bit
|
||||
@@ -1309,9 +1352,11 @@ $(eval $(call gen-tester1.html,esm64,-esm-64bit,\
|
||||
-Dtester1.js=tester1-64bit.mjs \
|
||||
-Dsqlite3.js=$(dir.dout)/sqlite3-64bit.mjs))
|
||||
|
||||
# tester1-worker.html variants:
|
||||
# There is no ESM variant of this file. Instead, that page accepts a
|
||||
# ?esm URL flag to switch to ESM mode.
|
||||
#
|
||||
# tester1-worker.html variants: There is no ESM variant of this
|
||||
# file. Instead, that page accepts the ?esm URL flag to switch to ESM
|
||||
# mode.
|
||||
#
|
||||
$(eval $(call b.c-pp.target,test,tester1-worker.c-pp.html,\
|
||||
tester1-worker.html,-Dbitness=32))
|
||||
$(eval $(call b.c-pp.target,test,tester1-worker.c-pp.html,\
|
||||
@@ -1321,8 +1366,9 @@ tester1-worker.html: tester1.mjs
|
||||
tester1-worker-64bit.html: tester1-64bit.mjs
|
||||
|
||||
all: tester1
|
||||
#
|
||||
# end tester1
|
||||
########################################################################
|
||||
#
|
||||
|
||||
#
|
||||
# Convenience rules to rebuild with various -Ox levels. Much
|
||||
@@ -1333,6 +1379,7 @@ all: tester1
|
||||
#
|
||||
# Achtung: build times with anything higher than -O0 are somewhat
|
||||
# painful, which is why -O0 is the default.
|
||||
#
|
||||
.PHONY: o0 o1 o2 o3 os oz
|
||||
emcc-opt-extra =
|
||||
#ifeq (1,$(wasm-bare-bones))
|
||||
@@ -1383,7 +1430,9 @@ push-testing:
|
||||
ssh wasm-testing 'cd $(wasm-testing.dir) && bash .gzip' || \
|
||||
echo "SSH failed: it's likely that stale content will be served via old gzip files."
|
||||
|
||||
#
|
||||
# build everything needed by push-testing with -Oz
|
||||
#
|
||||
.PHONY: for-testing
|
||||
for-testing: emcc_opt=-Oz
|
||||
for-testing: loud=1
|
||||
@@ -1468,9 +1517,9 @@ endif
|
||||
dist-name-prefix = sqlite-wasm$(dist-name-extra)
|
||||
.PHONY: dist
|
||||
dist:
|
||||
./mkdist.sh $(dist-name-prefix)
|
||||
$(bin.bash) ./mkdist.sh $(dist-name-prefix)
|
||||
snapshot:
|
||||
./mkdist.sh $(dist-name-prefix) --snapshot
|
||||
$(bin.bash) ./mkdist.sh $(dist-name-prefix) --snapshot
|
||||
endif
|
||||
# ^^^ making dist/snapshot
|
||||
CLEAN_FILES += $(wildcard sqlite-wasm-*.zip)
|
||||
|
||||
@@ -155,3 +155,92 @@ _sqlite3_vtab_in_next
|
||||
_sqlite3_vtab_nochange
|
||||
_sqlite3_vtab_on_conflict
|
||||
_sqlite3_vtab_rhs_value
|
||||
//#if not bare-bones
|
||||
_sqlite3_column_database_name
|
||||
_sqlite3_column_origin_name
|
||||
_sqlite3_column_table_name
|
||||
_sqlite3_create_module
|
||||
_sqlite3_create_module_v2
|
||||
_sqlite3_create_window_function
|
||||
_sqlite3_declare_vtab
|
||||
_sqlite3_drop_modules
|
||||
_sqlite3_preupdate_blobwrite
|
||||
_sqlite3_preupdate_count
|
||||
_sqlite3_preupdate_depth
|
||||
_sqlite3_preupdate_hook
|
||||
_sqlite3_preupdate_new
|
||||
_sqlite3_preupdate_old
|
||||
_sqlite3_progress_handler
|
||||
_sqlite3_set_authorizer
|
||||
_sqlite3_vtab_collation
|
||||
_sqlite3_vtab_distinct
|
||||
_sqlite3_vtab_in
|
||||
_sqlite3_vtab_in_first
|
||||
_sqlite3_vtab_in_next
|
||||
_sqlite3_vtab_nochange
|
||||
_sqlite3_vtab_on_conflict
|
||||
_sqlite3_vtab_rhs_value
|
||||
_sqlite3changegroup_add
|
||||
_sqlite3changegroup_add_strm
|
||||
_sqlite3changegroup_delete
|
||||
_sqlite3changegroup_new
|
||||
_sqlite3changegroup_output
|
||||
_sqlite3changegroup_output_strm
|
||||
_sqlite3changeset_apply
|
||||
_sqlite3changeset_apply_strm
|
||||
_sqlite3changeset_apply_v2
|
||||
_sqlite3changeset_apply_v2_strm
|
||||
_sqlite3changeset_apply_v3
|
||||
_sqlite3changeset_apply_v3_strm
|
||||
_sqlite3changeset_concat
|
||||
_sqlite3changeset_concat_strm
|
||||
_sqlite3changeset_conflict
|
||||
_sqlite3changeset_finalize
|
||||
_sqlite3changeset_fk_conflicts
|
||||
_sqlite3changeset_invert
|
||||
_sqlite3changeset_invert_strm
|
||||
_sqlite3changeset_new
|
||||
_sqlite3changeset_next
|
||||
_sqlite3changeset_old
|
||||
_sqlite3changeset_op
|
||||
_sqlite3changeset_pk
|
||||
_sqlite3changeset_start
|
||||
_sqlite3changeset_start_strm
|
||||
_sqlite3changeset_start_v2
|
||||
_sqlite3changeset_start_v2_strm
|
||||
_sqlite3session_attach
|
||||
_sqlite3session_changeset
|
||||
_sqlite3session_changeset_size
|
||||
_sqlite3session_changeset_strm
|
||||
_sqlite3session_config
|
||||
_sqlite3session_create
|
||||
_sqlite3session_delete
|
||||
_sqlite3session_diff
|
||||
_sqlite3session_enable
|
||||
_sqlite3session_indirect
|
||||
_sqlite3session_isempty
|
||||
_sqlite3session_memory_used
|
||||
_sqlite3session_object_config
|
||||
_sqlite3session_patchset
|
||||
_sqlite3session_patchset_strm
|
||||
_sqlite3session_table_filter
|
||||
//#endif not bare-bones
|
||||
//#if enable-see
|
||||
_sqlite3_key
|
||||
_sqlite3_key_v2
|
||||
_sqlite3_rekey
|
||||
_sqlite3_rekey_v2
|
||||
_sqlite3_activate_see
|
||||
//#endif enable-see
|
||||
//#if fiddle
|
||||
_fiddle_db_arg
|
||||
_fiddle_db_filename
|
||||
_fiddle_exec
|
||||
_fiddle_experiment
|
||||
_fiddle_interrupt
|
||||
_fiddle_main
|
||||
_fiddle_reset_db
|
||||
_fiddle_db_handle
|
||||
_fiddle_db_vfs
|
||||
_fiddle_export_db
|
||||
//#endif fiddle
|
||||
@@ -1,68 +0,0 @@
|
||||
_sqlite3_column_database_name
|
||||
_sqlite3_column_origin_name
|
||||
_sqlite3_column_table_name
|
||||
_sqlite3_create_module
|
||||
_sqlite3_create_module_v2
|
||||
_sqlite3_create_window_function
|
||||
_sqlite3_declare_vtab
|
||||
_sqlite3_drop_modules
|
||||
_sqlite3_preupdate_blobwrite
|
||||
_sqlite3_preupdate_count
|
||||
_sqlite3_preupdate_depth
|
||||
_sqlite3_preupdate_hook
|
||||
_sqlite3_preupdate_new
|
||||
_sqlite3_preupdate_old
|
||||
_sqlite3_progress_handler
|
||||
_sqlite3_set_authorizer
|
||||
_sqlite3_vtab_collation
|
||||
_sqlite3_vtab_distinct
|
||||
_sqlite3_vtab_in
|
||||
_sqlite3_vtab_in_first
|
||||
_sqlite3_vtab_in_next
|
||||
_sqlite3_vtab_nochange
|
||||
_sqlite3_vtab_on_conflict
|
||||
_sqlite3_vtab_rhs_value
|
||||
_sqlite3changegroup_add
|
||||
_sqlite3changegroup_add_strm
|
||||
_sqlite3changegroup_delete
|
||||
_sqlite3changegroup_new
|
||||
_sqlite3changegroup_output
|
||||
_sqlite3changegroup_output_strm
|
||||
_sqlite3changeset_apply
|
||||
_sqlite3changeset_apply_strm
|
||||
_sqlite3changeset_apply_v2
|
||||
_sqlite3changeset_apply_v2_strm
|
||||
_sqlite3changeset_apply_v3
|
||||
_sqlite3changeset_apply_v3_strm
|
||||
_sqlite3changeset_concat
|
||||
_sqlite3changeset_concat_strm
|
||||
_sqlite3changeset_conflict
|
||||
_sqlite3changeset_finalize
|
||||
_sqlite3changeset_fk_conflicts
|
||||
_sqlite3changeset_invert
|
||||
_sqlite3changeset_invert_strm
|
||||
_sqlite3changeset_new
|
||||
_sqlite3changeset_next
|
||||
_sqlite3changeset_old
|
||||
_sqlite3changeset_op
|
||||
_sqlite3changeset_pk
|
||||
_sqlite3changeset_start
|
||||
_sqlite3changeset_start_strm
|
||||
_sqlite3changeset_start_v2
|
||||
_sqlite3changeset_start_v2_strm
|
||||
_sqlite3session_attach
|
||||
_sqlite3session_changeset
|
||||
_sqlite3session_changeset_size
|
||||
_sqlite3session_changeset_strm
|
||||
_sqlite3session_config
|
||||
_sqlite3session_create
|
||||
_sqlite3session_delete
|
||||
_sqlite3session_diff
|
||||
_sqlite3session_enable
|
||||
_sqlite3session_indirect
|
||||
_sqlite3session_isempty
|
||||
_sqlite3session_memory_used
|
||||
_sqlite3session_object_config
|
||||
_sqlite3session_patchset
|
||||
_sqlite3session_patchset_strm
|
||||
_sqlite3session_table_filter
|
||||
@@ -1,5 +0,0 @@
|
||||
_sqlite3_key
|
||||
_sqlite3_key_v2
|
||||
_sqlite3_rekey
|
||||
_sqlite3_rekey_v2
|
||||
_sqlite3_activate_see
|
||||
@@ -1,3 +0,0 @@
|
||||
FS
|
||||
wasmMemory
|
||||
|
||||
+43
-39
@@ -23,7 +23,7 @@ this writing, but is not set in stone forever and may change at any
|
||||
time. This doc targets maintainers of this code and those wanting to
|
||||
dive in to the details, not end user.
|
||||
|
||||
First off, a pikchr of the proverbial onion:
|
||||
First off, a [pikchr][] of the proverbial onion:
|
||||
|
||||
```pikchr toggle center
|
||||
scale = 0.85
|
||||
@@ -60,14 +60,14 @@ maintenance point of view.
|
||||
At the center of the onion is `sqlite3-api.js`, which gets generated
|
||||
by concatenating the following files together in their listed order:
|
||||
|
||||
- **`sqlite3-api-prologue.js`**\
|
||||
- **`sqlite3-api-prologue.js`**
|
||||
Contains the initial bootstrap setup of the sqlite3 API
|
||||
objects. This is exposed as a function, rather than objects, so that
|
||||
the next step can pass in a config object which abstracts away parts
|
||||
of the WASM environment, to facilitate plugging it in to arbitrary
|
||||
WASM toolchains. The bootstrapping function gets removed from the
|
||||
global scope in a later stage of the bootstrapping process.
|
||||
- **`../common/whwasmutil.js`**\
|
||||
- **`../common/whwasmutil.js`**
|
||||
A semi-third-party collection of JS/WASM utility code intended to
|
||||
replace much of the Emscripten glue. The sqlite3 APIs internally use
|
||||
these APIs instead of their Emscripten counterparts, in order to be
|
||||
@@ -77,79 +77,78 @@ by concatenating the following files together in their listed order:
|
||||
toolchains. It is "semi-third-party" in that it was created in order
|
||||
to support this tree but is standalone and maintained together
|
||||
with...
|
||||
- **`../jaccwabyt/jaccwabyt.js`**\
|
||||
- **`../jaccwabyt/jaccwabyt.js`**
|
||||
Another semi-third-party API which creates bindings between JS
|
||||
and C structs, such that changes to the struct state from either JS
|
||||
or C are visible to the other end of the connection. This is also an
|
||||
independent spinoff project, conceived for the sqlite3 project but
|
||||
maintained separately.
|
||||
- **`sqlite3-api-glue.js`**\
|
||||
- **`sqlite3-api-glue.js`**
|
||||
Invokes functionality exposed by the previous two files to flesh out
|
||||
low-level parts of `sqlite3-api-prologue.js`. Most of these pieces
|
||||
involve populating the `sqlite3.capi.wasm` object and creating
|
||||
`sqlite3.capi.sqlite3_...()` bindings. This file also deletes most
|
||||
global-scope symbols the above files create, effectively moving them
|
||||
into the scope being used for initializing the API.
|
||||
- **`<build>/sqlite3-api-build-version.js`**\
|
||||
- **`<build>/sqlite3-api-build-version.js`**
|
||||
Gets created by the build process and populates the
|
||||
`sqlite3.version` object. This part is not critical, but records the
|
||||
version of the library against which this module was built.
|
||||
- **`sqlite3-api-oo1.js`**\
|
||||
- **`sqlite3-api-oo1.js`**
|
||||
Provides a high-level object-oriented wrapper to the lower-level C
|
||||
API, colloquially known as OO API #1. Its API is similar to other
|
||||
high-level sqlite3 JS wrappers and should feel relatively familiar
|
||||
to anyone familiar with such APIs. It is not a "required component"
|
||||
and can be elided from builds which do not want it.
|
||||
- **`sqlite3-api-worker1.js`**\
|
||||
- **`sqlite3-api-worker1.js`**
|
||||
A Worker-thread-based API which uses OO API #1 to provide an
|
||||
interface to a database which can be driven from the main Window
|
||||
thread via the Worker message-passing interface. Like OO API #1,
|
||||
this is an optional component, offering one of any number of
|
||||
potential implementations for such an API.
|
||||
- **`sqlite3-worker1.js`**\
|
||||
- **`sqlite3-worker1.js`**
|
||||
Is not part of the amalgamated sources and is intended to be
|
||||
loaded by a client Worker thread. It loads the sqlite3 module
|
||||
and runs the Worker #1 API which is implemented in
|
||||
`sqlite3-api-worker1.js`.
|
||||
- **`sqlite3-worker1-promiser.js`**\
|
||||
- **`sqlite3-worker1-promiser.js`**
|
||||
Is likewise not part of the amalgamated sources and provides
|
||||
a Promise-based interface into the Worker #1 API. This is
|
||||
a far user-friendlier way to interface with databases running
|
||||
in a Worker thread.
|
||||
- **`sqlite3-vfs-helper.js`**\
|
||||
- **`sqlite3-vfs-helper.js`**
|
||||
Installs the `sqlite3.vfs` namespace, which contain helpers for use
|
||||
by downstream code which creates `sqlite3_vfs` implementations.
|
||||
- **`sqlite3-vtab-helper.js`**\
|
||||
- **`sqlite3-vtab-helper.js`**
|
||||
Installs the `sqlite3.vtab` namespace, which contain helpers for use
|
||||
by downstream code which creates `sqlite3_module` implementations.
|
||||
- **`sqlite3-vfs-opfs.c-pp.js`**\
|
||||
- **`sqlite3-vfs-opfs.c-pp.js`**
|
||||
is an sqlite3 VFS implementation which supports the [Origin-Private
|
||||
FileSystem (OPFS)][OPFS] as a storage layer to provide persistent
|
||||
storage for database files in a browser. It requires...
|
||||
- **`sqlite3-opfs-async-proxy.js`**\
|
||||
- **`sqlite3-opfs-async-proxy.js`**
|
||||
is the asynchronous backend part of the [OPFS][] proxy. It
|
||||
speaks directly to the (async) OPFS API and channels those
|
||||
results back to its synchronous counterpart. This file, because
|
||||
it must be started in its own Worker, is not part of the
|
||||
amalgamation.
|
||||
- **`sqlite3-vfs-opfs-sahpool.c-pp.js`**\
|
||||
- **`sqlite3-vfs-opfs-sahpool.c-pp.js`**
|
||||
is another sqlite3 VFS supporting the [OPFS][], but uses a
|
||||
completely different approach than the above-listed one.
|
||||
- **`sqlite3-api-cleanup.js`**\
|
||||
The previous files do not immediately extend the library. Instead
|
||||
they add callback functions to be called during its
|
||||
bootstrapping. Some also temporarily create global objects in order
|
||||
to communicate their state to the files which follow them. This file
|
||||
cleans up any dangling globals and runs the API bootstrapping
|
||||
process, which is what finally executes the initialization code
|
||||
installed by the previous files. As of this writing, this code
|
||||
ensures that the previous files leave no more than a single global
|
||||
symbol installed - `sqlite3InitModule()`. When adapting the API for
|
||||
non-Emscripten toolchains, this "should" be the only file, of those
|
||||
in this list, where changes are needed. The Emscripten-specific
|
||||
pieces described below may also require counterparts in any as-yet
|
||||
hypothetical alternative build.
|
||||
|
||||
The previous files do not immediately extend the library. Instead they
|
||||
install a global function `sqlite3ApiBootstrap()`, which downstream
|
||||
code must call to configure the library for the current JS/WASM
|
||||
environment. Each file listed above pushes a callback into the
|
||||
bootstrapping queue, to be called as part of `sqlite3ApiBootstrap()`.
|
||||
Some files also temporarily create global objects in order to
|
||||
communicate their state to the files which follow them. Those
|
||||
get cleaned up vi `post-js-footer.js`, described below.
|
||||
|
||||
Adapting the build for non-Emscripten toolchains essentially requires packaging
|
||||
the above files, concatated together, into that toolchain's "JS glue"
|
||||
and, in the final stage of that glue, call `sqlite3ApiBootstrap()` and
|
||||
return its result to the end user.
|
||||
|
||||
**Files with the extension `.c-pp.js`** are intended [to be processed
|
||||
with `c-pp`](#c-pp), noting that such preprocessing may be applied
|
||||
@@ -171,23 +170,27 @@ from this file rather than `sqlite3.c`.
|
||||
The following Emscripten-specific files are injected into the
|
||||
build-generated `sqlite3.js` along with `sqlite3-api.js`.
|
||||
|
||||
- **`extern-pre-js.js`**\
|
||||
- **`extern-pre-js.js`**
|
||||
Emscripten-specific header for Emscripten's `--extern-pre-js`
|
||||
flag. As of this writing, that file is only used for experimentation
|
||||
purposes and holds no code relevant to the production deliverables.
|
||||
- **`pre-js.c-pp.js`**\
|
||||
- **`pre-js.c-pp.js`**
|
||||
Emscripten-specific header for Emscripten's `--pre-js` flag. This
|
||||
file overrides certain Emscripten behavior before Emscripten does
|
||||
most of its work.
|
||||
- **`post-js-header.js`**\
|
||||
- **`post-js-header.js`**
|
||||
Emscripten-specific header for the `--post-js` input. It opens up,
|
||||
but does not close, a function used for initializing the library.
|
||||
- (**`sqlite3-api.js`** gets sandwiched between these ↑ two
|
||||
↓ files.)
|
||||
- **`post-js-footer.js`**\
|
||||
- **`sqlite3-api.js`** gets sandwiched between these ↑ two
|
||||
↓ files.
|
||||
- **`post-js-footer.js`**
|
||||
Emscripten-specific footer for the `--post-js` input. This closes
|
||||
off the function opened by `post-js-header.js`.
|
||||
- **`extern-post-js.c-pp.js`**\
|
||||
off the function opened by `post-js-header.js`. This file cleans up
|
||||
any dangling globals and runs `sqlite3ApiBootstrap()`. As of this
|
||||
writing, this code ensures that the previous files leave no more
|
||||
than a single global symbol installed - `sqlite3InitModule()`.
|
||||
|
||||
- **`extern-post-js.c-pp.js`**
|
||||
Emscripten-specific header for Emscripten's `--extern-post-js`
|
||||
flag. This file is run in the global scope. It overwrites the
|
||||
Emscripten-installed `sqlite3InitModule()` function with one which
|
||||
@@ -205,9 +208,10 @@ Preprocessing of Source Files
|
||||
Certain files in the build require preprocessing to filter in/out
|
||||
parts which differ between vanilla JS, ES6 Modules, and node.js
|
||||
builds. The preprocessor application itself is in
|
||||
[`c-pp.c`](/file/ext/wasm/c-pp.c) and the complete technical details
|
||||
of such preprocessing are maintained in
|
||||
[`c-pp-lite.c`](/file/ext/wasm/c-pp-lite.c) and the complete technical
|
||||
details of such preprocessing are maintained in
|
||||
[`GNUMakefile`](/file/ext/wasm/GNUmakefile).
|
||||
|
||||
|
||||
[OPFS]: https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system
|
||||
[pikchr]: https://pikchr.org
|
||||
|
||||
@@ -26,7 +26,7 @@ const toExportForESM =
|
||||
*/
|
||||
const originalInit = sqlite3InitModule;
|
||||
if(!originalInit){
|
||||
throw new Error("Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build.");
|
||||
throw new Error("Expecting sqlite3InitModule to be defined by the Emscripten build.");
|
||||
}
|
||||
/**
|
||||
We need to add some state which our custom Module.locateFile()
|
||||
|
||||
@@ -1,3 +1,72 @@
|
||||
/*
|
||||
2022-07-22
|
||||
|
||||
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 the tail end of the sqlite3-api.js constellation,
|
||||
closing the function scope opened by post-js-header.js.
|
||||
|
||||
In terms of amalgamation code placement, this file is appended
|
||||
immediately after the final sqlite3-api-*.js piece. Those files
|
||||
cooperate to prepare sqlite3ApiBootstrap() and this file calls it.
|
||||
It is run within a context which gives it access to Emscripten's
|
||||
Module object, after sqlite3.wasm is loaded but before
|
||||
sqlite3ApiBootstrap() has been called.
|
||||
|
||||
Because this code resides (after building) inside the function
|
||||
installed by post-js-header.js, it has access to state set up by
|
||||
pre-js.c-pp.js and friends.
|
||||
*/
|
||||
try{
|
||||
/* We are in the closing block of Module.runSQLite3PostLoadInit(), so
|
||||
its arguments are visible here. */
|
||||
|
||||
/* Config options for sqlite3ApiBootstrap(). */
|
||||
const bootstrapConfig = Object.assign(
|
||||
Object.create(null),
|
||||
/** The WASM-environment-dependent configuration for sqlite3ApiBootstrap() */
|
||||
{
|
||||
memory: ('undefined'!==typeof wasmMemory)
|
||||
? wasmMemory
|
||||
: EmscriptenModule['wasmMemory'],
|
||||
exports: ('undefined'!==typeof wasmExports)
|
||||
? wasmExports /* emscripten >=3.1.44 */
|
||||
: (Object.prototype.hasOwnProperty.call(EmscriptenModule,'wasmExports')
|
||||
? EmscriptenModule['wasmExports']
|
||||
: EmscriptenModule['asm']/* emscripten <=3.1.43 */)
|
||||
},
|
||||
globalThis.sqlite3ApiBootstrap.defaultConfig, // default options
|
||||
globalThis.sqlite3ApiConfig || {} // optional client-provided options
|
||||
);
|
||||
|
||||
sqlite3InitScriptInfo.debugModule("Bootstrapping lib config", bootstrapConfig);
|
||||
|
||||
/**
|
||||
For purposes of the Emscripten build, call sqlite3ApiBootstrap().
|
||||
Ideally clients should be able to inject their own config here,
|
||||
but that's not practical in this particular build constellation
|
||||
because of the order everything happens in. Clients may either
|
||||
define globalThis.sqlite3ApiConfig or modify
|
||||
globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default
|
||||
configuration used by a no-args call to sqlite3ApiBootstrap(),
|
||||
but must have first loaded their WASM module in order to be able
|
||||
to provide the necessary configuration state.
|
||||
*/
|
||||
const p = globalThis.sqlite3ApiBootstrap(bootstrapConfig);
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
return p /* the eventual result of globalThis.sqlite3InitModule() */;
|
||||
}catch(e){
|
||||
console.error("sqlite3ApiBootstrap() error:",e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
//console.warn("This is the end of the Module.runSQLite3PostLoadInit handler.");
|
||||
}/*Module.runSQLite3PostLoadInit(...)*/;
|
||||
//console.warn("This is the end of the setup of the (pending) Module.runSQLite3PostLoadInit");
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
post-js.js for use with Emscripten's --post-js flag, so it gets
|
||||
injected in the earliest stages of sqlite3InitModule().
|
||||
|
||||
This function wraps the whole SQLite3 library but does not
|
||||
bootstrap it.
|
||||
|
||||
Running this function will bootstrap the library and return
|
||||
a Promise to the sqlite3 namespace object.
|
||||
|
||||
In the canonical builds, this gets called by extern-post-js.c-pp.js
|
||||
*/
|
||||
Module.runSQLite3PostLoadInit = function(
|
||||
sqlite3InitScriptInfo /* populated by extern-post-js.c-pp.js */,
|
||||
Module.runSQLite3PostLoadInit = async function(
|
||||
sqlite3InitScriptInfo,
|
||||
EmscriptenModule/*the Emscripten-style module object*/,
|
||||
sqlite3IsUnderTest
|
||||
){
|
||||
@@ -35,7 +34,6 @@ Module.runSQLite3PostLoadInit = function(
|
||||
- sqlite3-vtab-helper.c-pp.js => Utilities for virtual table impls
|
||||
- sqlite3-vfs-opfs.c-pp.js => OPFS VFS
|
||||
- sqlite3-vfs-opfs-sahpool.c-pp.js => OPFS SAHPool VFS
|
||||
- sqlite3-api-cleanup.js => final bootstrapping phase
|
||||
- post-js-footer.js => this file's epilogue
|
||||
|
||||
And all of that gets sandwiched between extern-pre-js.js and
|
||||
|
||||
@@ -14,12 +14,33 @@
|
||||
itself. i.e. try to keep file-local symbol names obnoxiously
|
||||
collision-resistant.
|
||||
*/
|
||||
/**
|
||||
This file was preprocessed using:
|
||||
|
||||
//#@policy error
|
||||
@c-pp::ARGV@
|
||||
//#@policy off
|
||||
*/
|
||||
//#if unsupported-build
|
||||
/**
|
||||
UNSUPPORTED BUILD:
|
||||
|
||||
This SQLite JS build configuration is entirely unsupported! It has
|
||||
not been tested beyond the ability to compile it. It may not
|
||||
load. It may not work properly. Only builds targeting browser
|
||||
environments are supported and tested.
|
||||
*/
|
||||
//#endif
|
||||
(function(Module){
|
||||
const sIMS =
|
||||
globalThis.sqlite3InitModuleState/*from extern-post-js.c-pp.js*/
|
||||
|| Object.assign(Object.create(null),{
|
||||
debugModule: ()=>{
|
||||
console.warn("globalThis.sqlite3InitModuleState is missing");
|
||||
/* In WASMFS builds this file gets loaded once per thread,
|
||||
but sqlite3InitModuleState is not getting set for the
|
||||
worker threads? That those workers seem to function fine
|
||||
despite that is curious. */
|
||||
debugModule: function(){
|
||||
console.warn("globalThis.sqlite3InitModuleState is missing",arguments);
|
||||
}
|
||||
});
|
||||
delete globalThis.sqlite3InitModuleState;
|
||||
@@ -72,8 +93,7 @@
|
||||
//#endif target:es6-module
|
||||
}.bind(sIMS);
|
||||
|
||||
//#if Module.instantiateWasm
|
||||
//#if not wasmfs
|
||||
//#if Module.instantiateWasm and not wasmfs
|
||||
/**
|
||||
Override Module.instantiateWasm().
|
||||
|
||||
@@ -109,7 +129,6 @@
|
||||
.then(finalThen)
|
||||
return loadWasm();
|
||||
}.bind(sIMS);
|
||||
//#endif not wasmfs
|
||||
//#endif Module.instantiateWasm
|
||||
//#endif Module.instantiateWasm and not wasmfs
|
||||
})(Module);
|
||||
/* END FILE: api/pre-js.js. */
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
2022-07-22
|
||||
|
||||
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 the tail end of the sqlite3-api.js constellation,
|
||||
intended to be appended after all other sqlite3-api-*.js files so
|
||||
that it can finalize any setup and clean up any global symbols
|
||||
temporarily used for setting up the API's various subsystems.
|
||||
|
||||
In Emscripten builds it's run in the context of what amounts to a
|
||||
Module.postRun handler, though it's no longer actually a postRun
|
||||
handler because Emscripten 4.0 changed postRun semantics in an
|
||||
incompatible way.
|
||||
|
||||
In terms of amalgamation code placement, this file is appended
|
||||
immediately after the final sqlite3-api-*.js piece. Those files
|
||||
cooperate to prepare sqlite3ApiBootstrap() and this file calls it.
|
||||
It is run within a context which gives it access to Emscripten's
|
||||
Module object, after sqlite3.wasm is loaded but before
|
||||
sqlite3ApiBootstrap() has been called.
|
||||
|
||||
Because this code resides (after building) inside the function
|
||||
installed by post-js-header.js, it has access to the
|
||||
*/
|
||||
'use strict';
|
||||
if( 'undefined' === typeof EmscriptenModule/*from post-js-header.js*/ ){
|
||||
console.warn("This is not running in the context of Module.runSQLite3PostLoadInit()");
|
||||
throw new Error("sqlite3-api-cleanup.js expects to be running in the "+
|
||||
"context of its Emscripten module loader.");
|
||||
}
|
||||
try{
|
||||
/* Config options for sqlite3ApiBootstrap(). */
|
||||
const bootstrapConfig = Object.assign(
|
||||
Object.create(null),
|
||||
globalThis.sqlite3ApiBootstrap.defaultConfig, // default options
|
||||
globalThis.sqlite3ApiConfig || {}, // optional client-provided options
|
||||
/** The WASM-environment-dependent configuration for sqlite3ApiBootstrap() */
|
||||
{
|
||||
memory: ('undefined'!==typeof wasmMemory)
|
||||
? wasmMemory
|
||||
: EmscriptenModule['wasmMemory'],
|
||||
exports: ('undefined'!==typeof wasmExports)
|
||||
? wasmExports /* emscripten >=3.1.44 */
|
||||
: (Object.prototype.hasOwnProperty.call(EmscriptenModule,'wasmExports')
|
||||
? EmscriptenModule['wasmExports']
|
||||
: EmscriptenModule['asm']/* emscripten <=3.1.43 */)
|
||||
}
|
||||
);
|
||||
|
||||
/** Figure out if this is a 32- or 64-bit WASM build. */
|
||||
bootstrapConfig.wasmPtrIR =
|
||||
'number'===(typeof bootstrapConfig.exports.sqlite3_libversion())
|
||||
? 'i32' :'i64';
|
||||
const sIMS = sqlite3InitScriptInfo;
|
||||
sIMS.debugModule("Bootstrapping lib config", sIMS);
|
||||
|
||||
/**
|
||||
For purposes of the Emscripten build, call sqlite3ApiBootstrap().
|
||||
Ideally clients should be able to inject their own config here,
|
||||
but that's not practical in this particular build constellation
|
||||
because of the order everything happens in. Clients may either
|
||||
define globalThis.sqlite3ApiConfig or modify
|
||||
globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default
|
||||
configuration used by a no-args call to sqlite3ApiBootstrap(),
|
||||
but must have first loaded their WASM module in order to be able
|
||||
to provide the necessary configuration state.
|
||||
*/
|
||||
const p = globalThis.sqlite3ApiBootstrap(bootstrapConfig);
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
return p /* the eventual result of globalThis.sqlite3InitModule() */;
|
||||
}catch(e){
|
||||
console.error("sqlite3ApiBootstrap() error:",e);
|
||||
throw e;
|
||||
}
|
||||
throw new Error("Maintenance required: this line should never be reached");
|
||||
@@ -120,7 +120,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
|
||||
["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
|
||||
["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
|
||||
//#define proxy-text-apis=1
|
||||
//#if not proxy-text-apis
|
||||
/* Search this file for tag:proxy-text-apis to see what this is about. */
|
||||
["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
|
||||
//#endif
|
||||
["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
|
||||
["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"],
|
||||
["sqlite3_commit_hook", "void*", [
|
||||
@@ -317,7 +321,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
["sqlite3_value_numeric_type", "int", "sqlite3_value*"],
|
||||
["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"],
|
||||
["sqlite3_value_subtype", "int", "sqlite3_value*"],
|
||||
//#if not proxy-text-apis
|
||||
["sqlite3_value_text", "string", "sqlite3_value*"],
|
||||
//#endif
|
||||
["sqlite3_value_type", "int", "sqlite3_value*"],
|
||||
["sqlite3_vfs_find", "*", "string"],
|
||||
["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
|
||||
@@ -1654,6 +1660,45 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
}/*sqlite3_bind_text/blob()*/
|
||||
|
||||
//#if proxy-text-apis
|
||||
if(!capi.sqlite3_column_text){
|
||||
/*[tag:proxy-text-apis]
|
||||
As discussed at:
|
||||
|
||||
https://sqlite.org/forum/forumpost/d77281aec2df9ada
|
||||
|
||||
Summary: there are opinions that sqlite3_column_text() and
|
||||
sqlite3_value_text() should handle strings such that embedded
|
||||
NULs are retained. This block does that. This block does _not_
|
||||
apply that special-case behavior to any number of _other_
|
||||
APIs which return C-strings. That discrepancy makes this
|
||||
block highly arguable, but one can also argue that these two
|
||||
specific functions can get away with such acrobatics without
|
||||
it being called voodoo in a pejorative sense.
|
||||
*/
|
||||
const argStmt = wasm.xWrap.argAdapter('sqlite3_stmt*'),
|
||||
argInt = wasm.xWrap.argAdapter('int'),
|
||||
argValue = wasm.xWrap.argAdapter('sqlite3_value*'),
|
||||
newStr =
|
||||
(cstr,n)=>wasm.typedArrayToString(wasm.heap8u(),
|
||||
Number(cstr), Number(cstr)+n)
|
||||
capi.sqlite3_column_text = function(stmt, colIndex){
|
||||
const a0 = argStmt(stmt), a1 = argInt(colIndex);
|
||||
const cstr = wasm.exports.sqlite3_column_text(a0, a1);
|
||||
return cstr
|
||||
? newStr(cstr,wasm.exports.sqlite3_column_bytes(a0, a1))
|
||||
: null;
|
||||
};
|
||||
capi.sqlite3_value_text = function(val){
|
||||
const a0 = argValue(val);
|
||||
const cstr = wasm.exports.sqlite3_value_text(a0);
|
||||
return cstr
|
||||
? newStr(cstr,wasm.exports.sqlite3_value_bytes(a0))
|
||||
: null;
|
||||
};
|
||||
}/*text-return-related bindings*/
|
||||
//#endif proxy-text-apis
|
||||
|
||||
{/* sqlite3_config() */
|
||||
/**
|
||||
Wraps a small subset of the C API's sqlite3_config() options.
|
||||
@@ -1836,6 +1881,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
for anything other than local/sessionStorage. It "can"
|
||||
be used that way but it's not really intended to be. */
|
||||
capi.sqlite3_vfs_unregister(pKvvfs);
|
||||
delete capi.sqlite3_kvvfs_methods;
|
||||
}
|
||||
}/*pKvvfs*/
|
||||
|
||||
@@ -1944,7 +1990,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
tgt[memKey] = fProxy;
|
||||
}else{
|
||||
const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name));
|
||||
const pFunc = wasm.installFunction(fProxy, sigN);
|
||||
tgt[memKey] = pFunc;
|
||||
if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
|
||||
tgt.addOnDispose('ondispose.__removeFuncList handler',
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
/**
|
||||
sqlite3ApiBootstrap() is the only global symbol persistently
|
||||
exposed by this API. It is intended to be called one time at the
|
||||
end of the API amalgamation process, passed configuration details
|
||||
for the current environment, and then optionally be removed from
|
||||
the global object using `delete globalThis.sqlite3ApiBootstrap`.
|
||||
end of the API amalgamation process and passed configuration details
|
||||
for the current environment.
|
||||
|
||||
This function is not intended for client-level use. It is intended
|
||||
for use in creating bundles configured for specific WASM
|
||||
environments.
|
||||
environments. That said, the "sqlite3-api.js" intermediary build
|
||||
file aims to be suitable for dropping in to custom builds, and it
|
||||
exposes only this function.
|
||||
|
||||
This function expects a configuration object, intended to abstract
|
||||
away details specific to any given WASM environment, primarily so
|
||||
@@ -93,9 +94,10 @@
|
||||
can be replaced with (e.g.) empty functions to squelch all such
|
||||
output.
|
||||
|
||||
- `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the OPFS-backed
|
||||
filesystem in WASMFS-capable builds.
|
||||
|
||||
- `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the
|
||||
OPFS-backed filesystem in WASMFS-capable builds. This is only
|
||||
used in WASMFS-capable builds of the library (which the canonical
|
||||
builds do not include).
|
||||
|
||||
[^1] = This property may optionally be a function, in which case
|
||||
this function calls that function to fetch the value,
|
||||
@@ -125,7 +127,8 @@
|
||||
Both sqlite3ApiBootstrap.defaultConfig and
|
||||
globalThis.sqlite3ApiConfig get deleted by sqlite3ApiBootstrap()
|
||||
because any changes to them made after that point would have no
|
||||
useful effect.
|
||||
useful effect. This function also deletes itself from globalThis
|
||||
when it's called.
|
||||
|
||||
This function returns a Promise to the sqlite3 namespace object,
|
||||
which resolves after the async pieces of the library init are
|
||||
@@ -177,14 +180,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Eliminate any confusion about whether these config objects may
|
||||
be used after library initialization by eliminating the outward-facing
|
||||
objects...
|
||||
*/
|
||||
delete globalThis.sqlite3ApiConfig;
|
||||
delete sqlite3ApiBootstrap.defaultConfig;
|
||||
|
||||
/**
|
||||
The main sqlite3 binding API gets installed into this object,
|
||||
mimicking the C API as closely as we can. The numerous members
|
||||
@@ -796,25 +791,10 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
|
||||
/**
|
||||
wasm.X properties which are used for configuring the wasm
|
||||
environment via whwashutil.js.
|
||||
environment via whwashutil.js. This object gets fleshed out with
|
||||
a number of WASM-specific utilities, in sqlite3-api-glue.c-pp.js.
|
||||
*/
|
||||
Object.assign(wasm, {
|
||||
/**
|
||||
The WASM IR (Intermediate Representation) value for
|
||||
pointer-type values. If set then it MUST be one of 'i32' or
|
||||
'i64' (else an exception will be thrown). If it's not set, it
|
||||
will default to 'i32'.
|
||||
*/
|
||||
pointerIR: config.wasmPtrIR,
|
||||
|
||||
/**
|
||||
True if BigInt support was enabled via (e.g.) the
|
||||
Emscripten -sWASM_BIGINT flag, else false. When
|
||||
enabled, certain 64-bit sqlite3 APIs are enabled which
|
||||
are not otherwise enabled due to JS/WASM int64
|
||||
impedance mismatches.
|
||||
*/
|
||||
bigIntEnabled: !!config.bigIntEnabled,
|
||||
|
||||
/**
|
||||
The symbols exported by the WASM environment.
|
||||
@@ -825,8 +805,9 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
/**
|
||||
When Emscripten compiles with `-sIMPORTED_MEMORY`, it
|
||||
initializes the heap and imports it into wasm, as opposed to
|
||||
the other way around. In this case, the memory is not
|
||||
available via this.exports.memory.
|
||||
the other way around. In this case, the memory is not available
|
||||
via this.exports.memory so the client must pass it in via
|
||||
config.memory.
|
||||
*/
|
||||
memory: config.memory
|
||||
|| config.exports['memory']
|
||||
@@ -834,6 +815,29 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
"in either config.exports.memory (exported)",
|
||||
"or config.memory (imported)."),
|
||||
|
||||
/**
|
||||
The WASM pointer size. If set then it MUST be one of 4 or 8 and
|
||||
it MUST correspond to the WASM environment's pointer size. We
|
||||
figure out the size by calling some un-JS-wrapped WASM function
|
||||
which returns a pointer-type value. If that value is a BigInt,
|
||||
it's 64-bit, else it's 32-bit. The pieces which populate
|
||||
sqlite3.wasm (whwasmutil.js) can figure this out _if_ they can
|
||||
allocate, but we have a chicken/egg situation there which makes
|
||||
it illegal for that code to invoke wasm.dealloc() at the time
|
||||
it would be needed. So we need to configure it ahead of time
|
||||
(here) instead.
|
||||
*/
|
||||
pointerSize: ('number'===typeof config.exports.sqlite3_libversion()) ? 4 : 8,
|
||||
|
||||
/**
|
||||
True if BigInt support was enabled via (e.g.) the
|
||||
Emscripten -sWASM_BIGINT flag, else false. When
|
||||
enabled, certain 64-bit sqlite3 APIs are enabled which
|
||||
are not otherwise enabled due to JS/WASM int64
|
||||
impedance mismatches.
|
||||
*/
|
||||
bigIntEnabled: !!config.bigIntEnabled,
|
||||
|
||||
/**
|
||||
WebAssembly.Table object holding the indirect function call
|
||||
table. Defaults to exports.__indirect_function_table.
|
||||
@@ -921,9 +925,11 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
srcTypedArray = new Uint8Array(srcTypedArray);
|
||||
}
|
||||
affirmBindableTypedArray(srcTypedArray);
|
||||
const heap = wasm.heapForSize(srcTypedArray.constructor);
|
||||
const pRet = wasm.alloc(srcTypedArray.byteLength || 1);
|
||||
heap.set(srcTypedArray.byteLength ? srcTypedArray : [0], Number(pRet));
|
||||
wasm.heapForSize(srcTypedArray.constructor)
|
||||
.set(srcTypedArray.byteLength ? srcTypedArray : [0], Number(pRet))
|
||||
/* Maintenance note: the order of alloc() and heapForSize() calls
|
||||
is significant: https://sqlite.org/forum/forumpost/05b77273be104532 */;
|
||||
return pRet;
|
||||
};
|
||||
|
||||
@@ -947,7 +953,11 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
};
|
||||
wasm.realloc.impl = wasm.exports[keyRealloc];
|
||||
wasm.dealloc = function f(m){
|
||||
f.impl(wasm.ptr.coerce(m)/*tag:64bit*/);
|
||||
f.impl(wasm.ptr.coerce(m)/*tag:64bit*/)
|
||||
/* This coerce() is the reason we have to set wasm.pointerSize before
|
||||
calling WhWasmUtilInstaller(). If we don't, that code will call
|
||||
into this very early in its init, before wasm.ptr has been set up,
|
||||
resulting in a null deref here. */;
|
||||
};
|
||||
wasm.dealloc.impl = wasm.exports[keyDealloc];
|
||||
}
|
||||
@@ -1018,18 +1028,18 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}/*compileOptionUsed()*/;
|
||||
|
||||
/**
|
||||
sqlite3.wasm.pstack (pseudo-stack) holds a special-case intended
|
||||
solely for short-lived, small data. In practice, it's primarily
|
||||
used to allocate output pointers. It mus not be used for any
|
||||
memory which needs to outlive the scope in which it's obtained
|
||||
from pstack.
|
||||
sqlite3.wasm.pstack (pseudo-stack) holds a special-case allocator
|
||||
intended solely for short-lived, small data. In practice, it's
|
||||
primarily used to allocate output pointers. It must not be used
|
||||
for any memory which needs to outlive the scope in which it's
|
||||
obtained from pstack.
|
||||
|
||||
The library guarantees only that a minimum of 2kb are available
|
||||
in this allocator, and it may provide more (it's a build-time
|
||||
value). pstack.quota and pstack.remaining can be used to get the
|
||||
total resp. remaining amount of memory.
|
||||
|
||||
It has only a single intended usage:
|
||||
It has only a single intended usage pattern:
|
||||
|
||||
```
|
||||
const stackPos = pstack.pointer;
|
||||
@@ -1046,13 +1056,11 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
```
|
||||
|
||||
This allocator is much faster than a general-purpose one but is
|
||||
limited to usage patterns like the one shown above.
|
||||
limited to usage patterns like the one shown above (which are
|
||||
pretty common when using sqlite3.capi).
|
||||
|
||||
It operates from a static range of memory which lives outside of
|
||||
space managed by Emscripten's stack-management, so does not
|
||||
collide with Emscripten-provided stack allocation APIs. The
|
||||
memory lives in the WASM heap and can be used with routines such
|
||||
as wasm.poke() and wasm.heap8u().slice().
|
||||
The memory lives in the WASM heap and can be used with routines
|
||||
such as wasm.poke() and wasm.heap8u().slice().
|
||||
*/
|
||||
wasm.pstack = Object.assign(Object.create(null),{
|
||||
/**
|
||||
@@ -1126,7 +1134,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
argument: if it's 1, it returns a single pointer value. If it's
|
||||
more than 1, it returns the same as allocChunks().
|
||||
|
||||
When a returned pointers will refer to a 64-bit value, e.g. a
|
||||
When a returned pointer will refer to a 64-bit value, e.g. a
|
||||
double or int64, and that value must be written or fetched,
|
||||
e.g. using wasm.poke() or wasm.peek(), it is
|
||||
important that the pointer in question be aligned to an 8-byte
|
||||
@@ -1194,6 +1202,9 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}
|
||||
})/*wasm.pstack properties*/;
|
||||
|
||||
/**
|
||||
Docs: https://sqlite.org/wasm/doc/trunk/api-c-style.md#sqlite3_randomness
|
||||
*/
|
||||
capi.sqlite3_randomness = (...args)=>{
|
||||
if(1===args.length
|
||||
&& util.isTypedArray(args[0])
|
||||
@@ -1228,8 +1239,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
wasm.exports.sqlite3_randomness(...args);
|
||||
};
|
||||
|
||||
/** State for sqlite3_wasmfs_opfs_dir(). */
|
||||
let __wasmfsOpfsDir = undefined;
|
||||
/**
|
||||
If the wasm environment has a WASMFS/OPFS-backed persistent
|
||||
storage directory, its path is returned by this function. If it
|
||||
@@ -1253,7 +1262,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
WASMFS capability requires a custom build.
|
||||
*/
|
||||
capi.sqlite3_wasmfs_opfs_dir = function(){
|
||||
if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir;
|
||||
if(undefined !== this.dir) return this.dir;
|
||||
// If we have no OPFS, there is no persistent dir
|
||||
const pdir = config.wasmfsOpfsDir;
|
||||
if(!pdir
|
||||
@@ -1261,21 +1270,21 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
|| !globalThis.FileSystemDirectoryHandle
|
||||
|| !globalThis.FileSystemFileHandle
|
||||
|| !wasm.exports.sqlite3__wasm_init_wasmfs){
|
||||
return __wasmfsOpfsDir = "";
|
||||
return this.dir = "";
|
||||
}
|
||||
try{
|
||||
if(pdir && 0===wasm.xCallWrapped(
|
||||
'sqlite3__wasm_init_wasmfs', 'i32', ['string'], pdir
|
||||
)){
|
||||
return __wasmfsOpfsDir = pdir;
|
||||
return this.dir = pdir;
|
||||
}else{
|
||||
return __wasmfsOpfsDir = "";
|
||||
return this.dir = "";
|
||||
}
|
||||
}catch(e){
|
||||
// sqlite3__wasm_init_wasmfs() is not available
|
||||
return __wasmfsOpfsDir = "";
|
||||
return this.dir = "";
|
||||
}
|
||||
};
|
||||
}.bind(Object.create(null));
|
||||
|
||||
/**
|
||||
Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
|
||||
@@ -1331,7 +1340,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
*/
|
||||
capi.sqlite3_js_vfs_list = function(){
|
||||
const rc = [];
|
||||
let pVfs = capi.sqlite3_vfs_find(wasm.ptr.coerce(0));
|
||||
let pVfs = capi.sqlite3_vfs_find(wasm.ptr.null);
|
||||
while(pVfs){
|
||||
const oVfs = new capi.sqlite3_vfs(pVfs);
|
||||
rc.push(wasm.cstrToJs(oVfs.$zName));
|
||||
@@ -1951,55 +1960,58 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
return (0===v) ? undefined : capi.sqlite3_value_to_js(v, throwIfCannotConvert);
|
||||
};
|
||||
|
||||
/**
|
||||
Internal impl of sqlite3_preupdate_new/old_js() and
|
||||
sqlite3changeset_new/old_js().
|
||||
*/
|
||||
const __newOldValue = function(pObj, iCol, impl){
|
||||
impl = capi[impl];
|
||||
if(!this.ptr) this.ptr = wasm.allocPtr();
|
||||
else wasm.pokePtr(this.ptr, 0);
|
||||
const rc = impl(pObj, iCol, this.ptr);
|
||||
if(rc) return SQLite3Error.toss(rc,arguments[2]+"() failed with code "+rc);
|
||||
const pv = wasm.peekPtr(this.ptr);
|
||||
return pv ? capi.sqlite3_value_to_js( pv, true ) : undefined;
|
||||
}.bind(Object.create(null));
|
||||
if( true ){ /* changeset/preupdate additions... */
|
||||
/**
|
||||
Internal impl of sqlite3_preupdate_new/old_js() and
|
||||
sqlite3changeset_new/old_js().
|
||||
*/
|
||||
const __newOldValue = function(pObj, iCol, impl){
|
||||
impl = capi[impl];
|
||||
if(!this.ptr) this.ptr = wasm.allocPtr();
|
||||
else wasm.pokePtr(this.ptr, 0);
|
||||
const rc = impl(pObj, iCol, this.ptr);
|
||||
if(rc) return SQLite3Error.toss(rc,arguments[2]+"() failed with code "+rc);
|
||||
const pv = wasm.peekPtr(this.ptr);
|
||||
return pv ? capi.sqlite3_value_to_js( pv, true ) : undefined;
|
||||
}.bind(Object.create(null));
|
||||
|
||||
/**
|
||||
A wrapper around sqlite3_preupdate_new() which fetches the
|
||||
sqlite3_value at the given index and returns the result of
|
||||
passing it to sqlite3_value_to_js(). Throws on error.
|
||||
*/
|
||||
capi.sqlite3_preupdate_new_js =
|
||||
(pDb, iCol)=>__newOldValue(pDb, iCol, 'sqlite3_preupdate_new');
|
||||
/**
|
||||
A wrapper around sqlite3_preupdate_new() which fetches the
|
||||
sqlite3_value at the given index and returns the result of
|
||||
passing it to sqlite3_value_to_js(). Throws on error.
|
||||
*/
|
||||
capi.sqlite3_preupdate_new_js =
|
||||
(pDb, iCol)=>__newOldValue(pDb, iCol, 'sqlite3_preupdate_new');
|
||||
|
||||
/**
|
||||
The sqlite3_preupdate_old() counterpart of
|
||||
sqlite3_preupdate_new_js(), with an identical interface.
|
||||
*/
|
||||
capi.sqlite3_preupdate_old_js =
|
||||
(pDb, iCol)=>__newOldValue(pDb, iCol, 'sqlite3_preupdate_old');
|
||||
/**
|
||||
The sqlite3_preupdate_old() counterpart of
|
||||
sqlite3_preupdate_new_js(), with an identical interface.
|
||||
*/
|
||||
capi.sqlite3_preupdate_old_js =
|
||||
(pDb, iCol)=>__newOldValue(pDb, iCol, 'sqlite3_preupdate_old');
|
||||
|
||||
/**
|
||||
A wrapper around sqlite3changeset_new() which fetches the
|
||||
sqlite3_value at the given index and returns the result of
|
||||
passing it to sqlite3_value_to_js(). Throws on error.
|
||||
/**
|
||||
A wrapper around sqlite3changeset_new() which fetches the
|
||||
sqlite3_value at the given index and returns the result of
|
||||
passing it to sqlite3_value_to_js(). Throws on error.
|
||||
|
||||
If sqlite3changeset_new() succeeds but has no value to report,
|
||||
this function returns the undefined value, noting that undefined
|
||||
is a valid conversion from an `sqlite3_value`, so is unambiguous.
|
||||
*/
|
||||
capi.sqlite3changeset_new_js =
|
||||
(pChangesetIter, iCol) => __newOldValue(pChangesetIter, iCol,
|
||||
'sqlite3changeset_new');
|
||||
If sqlite3changeset_new() succeeds but has no value to report,
|
||||
this function returns the undefined value, noting that
|
||||
undefined is not a valid conversion from an `sqlite3_value`, so
|
||||
is unambiguous.
|
||||
*/
|
||||
capi.sqlite3changeset_new_js =
|
||||
(pChangesetIter, iCol) => __newOldValue(pChangesetIter, iCol,
|
||||
'sqlite3changeset_new');
|
||||
|
||||
/**
|
||||
The sqlite3changeset_old() counterpart of
|
||||
sqlite3changeset_new_js(), with an identical interface.
|
||||
*/
|
||||
capi.sqlite3changeset_old_js =
|
||||
(pChangesetIter, iCol)=>__newOldValue(pChangesetIter, iCol,
|
||||
'sqlite3changeset_old');
|
||||
/**
|
||||
The sqlite3changeset_old() counterpart of
|
||||
sqlite3changeset_new_js(), with an identical interface.
|
||||
*/
|
||||
capi.sqlite3changeset_old_js =
|
||||
(pChangesetIter, iCol)=>__newOldValue(pChangesetIter, iCol,
|
||||
'sqlite3changeset_old');
|
||||
}/*changeset/preupdate additions*/
|
||||
|
||||
/* The remainder of the API will be set up in later steps. */
|
||||
const sqlite3 = {
|
||||
@@ -2011,10 +2023,10 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
config,
|
||||
/**
|
||||
Holds the version info of the sqlite3 source tree from which
|
||||
the generated sqlite3-api.js gets built. Note that its version
|
||||
may well differ from that reported by sqlite3_libversion(), but
|
||||
that should be considered a source file mismatch, as the JS and
|
||||
WASM files are intended to be built and distributed together.
|
||||
the generated sqlite3-api.js gets built. Its version may well
|
||||
differ from that reported by sqlite3_libversion(), but that
|
||||
should be considered a source file mismatch, as the JS and WASM
|
||||
files are intended to be built and distributed together.
|
||||
|
||||
This object is initially a placeholder which gets replaced by a
|
||||
build-generated object.
|
||||
@@ -2039,9 +2051,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
async init will be fatal to the init as a whole, but init
|
||||
routines are themselves welcome to install dummy catch()
|
||||
handlers which are not fatal if their failure should be
|
||||
considered non-fatal. If called more than once, the second and
|
||||
subsequent calls are no-ops which return a pre-resolved
|
||||
Promise.
|
||||
considered non-fatal.
|
||||
|
||||
Ideally this function is called as part of the Promise chain
|
||||
which handles the loading and bootstrapping of the API. If not
|
||||
@@ -2058,18 +2068,14 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
*/
|
||||
asyncPostInit: async function ff(){
|
||||
if(ff.isReady instanceof Promise) return ff.isReady;
|
||||
let lia = sqlite3ApiBootstrap.initializersAsync;
|
||||
delete sqlite3ApiBootstrap.initializersAsync;
|
||||
let lia = this.initializersAsync;
|
||||
delete this.initializersAsync;
|
||||
const postInit = async ()=>{
|
||||
if(!sqlite3.__isUnderTest){
|
||||
/* Delete references to internal-only APIs which are used by
|
||||
some initializers. Retain them when running in test mode
|
||||
so that we can add tests for them. */
|
||||
delete sqlite3.util;
|
||||
/* It's conceivable that we might want to expose
|
||||
StructBinder to client-side code, but it's only useful if
|
||||
clients build their own sqlite3.wasm which contains their
|
||||
own C struct types. */
|
||||
delete sqlite3.StructBinder;
|
||||
}
|
||||
return sqlite3;
|
||||
@@ -2088,7 +2094,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
let p = Promise.resolve(sqlite3);
|
||||
while(lia.length) p = p.then(lia.shift());
|
||||
return ff.isReady = p.catch(catcher);
|
||||
},
|
||||
}.bind(sqlite3ApiBootstrap),
|
||||
/**
|
||||
scriptInfo ideally gets injected into this object by the
|
||||
infrastructure which assembles the JS/WASM module. It contains
|
||||
@@ -2115,16 +2121,37 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}
|
||||
delete sqlite3ApiBootstrap.initializers;
|
||||
sqlite3ApiBootstrap.sqlite3 = sqlite3;
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
delete globalThis.sqlite3ApiConfig;
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3ApiBootstrap() complete", sqlite3
|
||||
);
|
||||
sqlite3.scriptInfo /* used by some async init code */ =
|
||||
sqlite3InitScriptInfo /* from post-js-header.js */;
|
||||
if( (sqlite3.__isUnderTest = sqlite3IsUnderTest /* from post-js-header.js */) ){
|
||||
sqlite3.config.emscripten = EmscriptenModule;
|
||||
const iw = sqlite3InitScriptInfo.instantiateWasm;
|
||||
if( 'undefined'!==typeof sqlite3InitScriptInfo/* from post-js-header.js */ ){
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3ApiBootstrap() complete", sqlite3
|
||||
);
|
||||
sqlite3.scriptInfo
|
||||
/* Used by some async init code. As of 2025-11-15 this is still
|
||||
in use by the OPFS VFS for locating its worker. In non-Emscripten
|
||||
builds, this would need to be injected in somewhere to get
|
||||
that VFS loading. */ = sqlite3InitScriptInfo;
|
||||
}
|
||||
sqlite3.__isUnderTest =
|
||||
('undefined'===typeof sqlite3IsUnderTest /* from post-js-header.js */)
|
||||
? false : !!sqlite3IsUnderTest;
|
||||
if( sqlite3.__isUnderTest ){
|
||||
if( 'undefined'!==typeof EmscriptenModule ){
|
||||
sqlite3.config.emscripten = EmscriptenModule;
|
||||
}
|
||||
/*
|
||||
The problem with exposing these pieces (in non-testing runs) via
|
||||
sqlite3.wasm is that it exposes non-SQLite pieces to the
|
||||
clients, who may come to expect it to remain. _We_ only have
|
||||
these data because we've overridden Emscripten's wasm file
|
||||
loader, and if we lose that capability for some reason then
|
||||
we'll lose access to this metadata.
|
||||
|
||||
These data are interesting for exploring how the wasm/JS
|
||||
pieces connect, e.g. for exploring exactly what Emscripten
|
||||
imports into WASM from its JS glue, but it's not
|
||||
SQLite-related.
|
||||
*/
|
||||
const iw = sqlite3.scriptInfo?.instantiateWasm;
|
||||
if( iw ){
|
||||
/* Metadata injected by the custom Module.instantiateWasm()
|
||||
in pre-js.c-pp.js. */
|
||||
@@ -2133,6 +2160,15 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
sqlite3.wasm.imports = iw.imports;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Eliminate any confusion about whether these config objects may
|
||||
be used after library initialization by eliminating the outward-facing
|
||||
objects...
|
||||
*/
|
||||
delete globalThis.sqlite3ApiConfig;
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
delete sqlite3ApiBootstrap.defaultConfig;
|
||||
return sqlite3.asyncPostInit().then((s)=>{
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3.asyncPostInit() complete", sqlite3
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
asynchronous Origin-Private FileSystem (OPFS) APIs using a second
|
||||
Worker, implemented in sqlite3-opfs-async-proxy.js. This file is
|
||||
intended to be appended to the main sqlite3 JS deliverable somewhere
|
||||
after sqlite3-api-oo1.js and before sqlite3-api-cleanup.js.
|
||||
after sqlite3-api-oo1.js.
|
||||
*/
|
||||
'use strict';
|
||||
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
@@ -1441,7 +1441,7 @@ installOpfsVfs.defaultProxyUri =
|
||||
globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
|
||||
try{
|
||||
let proxyJs = installOpfsVfs.defaultProxyUri;
|
||||
if(sqlite3.scriptInfo.sqlite3Dir){
|
||||
if( sqlite3?.scriptInfo?.sqlite3Dir ){
|
||||
installOpfsVfs.defaultProxyUri =
|
||||
sqlite3.scriptInfo.sqlite3Dir + proxyJs;
|
||||
//sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri);
|
||||
|
||||
@@ -136,8 +136,8 @@
|
||||
/*
|
||||
** If SQLITE_WASM_BARE_BONES is defined, undefine most of the ENABLE
|
||||
** macros. This will, when using the canonical makefile, also elide
|
||||
** any C functions from the WASM exports which are listed in
|
||||
** ./EXPORT_FUNCTIONS.sqlite3-extras.
|
||||
** any C functions from the WASM exports: see
|
||||
** ./EXPORTED_FUNCTIONS.c-pp.
|
||||
*/
|
||||
#ifdef SQLITE_WASM_BARE_BONES
|
||||
# undef SQLITE_ENABLE_COLUMN_METADATA
|
||||
@@ -326,7 +326,7 @@ SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_ptr(void){
|
||||
*/
|
||||
SQLITE_WASM_EXPORT void sqlite3__wasm_pstack_restore(unsigned char * p){
|
||||
assert(p>=PStack.pBegin && p<=PStack.pEnd && p>=PStack.pPos);
|
||||
assert(0==((unsigned long long)p & 0x7));
|
||||
assert(0==((unsigned long long)p & 0x7) /* 8-byte aligned */);
|
||||
if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){
|
||||
PStack.pPos = p;
|
||||
}
|
||||
|
||||
+54
-21
@@ -270,9 +270,10 @@ static void db_prepare(sqlite3_stmt **pStmt, const char * zSql, ...);
|
||||
/*
|
||||
** Opens the given file and processes its contents as c-pp, sending
|
||||
** all output to the global c-pp output channel. Fails fatally on
|
||||
** error.
|
||||
** error. If bRaw is true then the file's contents are passed through
|
||||
** verbatim, rather than being preprocessed.
|
||||
*/
|
||||
static void cmpp_process_file(const char * zName);
|
||||
static void cmpp_process_file(const char * zName, int bRaw);
|
||||
|
||||
/*
|
||||
** Operator policy for cmpp_kvp_parse().
|
||||
@@ -970,7 +971,6 @@ void db_prepare(sqlite3_stmt **pStmt, const char * zSql, ...){
|
||||
char * z = 0;
|
||||
int n = 0;
|
||||
va_list va;
|
||||
if(!str) fatal("sqlite3_str_new() failed");
|
||||
va_start(va, zSql);
|
||||
sqlite3_str_vappendf(str, zSql, va);
|
||||
va_end(va);
|
||||
@@ -1638,11 +1638,7 @@ static void cmpp_t_out_expand(CmppTokenizer * const t,
|
||||
for( ;z<zEnd; ++z ){
|
||||
if( chEol==*z ){
|
||||
state = 0;
|
||||
//This ++z/--z thing breaks stuff.
|
||||
//++z /*ensure that we flush the EOL now*/;
|
||||
tflush;
|
||||
//--z/*And make sure that zLeft does the right thing*/;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if( g.delim.chAt==*z ){
|
||||
if( 0==state ){
|
||||
@@ -2217,12 +2213,23 @@ static void cmpp_kwd_endif(CmppKeyword const * pKw, CmppTokenizer *t){
|
||||
static void cmpp_kwd_include(CmppKeyword const * pKw, CmppTokenizer *t){
|
||||
char const * zFile;
|
||||
char * zResolved;
|
||||
int bRaw = 0 /* -raw flag */;
|
||||
if(CT_skip(t)) return;
|
||||
else if(t->args.argc!=2){
|
||||
cmpp_kwd__err(pKw, t, "Expecting exactly 1 filename argument");
|
||||
else if(t->args.argc<2 || t->args.argc>3){
|
||||
cmpp_kwd__err(pKw, t, "Expected args: ?-raw? filename");
|
||||
}
|
||||
zFile = (const char *)t->args.argv[1];
|
||||
if(db_including_has(zFile)){
|
||||
if(t->args.argc==2){
|
||||
zFile = (const char *)t->args.argv[1];
|
||||
}else{
|
||||
if( 0==strcmp("-raw", (char*)t->args.argv[1]) ){
|
||||
bRaw = 1;
|
||||
}else{
|
||||
cmpp_kwd__err(pKw, t, "Unhandled argument: %s",
|
||||
t->args.argv[1]);
|
||||
}
|
||||
zFile = (const char *)t->args.argv[2];
|
||||
}
|
||||
if(!bRaw && db_including_has(zFile)){
|
||||
/* Note that different spellings of the same filename
|
||||
** will elude this check, but that seems okay, as different
|
||||
** spellings means that we're not re-running the exact same
|
||||
@@ -2233,16 +2240,15 @@ static void cmpp_kwd_include(CmppKeyword const * pKw, CmppTokenizer *t){
|
||||
}
|
||||
zResolved = db_include_search(zFile);
|
||||
if(zResolved){
|
||||
db_including_add(zFile, t->zName, t->token.lineNo);
|
||||
cmpp_process_file(zResolved);
|
||||
db_include_rm(zFile);
|
||||
if( bRaw ) db_including_add(zFile, t->zName, t->token.lineNo);
|
||||
cmpp_process_file(zResolved, bRaw);
|
||||
if( bRaw ) db_include_rm(zFile);
|
||||
db_free(zResolved);
|
||||
}else{
|
||||
cmpp_t__err(t, "file not found: %s", zFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void cmpp_dump_defines( FILE * fp, int bIndent ){
|
||||
sqlite3_stmt * const q = g_stmt(GStmt_defSelAll);
|
||||
while( SQLITE_ROW==sqlite3_step(q) ){
|
||||
@@ -2396,7 +2402,7 @@ CmppKeyword aKeywords[] = {
|
||||
{S(Endif), 0, TT_Endif, cmpp_kwd_endif},
|
||||
{S(Error), 0, TT_Error, cmpp_kwd_error},
|
||||
{S(If), 1, TT_If, cmpp_kwd_if},
|
||||
{S(Include), 0, TT_Include, cmpp_kwd_include},
|
||||
{S(Include), 1, TT_Include, cmpp_kwd_include},
|
||||
{S(Pragma), 1, TT_Pragma, cmpp_kwd_pragma},
|
||||
{S(Savepoint), 1, TT_Savepoint, cmpp_kwd_savepoint},
|
||||
{S(Stderr), 0, TT_Stderr, cmpp_kwd_stderr},
|
||||
@@ -2448,14 +2454,25 @@ void cmpp_process_string(const char * zName,
|
||||
g.tok = oldTok;
|
||||
}
|
||||
|
||||
void cmpp_process_file(const char * zName){
|
||||
void cmpp_process_file(const char * zName, int bRaw){
|
||||
FileWrapper fw = FileWrapper_empty;
|
||||
FileWrapper_open(&fw, zName, "r");
|
||||
g_FileWrapper_link(&fw);
|
||||
FileWrapper_slurp(&fw);
|
||||
g_debug(1,("Read %u byte(s) from [%s]\n", fw.nContent, fw.zName));
|
||||
if( fw.zContent ){
|
||||
cmpp_process_string(zName, fw.zContent, fw.nContent);
|
||||
if( bRaw ){
|
||||
FileWrapper fw = FileWrapper_empty;
|
||||
FileWrapper_open(&fw, zName, "rb");
|
||||
g_FileWrapper_link(&fw);
|
||||
FileWrapper_slurp(&fw);
|
||||
if( 1!=fwrite(fw.zContent, fw.nContent, 1, g.out.pFile) ){
|
||||
fatal("fwrite() failed with errno %d\n", errno);
|
||||
}
|
||||
g_FileWrapper_close(&fw);
|
||||
}else{
|
||||
cmpp_process_string(zName, fw.zContent, fw.nContent);
|
||||
}
|
||||
}
|
||||
g_FileWrapper_close(&fw);
|
||||
}
|
||||
@@ -2584,6 +2601,21 @@ static int arg_is_flag( char const *zFlag, char const *zArg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void define_argv(int argc, char const * const * argv){
|
||||
sqlite3_str * const s = sqlite3_str_new(g.db);
|
||||
sqlite3_str_append(s, "c-pp::ARGV=", 11);
|
||||
for( int i = 0; i < argc; ++i ){
|
||||
if( i ) sqlite3_str_appendchar(s, 1, ' ');
|
||||
sqlite3_str_appendf(s, "%s", argv[i]);
|
||||
}
|
||||
char * const z = sqlite3_str_finish(s);
|
||||
assert(z);
|
||||
if(z){
|
||||
db_define_add(z, NULL);
|
||||
sqlite3_free(z);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char const * const * argv){
|
||||
int rc = 0;
|
||||
int inclCount = 0;
|
||||
@@ -2621,6 +2653,7 @@ int main(int argc, char const * const * argv){
|
||||
g.sqlTrace.expandSql = expandMode;
|
||||
}
|
||||
cmpp_initdb();
|
||||
define_argv(argc, argv);
|
||||
}
|
||||
for(int i = 1; i < argc; ++i){
|
||||
int negate = 0;
|
||||
@@ -2678,7 +2711,7 @@ int main(int argc, char const * const * argv){
|
||||
DOIT {
|
||||
++nFile;
|
||||
g_out_open;
|
||||
cmpp_process_file(zVal);
|
||||
cmpp_process_file(zVal, 0);
|
||||
}
|
||||
}
|
||||
ISFLAG("e"){
|
||||
@@ -2761,7 +2794,7 @@ int main(int argc, char const * const * argv){
|
||||
++inclCount;
|
||||
}
|
||||
FileWrapper_open(&g.out, g.out.zName, "w");
|
||||
cmpp_process_file("-");
|
||||
cmpp_process_file("-", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +227,14 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
all args with a space between each. */
|
||||
const toss = (...args)=>{throw new Error(args.join(' '))};
|
||||
|
||||
if( !target.pointerSize && !target.pointerIR
|
||||
&& target.alloc && target.dealloc ){
|
||||
/* Try to determine the pointer size by allocating. */
|
||||
const ptr = target.alloc(1);
|
||||
target.pointerSize = ('bigint'===typeof ptr ? 8 : 4);
|
||||
target.dealloc(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
As of 2025-09-21, this library works with 64-bit WASM modules
|
||||
built with Emscripten's -sMEMORY64=1.
|
||||
@@ -659,12 +667,14 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
const ft = target.functionTable();
|
||||
const oldLen = __asPtrType(ft.length);
|
||||
let ptr;
|
||||
while(cache.freeFuncIndexes.length){
|
||||
ptr = cache.freeFuncIndexes.pop();
|
||||
if(ft.get(ptr)){ /* Table was modified via a different API */
|
||||
while( (ptr = cache.freeFuncIndexes.pop()) ){
|
||||
if(ft.get(ptr)){
|
||||
/* freeFuncIndexes's entry is stale. Table was modified via a
|
||||
different API */
|
||||
ptr = null;
|
||||
continue;
|
||||
}else{
|
||||
/* This index is free. We'll re-use it. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -755,10 +765,9 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
has no side effects and returns undefined.
|
||||
*/
|
||||
target.uninstallFunction = function(ptr){
|
||||
if(!ptr && 0!==ptr) return undefined;
|
||||
const fi = cache.freeFuncIndexes;
|
||||
if(!ptr && __NullPtr!==ptr) return undefined;
|
||||
const ft = target.functionTable();
|
||||
fi.push(ptr);
|
||||
cache.freeFuncIndexes.push(ptr);
|
||||
const rc = ft.get(ptr);
|
||||
ft.set(ptr, null);
|
||||
return rc;
|
||||
@@ -996,12 +1005,12 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
target.heap8u().
|
||||
*/
|
||||
target.cstrlen = function(ptr){
|
||||
if(!ptr || !target.isPtr(ptr)) return null;
|
||||
if(!ptr || !target.isPtr/*64*/(ptr)) return null;
|
||||
ptr = Number(ptr) /*tag:64bit*/;
|
||||
const h = heapWrappers().HEAP8U;
|
||||
let pos = ptr;
|
||||
for( ; h[pos] !== 0; ++pos ){}
|
||||
return Number(pos - ptr);
|
||||
return pos - ptr;
|
||||
};
|
||||
|
||||
/** Internal helper to use in operations which need to distinguish
|
||||
|
||||
+365
-96
@@ -32,7 +32,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
|
||||
if(!(config.heap instanceof WebAssembly.Memory)
|
||||
&& !(config.heap instanceof Function)){
|
||||
toss("config.heap must be WebAssembly.Memory instance or a function.");
|
||||
toss("config.heap must be WebAssembly.Memory instance or a function which returns one.");
|
||||
}
|
||||
['alloc','dealloc'].forEach(function(k){
|
||||
(config[k] instanceof Function) ||
|
||||
@@ -48,14 +48,19 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
memberSuffix = (config.memberSuffix || ""),
|
||||
BigInt = globalThis['BigInt'],
|
||||
BigInt64Array = globalThis['BigInt64Array'],
|
||||
bigIntEnabled = config.bigIntEnabled ?? !!BigInt64Array,
|
||||
ptrIR = config.pointerIR
|
||||
|| config.ptrIR/*deprecated*/
|
||||
|| 'i32',
|
||||
/* Undocumented (on purpose) config options: */
|
||||
ptrSize = config.ptrSize/*deprecated*/
|
||||
|| ('i32'===ptrIR ? 4 : 8)
|
||||
;
|
||||
bigIntEnabled = config.bigIntEnabled ?? !!BigInt64Array;
|
||||
|
||||
//console.warn("config",config);
|
||||
let ptr = alloc(1);
|
||||
const ptrIR = config.pointerIR
|
||||
|| config.ptrIR/*deprecated*/
|
||||
|| ('bigint'===typeof ptr ? 'i64' : 'i32');
|
||||
/* Undocumented (on purpose) config options: */
|
||||
const ptrSize = config.ptrSize/*deprecated*/
|
||||
|| ('i32'===ptrIR ? 4 : 8);
|
||||
dealloc(ptr);
|
||||
ptr = undefined;
|
||||
//console.warn("ptrIR =",ptrIR,"ptrSize =",ptrSize);
|
||||
|
||||
if(ptrIR!=='i32' && ptrIR!=='i64') toss("Invalid pointer representation:",ptrIR);
|
||||
if(ptrSize!==4 && ptrSize!==8) toss("Invalid pointer size:",ptrSize);
|
||||
@@ -136,11 +141,11 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
/** True if SIG s looks like a function signature, else
|
||||
false. */
|
||||
const isFuncSig = (s)=>'('===s[1];
|
||||
/** True if SIG s is-a pointer signature. */
|
||||
const isPtrSig = (s)=>'p'===s || 'P'===s;
|
||||
/** True if SIG s is-a pointer-type signature. */
|
||||
const isPtrSig = (s)=>'p'===s || 'P'===s || 's'===s;
|
||||
const isAutoPtrSig = (s)=>'P'===s /*EXPERIMENTAL*/;
|
||||
/** Returns p if SIG s is a function SIG, else returns s[0]. */
|
||||
const sigLetter = (s)=>isFuncSig(s) ? 'p' : s[0];
|
||||
const sigLetter = (s)=>s ? (isFuncSig(s) ? 'p' : s[0]) : undefined;
|
||||
/** Returns the WASM IR form of the Emscripten-conventional letter
|
||||
at SIG s[0]. Throws for an unknown SIG. */
|
||||
const sigIR = function(s){
|
||||
@@ -154,6 +159,19 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
}
|
||||
toss("Unhandled signature IR:",s);
|
||||
};
|
||||
/** Returns the WASM sizeof of the Emscripten-conventional letter
|
||||
at SIG s[0]. Throws for an unknown SIG. */
|
||||
const sigSize = function(s){
|
||||
switch(sigLetter(s)){
|
||||
case 'c': case 'C': return 1;
|
||||
case 'i': return 4;
|
||||
case 'p': case 'P': case 's': return ptrSize;
|
||||
case 'j': return 8;
|
||||
case 'f': return 4;
|
||||
case 'd': return 8;
|
||||
}
|
||||
toss("Unhandled signature sizeof:",s);
|
||||
};
|
||||
|
||||
const affirmBigIntArray = BigInt64Array
|
||||
? ()=>true : ()=>toss('BigInt64Array is not available.');
|
||||
@@ -232,11 +250,22 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
accessible via boundObject.pointer, which is gated behind a
|
||||
property interceptor, but are not exposed anywhere else in the
|
||||
object.
|
||||
|
||||
This approach means we cannot proxy arrays, or any type which
|
||||
might be realloced, as that pointer could change out from under
|
||||
us. That's not an issue for nested structs, but it might be for a
|
||||
struct they're embedded in. In the case of nested structs we
|
||||
"could" record their top-most parent object and their offset into
|
||||
that object, instead of storing the pointer itself. We could that
|
||||
by allowing a function instead of a pointer in this map, that
|
||||
function returning the (lazily-calculated) address. Hmm.
|
||||
*/
|
||||
const __instancePointerMap = new WeakMap();
|
||||
|
||||
const getInstancePtr = (obj)=>__instancePointerMap.get(obj);
|
||||
|
||||
/** Property name for the pointer-is-external marker. */
|
||||
const xPtrPropName = '(pointer-is-external)';
|
||||
const xPtrPropName = Symbol('(pointer-is-external)');
|
||||
|
||||
const __isPtr32 = (ptr)=>('number'===typeof ptr && (ptr===(ptr|0)) && ptr>=0);
|
||||
const __isPtr64 = (ptr)=>(
|
||||
@@ -252,7 +281,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
/** Frees the obj.pointer memory and clears the pointer
|
||||
property. */
|
||||
const __freeStruct = function(ctor, obj, m){
|
||||
if(!m) m = __instancePointerMap.get(obj);
|
||||
if(!m) m = getInstancePtr(obj);
|
||||
if(m) {
|
||||
__instancePointerMap.delete(obj);
|
||||
if(Array.isArray(obj.ondispose)){
|
||||
@@ -283,7 +312,12 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
ctor.structName,"instance:",
|
||||
ctor.structInfo.sizeof,"bytes @"+m);
|
||||
}
|
||||
if(!obj[xPtrPropName]) dealloc(m);
|
||||
if(!obj[xPtrPropName]){
|
||||
if( ctor.structInfo.zeroOnFree ){
|
||||
heap().fill(0, Number(m), Number(m)+ctor.structInfo.sizeof);
|
||||
}
|
||||
dealloc(m);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -324,8 +358,69 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
: null;
|
||||
};
|
||||
|
||||
/** True if sig looks like an emscripten/jaccwabyt
|
||||
type signature, else false. */
|
||||
const looksLikeASig = function f(sig){
|
||||
f.rxSig1 ??= /^[ipPsjfdcC]$/;
|
||||
f.rxSig2 ??= /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/;
|
||||
return f.rxSig1.test(sig) || f.rxSig2.test(sig);
|
||||
};
|
||||
|
||||
/** Returns a pair of adaptor maps (objects) in a length-3
|
||||
array specific to the given object. */
|
||||
const __adaptorsFor = function(who){
|
||||
let x = this.get(who);
|
||||
if( !x ){
|
||||
x = [ Object.create(null), Object.create(null), Object.create(null) ];
|
||||
this.set(who, x);
|
||||
}
|
||||
return x;
|
||||
}.bind(new WeakMap);
|
||||
|
||||
/** Code de-duplifier for __adaptGet(), __adaptSet(), and
|
||||
__adaptStruct(). */
|
||||
const __adaptor = function(who, which, key, proxy){
|
||||
const a = __adaptorsFor(who)[which];
|
||||
if(3===arguments.length) return a[key];
|
||||
if( proxy ) return a[key] = proxy;
|
||||
return delete a[key];
|
||||
};
|
||||
|
||||
const noopAdapter = (x)=>x;
|
||||
|
||||
// StructBinder::adaptGet()
|
||||
const __adaptGet = function(key, ...args){
|
||||
/*if( looksLikeASig(key) ){
|
||||
toss("Getter adaptor's name (",key,") collides with a data type signature.");
|
||||
}*/
|
||||
return __adaptor(this, 0, key, ...args);
|
||||
};
|
||||
|
||||
// StructBinder::adaptSet()
|
||||
const __adaptSet = function(key, ...args){
|
||||
if( looksLikeASig(key) ){
|
||||
toss("Setter adaptor's name (",key,") collides with a data type signature.");
|
||||
}
|
||||
return __adaptor(this, 1, key, ...args);
|
||||
};
|
||||
|
||||
// StructBinder::adaptStruct()
|
||||
const __adaptStruct = function(key, ...args){
|
||||
return __adaptor(this, 2, key, ...args);
|
||||
};
|
||||
|
||||
const __adaptStruct2 = function(who,key){
|
||||
const si = ('string'===typeof key)
|
||||
? __adaptor(who, 2, key) : key;
|
||||
if( 'object'!==typeof si ){
|
||||
toss("Invalid struct mapping object. Arg =",key,JSON.stringify(si));
|
||||
}
|
||||
return si;
|
||||
};
|
||||
|
||||
const __memberKey = (k)=>memberPrefix + k + memberSuffix;
|
||||
const __memberKeyProp = rop(__memberKey);
|
||||
//const __adaptGetProp = rop(__adaptGet);
|
||||
|
||||
/**
|
||||
Looks up a struct member in structInfo.members. Throws if found
|
||||
@@ -342,7 +437,8 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
if(v.key===memberName){ m = v; break; }
|
||||
}
|
||||
if(!m && tossIfNotFound){
|
||||
toss(sPropName(structInfo.name,memberName),'is not a mapped struct member.');
|
||||
toss(sPropName(structInfo.name || structInfo.structName, memberName),
|
||||
'is not a mapped struct member.');
|
||||
}
|
||||
}
|
||||
return m;
|
||||
@@ -361,7 +457,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
|
||||
const __ptrPropDescriptor = {
|
||||
configurable: false, enumerable: false,
|
||||
get: function(){return __instancePointerMap.get(this)},
|
||||
get: function(){return getInstancePtr(this)},
|
||||
set: ()=>toss("Cannot assign the 'pointer' property of a struct.")
|
||||
// Reminder: leaving `set` undefined makes assignments
|
||||
// to the property _silently_ do nothing. Current unit tests
|
||||
@@ -558,78 +654,176 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
});
|
||||
|
||||
/**
|
||||
Pass this a StructBinder-generated prototype, and the struct
|
||||
member description object. It will define property accessors for
|
||||
proto[memberKey] which read from/write to memory in
|
||||
this.pointer. It modifies descr to make certain downstream
|
||||
operations much simpler.
|
||||
If struct description object si has a getter proxy, return it (a
|
||||
function), else return undefined.
|
||||
*/
|
||||
const makeMemberWrapper = function f(ctor,name, descr){
|
||||
const memberGetterProxy = function(si){
|
||||
return si.get || (si.adaptGet
|
||||
? StructBinder.adaptGet(si.adaptGet)
|
||||
: undefined);
|
||||
};
|
||||
|
||||
/**
|
||||
If struct description object si has a setter proxy, return it (a
|
||||
function), else return undefined.
|
||||
*/
|
||||
const memberSetterProxy = function(si){
|
||||
return si.set || (si.adaptSet
|
||||
? StructBinder.adaptSet(si.adaptSet)
|
||||
: undefined);
|
||||
};
|
||||
|
||||
/**
|
||||
To be called by makeMemberWrapper() when si has a 'members'
|
||||
member, i.e. is an embedded struct. This function sets up that
|
||||
struct like any other and also sets up property accessor for
|
||||
ctor.memberKey(name) which returns an instance of that new
|
||||
StructType when the member is accessed. That instance wraps the
|
||||
memory of the member's part of the containing C struct instance.
|
||||
|
||||
That is, if struct Foo has member bar which is an inner struct
|
||||
then:
|
||||
|
||||
const f = new Foo;
|
||||
const b = f.bar;
|
||||
assert( b is-a StructType object );
|
||||
assert( b.pointer === f.b.pointer );
|
||||
|
||||
b will be disposed of when f() is. Calling b.dispose() will not
|
||||
do any permanent harm, as the wrapper object will be recreated
|
||||
when accessing f.bar, pointing to the same memory in f.
|
||||
|
||||
The si.zeroOnFree flag has no effect on embedded structs because
|
||||
they wrap "external" memory, so do not own it, and are thus never
|
||||
freed, as such.
|
||||
*/
|
||||
const makeMemberStructWrapper = function callee(ctor, name, si){
|
||||
/**
|
||||
Where we store inner-struct member proxies. Keys are a
|
||||
combination of the parent object's pointer address and the
|
||||
property's name. The values are StructType instances.
|
||||
*/
|
||||
const __innerStructs = (callee.innerStructs ??= new Map());
|
||||
const key = ctor.memberKey(name);
|
||||
if( undefined!==si.signature ){
|
||||
toss("'signature' cannot be used on an embedded struct (",
|
||||
ctor.structName,".",key,").");
|
||||
}
|
||||
if( memberSetterProxy(si) ){
|
||||
toss("'set' and 'adaptSet' are not permitted for nested struct members.");
|
||||
}
|
||||
//console.warn("si =",ctor.structName, name, JSON.stringify(si,' '));
|
||||
si.structName ??= ctor.structName+'::'+name;
|
||||
si.key = key;
|
||||
si.name = name;
|
||||
si.constructor = this.call(this, si.structName, si);
|
||||
//console.warn("si.constructor =",si.constructor);
|
||||
//console.warn("si =",si,"ctor=",ctor);
|
||||
const getterProxy = memberGetterProxy(si);
|
||||
const prop = Object.assign(Object.create(null),{
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
set: __propThrowOnSet(ctor/*not si.constructor*/.structName, key),
|
||||
get: function(){
|
||||
const dbg = si.constructor.prototype.debugFlags.__flags;
|
||||
const p = this.pointer;
|
||||
const k = p+'.'+key;
|
||||
let s = __innerStructs.get(k);
|
||||
if(dbg.getter){ log("debug.getter: k =",k); }
|
||||
if( !s ){
|
||||
s = new si.constructor(__ptrAdd(p, si.offset));
|
||||
__innerStructs.set(k, s);
|
||||
this.addOnDispose(()=>s.dispose());
|
||||
s.addOnDispose(()=>__innerStructs.delete(k));
|
||||
//console.warn("Created",k,"proxy");
|
||||
}
|
||||
if(getterProxy) s = getterProxy.apply(this,[s,key]);
|
||||
if(dbg.getter) log("debug.getter: result =",s);
|
||||
return s;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(ctor.prototype, key, prop);
|
||||
}/*makeMemberStructWrapper()*/;
|
||||
|
||||
/**
|
||||
Pass this a StructBinderImpl-generated constructor, a member
|
||||
property name, and the struct member description object. It will
|
||||
define property accessors for proto[memberKey] which read
|
||||
from/write to memory in this.pointer. It modifies si to make
|
||||
certain downstream operations simpler.
|
||||
*/
|
||||
const makeMemberWrapper = function f(ctor, name, si){
|
||||
si = __adaptStruct2(this, si);
|
||||
if( si.members ){
|
||||
return makeMemberStructWrapper.call(this, ctor, name, si);
|
||||
}
|
||||
|
||||
if(!f._){
|
||||
/*cache all available getters/setters/set-wrappers for
|
||||
direct reuse in each accessor function. */
|
||||
/* Cache all available getters/setters/set-wrappers for
|
||||
direct reuse in each accessor function. */
|
||||
f._ = {getters: {}, setters: {}, sw:{}};
|
||||
const a = ['i','c','C','p','P','s','f','d','v()'];
|
||||
if(bigIntEnabled) a.push('j');
|
||||
a.forEach(function(v){
|
||||
//const ir = sigIR(v);
|
||||
f._.getters[v] = sigDVGetter(v) /* DataView[MethodName] values for GETTERS */;
|
||||
f._.setters[v] = sigDVSetter(v) /* DataView[MethodName] values for SETTERS */;
|
||||
f._.sw[v] = sigDVSetWrapper(v) /* BigInt or Number ctor to wrap around values
|
||||
for conversion */;
|
||||
});
|
||||
const rxSig1 = /^[ipPsjfdcC]$/,
|
||||
rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/;
|
||||
f.sigCheck = function(obj, name, key,sig){
|
||||
if(Object.prototype.hasOwnProperty.call(obj, key)){
|
||||
toss(obj.structName,'already has a property named',key+'.');
|
||||
}
|
||||
rxSig1.test(sig) || rxSig2.test(sig)
|
||||
looksLikeASig(sig)
|
||||
|| toss("Malformed signature for",
|
||||
sPropName(obj.structName,name)+":",sig);
|
||||
};
|
||||
}
|
||||
const key = ctor.memberKey(name);
|
||||
f.sigCheck(ctor.prototype, name, key, descr.signature);
|
||||
descr.key = key;
|
||||
descr.name = name;
|
||||
const sigGlyph = sigLetter(descr.signature);
|
||||
f.sigCheck(ctor.prototype, name, key, si.signature);
|
||||
si.key = key;
|
||||
si.name = name;
|
||||
const sigGlyph = sigLetter(si.signature);
|
||||
const xPropName = sPropName(ctor.prototype.structName,key);
|
||||
const dbg = ctor.prototype.debugFlags.__flags;
|
||||
/*
|
||||
TODO?: set prototype of descr to an object which can set/fetch
|
||||
TODO?: set prototype of si to an object which can set/fetch
|
||||
its preferred representation, e.g. conversion to string or mapped
|
||||
function. Advantage: we can avoid doing that via if/else if/else
|
||||
in the get/set methods.
|
||||
*/
|
||||
const getterProxy = memberGetterProxy(si);
|
||||
const prop = Object.create(null);
|
||||
prop.configurable = false;
|
||||
prop.enumerable = false;
|
||||
prop.get = function(){
|
||||
if(dbg.getter){
|
||||
log("debug.getter:",f._.getters[sigGlyph],"for", sigIR(sigGlyph),
|
||||
xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof);
|
||||
xPropName,'@', this.pointer,'+',si.offset,'sz',si.sizeof);
|
||||
}
|
||||
let rc = (
|
||||
new DataView(heap().buffer, Number(this.pointer) + descr.offset, descr.sizeof)
|
||||
new DataView(heap().buffer, Number(this.pointer) + si.offset, si.sizeof)
|
||||
)[f._.getters[sigGlyph]](0, isLittleEndian);
|
||||
if(getterProxy) rc = getterProxy.apply(this,[rc,key]);
|
||||
if(dbg.getter) log("debug.getter:",xPropName,"result =",rc);
|
||||
return rc;
|
||||
};
|
||||
if(descr.readOnly){
|
||||
if(si.readOnly){
|
||||
prop.set = __propThrowOnSet(ctor.prototype.structName,key);
|
||||
}else{
|
||||
const setterProxy = memberSetterProxy(si);
|
||||
prop.set = function(v){
|
||||
if(dbg.setter){
|
||||
log("debug.setter:",f._.setters[sigGlyph],"for", sigIR(sigGlyph),
|
||||
xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof, v);
|
||||
xPropName,'@', this.pointer,'+',si.offset,'sz',si.sizeof, v);
|
||||
}
|
||||
if(!this.pointer){
|
||||
toss("Cannot set struct property on disposed instance.");
|
||||
toss("Cannot set native property on a disposed struct instance.");
|
||||
}
|
||||
if(null===v) v = __NullPtr;
|
||||
else while(!__isPtr(v)){
|
||||
if(isAutoPtrSig(descr.signature) && (v instanceof StructType)){
|
||||
if( setterProxy ) v = setterProxy.apply(this,[v]);
|
||||
if( null===v || undefined===v ) v = __NullPtr;
|
||||
else while( isPtrSig(si.signature) && !__isPtr(v) ){
|
||||
if(isAutoPtrSig(si.signature) && (v instanceof StructType)){
|
||||
// It's a struct instance: let's store its pointer value!
|
||||
v = v.pointer || __NullPtr;
|
||||
if(dbg.setter) log("debug.setter:",xPropName,"resolved to",v);
|
||||
@@ -638,66 +832,45 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
toss("Invalid value for pointer-type",xPropName+'.');
|
||||
}
|
||||
(
|
||||
new DataView(heap().buffer, Number(this.pointer) + descr.offset,
|
||||
descr.sizeof)
|
||||
new DataView(heap().buffer, Number(this.pointer) + si.offset,
|
||||
si.sizeof)
|
||||
)[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian);
|
||||
};
|
||||
}
|
||||
Object.defineProperty(ctor.prototype, key, prop);
|
||||
}/*makeMemberWrapper*/;
|
||||
}/*makeMemberWrapper()*/;
|
||||
|
||||
/**
|
||||
The main factory function which will be returned to the
|
||||
caller.
|
||||
caller. The third argument is structly for internal use.
|
||||
|
||||
This level of indirection is to avoid that clients can pass a
|
||||
third argument to this, as that's only for internal use.
|
||||
|
||||
internalOpt options:
|
||||
|
||||
- None right now. This is for potential use in recursion.
|
||||
|
||||
Usages:
|
||||
|
||||
StructBinder(string, obj [,optObj]);
|
||||
StructBinder(obj);
|
||||
*/
|
||||
const StructBinder = function StructBinder(structName, structInfo){
|
||||
if(1===arguments.length){
|
||||
structInfo = structName;
|
||||
structName = structInfo.name;
|
||||
}else if(!structInfo.name){
|
||||
structInfo.name = structName;
|
||||
}
|
||||
if(!structName) toss("Struct name is required.");
|
||||
let lastMember = false;
|
||||
Object.keys(structInfo.members).forEach((k)=>{
|
||||
// Sanity checks of sizeof/offset info...
|
||||
const m = structInfo.members[k];
|
||||
if(!m.sizeof) toss(structName,"member",k,"is missing sizeof.");
|
||||
else if(m.sizeof===1){
|
||||
(m.signature === 'c' || m.signature === 'C') ||
|
||||
toss("Unexpected sizeof==1 member",
|
||||
sPropName(structInfo.name,k),
|
||||
"with signature",m.signature);
|
||||
}else{
|
||||
// sizes and offsets of size-1 members may be odd values, but
|
||||
// others may not.
|
||||
if(0!==(m.sizeof%4)){
|
||||
console.warn("Invalid struct member description =",m,"from",structInfo);
|
||||
toss(structName,"member",k,"sizeof is not aligned. sizeof="+m.sizeof);
|
||||
}
|
||||
if(0!==(m.offset%4)){
|
||||
console.warn("Invalid struct member description =",m,"from",structInfo);
|
||||
toss(structName,"member",k,"offset is not aligned. offset="+m.offset);
|
||||
}
|
||||
}
|
||||
if(!lastMember || lastMember.offset < m.offset) lastMember = m;
|
||||
});
|
||||
if(!lastMember) toss("No member property descriptions found.");
|
||||
else if(structInfo.sizeof < lastMember.offset+lastMember.sizeof){
|
||||
toss("Invalid struct config:",structName,
|
||||
"max member offset ("+lastMember.offset+") ",
|
||||
"extends past end of struct (sizeof="+structInfo.sizeof+").");
|
||||
}
|
||||
const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags));
|
||||
/** Constructor for the StructCtor. */
|
||||
const zeroAsPtr = __asPtrType(0);
|
||||
const StructBinderImpl = function StructBinderImpl(
|
||||
structName, si, opt = Object.create(null)
|
||||
){
|
||||
/**
|
||||
StructCtor is the eventual return value of this function. We
|
||||
need to populate this early on so that we can do some trickery
|
||||
in feeding it through recursion.
|
||||
*/
|
||||
const StructCtor = function StructCtor(externalMemory){
|
||||
externalMemory = __asPtrType(externalMemory);
|
||||
//console.warn("externalMemory",externalMemory,arguments[0]);
|
||||
if(!(this instanceof StructCtor)){
|
||||
toss("The",structName,"constructor may only be called via 'new'.");
|
||||
}else if(arguments.length){
|
||||
if(Number.isNaN(externalMemory) || externalMemory<=zeroAsPtr){
|
||||
if( !__isPtr(externalMemory) ){
|
||||
toss("Invalid pointer value",arguments[0],"for",structName,"constructor.");
|
||||
}
|
||||
__allocStruct(StructCtor, this, externalMemory);
|
||||
@@ -705,31 +878,127 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
__allocStruct(StructCtor, this);
|
||||
}
|
||||
};
|
||||
const self = this;
|
||||
/**
|
||||
"Convert" struct description x to a struct description, if
|
||||
needed.
|
||||
*/
|
||||
const ads = (x)=>{
|
||||
//console.warn("looksLikeASig(",x,") =",looksLikeASig(x));
|
||||
return (('string'===typeof x) && looksLikeASig(x))
|
||||
? {signature: x} : __adaptStruct2(self,x);
|
||||
};
|
||||
if(1===arguments.length){
|
||||
si = ads(structName);
|
||||
structName = si.structName || si.name;
|
||||
}else if(2===arguments.length){
|
||||
si = ads(si);
|
||||
si.name ??= structName;
|
||||
}else{
|
||||
si = ads(si);
|
||||
}
|
||||
structName ??= si.structName;
|
||||
//console.warn("arguments =",JSON.stringify(arguments));
|
||||
structName ??= opt.structName;
|
||||
if( !structName ) toss("One of 'name' or 'structName' are required.");
|
||||
if( si.adapt ){
|
||||
Object.keys(si.adapt.struct||{}).forEach((k)=>{
|
||||
__adaptStruct.call(StructBinderImpl, k, si.adapt.struct[k]);
|
||||
});
|
||||
Object.keys(si.adapt.set||{}).forEach((k)=>{
|
||||
__adaptSet.call(StructBinderImpl, k, si.adapt.set[k]);
|
||||
});
|
||||
Object.keys(si.adapt.get||{}).forEach((k)=>{
|
||||
__adaptGet.call(StructBinderImpl, k, si.adapt.get[k]);
|
||||
});
|
||||
}
|
||||
if(!si.members && !si.sizeof){
|
||||
si.sizeof = sigSize(si.signature);
|
||||
}
|
||||
|
||||
const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags));
|
||||
Object.defineProperties(StructCtor,{
|
||||
debugFlags: debugFlags,
|
||||
isA: rop((v)=>v instanceof StructCtor),
|
||||
memberKey: __memberKeyProp,
|
||||
memberKeys: __structMemberKeys,
|
||||
methodInfoForKey: rop(function(mKey){
|
||||
}),
|
||||
structInfo: rop(structInfo),
|
||||
//methodInfoForKey: rop(function(mKey){/*???*/}),
|
||||
structInfo: rop(si),
|
||||
structName: rop(structName)
|
||||
});
|
||||
StructCtor.prototype = new StructType(structName, structInfo, rop);
|
||||
StructCtor.prototype = new StructType(structName, si, rop);
|
||||
Object.defineProperties(StructCtor.prototype,{
|
||||
debugFlags: debugFlags,
|
||||
constructor: rop(StructCtor)
|
||||
/*if we assign StructCtor.prototype and don't do
|
||||
this then StructCtor!==instance.constructor!*/
|
||||
this then StructCtor!==instance.constructor*/
|
||||
});
|
||||
Object.keys(structInfo.members).forEach(
|
||||
(name)=>makeMemberWrapper(StructCtor, name, structInfo.members[name])
|
||||
);
|
||||
|
||||
|
||||
let lastMember = false;
|
||||
let offset = 0;
|
||||
//console.warn(structName,"si =",si);
|
||||
si.offset ??= 0;
|
||||
Object.keys(si.members || {}).forEach((k)=>{
|
||||
// Sanity checks of sizeof/offset info...
|
||||
let m = ads(si.members[k]);
|
||||
if(!m.members && !m.sizeof){
|
||||
/* ^^^^ fixme: we need to recursively collect all sizeofs
|
||||
before updating that. */
|
||||
m.sizeof = sigSize(m.signature);
|
||||
if(!m.sizeof){
|
||||
toss(sPropName(structName,k), "is missing a sizeof property.",m);
|
||||
}
|
||||
}
|
||||
if( undefined===m.offset ){
|
||||
m.offset = offset;
|
||||
}
|
||||
si.members[k] = m;
|
||||
if(!lastMember || lastMember.offset < m.offset) lastMember = m;
|
||||
makeMemberWrapper.call(self, StructCtor, k, m)
|
||||
offset += m.sizeof;
|
||||
//console.warn("offset",sPropName(structName,k),offset);
|
||||
});
|
||||
|
||||
if( !lastMember ) toss("No member property descriptions found.");
|
||||
if( !si.sizeof ) si.sizeof = offset;
|
||||
if(si.sizeof===1){
|
||||
(si.signature === 'c' || si.signature === 'C') ||
|
||||
toss("Unexpected sizeof==1 member",
|
||||
sPropName(structName,k),
|
||||
"with signature",si.signature);
|
||||
}else{
|
||||
// sizes and offsets of size-1 members may be odd values, but
|
||||
// others may not.
|
||||
if(0!==(si.sizeof%4)){
|
||||
console.warn("Invalid struct member description",si);
|
||||
toss(structName,"sizeof is not aligned. sizeof="+si.sizeof);
|
||||
}
|
||||
if(0!==(si.offset%4)){
|
||||
console.warn("Invalid struct member description",si);
|
||||
toss(structName,"offset is not aligned. offset="+si.offset);
|
||||
}
|
||||
}
|
||||
|
||||
if( si.sizeof < offset ){
|
||||
console.warn("Suspect struct description:",si,"offset =",offset);
|
||||
toss("Mismatch in the calculated vs. the provided sizeof/offset info.",
|
||||
"Expected sizeof",offset,"but got",si.sizeof,"for",si);
|
||||
}
|
||||
return StructCtor;
|
||||
}/*StructBinderImpl*/;
|
||||
|
||||
const StructBinder = function StructBinder(structName, structInfo){
|
||||
return (1==arguments.length)
|
||||
? StructBinderImpl.call(StructBinder, structName)
|
||||
: StructBinderImpl.call(StructBinder, structName, structInfo);
|
||||
};
|
||||
StructBinder.StructType = StructType;
|
||||
StructBinder.config = config;
|
||||
StructBinder.allocCString = __allocCString;
|
||||
StructBinder.adaptGet = __adaptGet;
|
||||
StructBinder.adaptSet = __adaptSet;
|
||||
StructBinder.adaptStruct = __adaptStruct;
|
||||
if(!StructBinder.debugFlags){
|
||||
StructBinder.debugFlags = SBF.__makeDebugFlags(SBF.debugFlags);
|
||||
}
|
||||
|
||||
+2
-1
@@ -193,8 +193,9 @@ done
|
||||
#
|
||||
# Done copying files. Now zip it up...
|
||||
#
|
||||
svi=${dirTop}/version-info
|
||||
svi=./version-info
|
||||
vnum=$($svi --download-version)
|
||||
[ "" = "$vnum" ] && die "version number is empty!"
|
||||
vdir=${buildName}-${vnum}
|
||||
fzip=${vdir}.zip
|
||||
rm -fr ${vdir} ${fzip}
|
||||
|
||||
+44
-39
@@ -71,13 +71,13 @@ enum BuildDefFlags {
|
||||
** only their JS file and patch their JS to use the WASM file from a
|
||||
** canonical build which uses that same WASM file. Reusing X.wasm
|
||||
** that way can only work for builds which are processed identically
|
||||
** by Emscripten. For a given set of C flags (as opposed to
|
||||
** by Emscripten. For a given set of C flags (as distinct from
|
||||
** JS-influencing flags), all builds of X.js and Y.js will produce
|
||||
** identical X.wasm and Y.wasm files. Their JS files may well
|
||||
** differ, however.
|
||||
*/
|
||||
CP_JS = 1 << 30,
|
||||
CP_WASM = 1 << 31,
|
||||
CP_JS = 1 << 30, /* X.js or X.mjs, depending on F_ESM */
|
||||
CP_WASM = 1 << 31, /* X,wasm */
|
||||
CP_ALL = CP_JS | CP_WASM
|
||||
};
|
||||
|
||||
@@ -94,11 +94,10 @@ enum BuildDefFlags {
|
||||
** final build directory $(dir.dout).
|
||||
**
|
||||
** To keep parallel builds from stepping on each other, each distinct
|
||||
** build goes into its own subdir $(dir.dout.BuildName)[^1], i.e.
|
||||
** $(dir.dout)/BuildName. Builds which produce deliverables we'd like
|
||||
** to keep/distribute copy their final results into the build dir
|
||||
** $(dir.dout). See the notes for the CP_JS enum entry for more
|
||||
** details on that.
|
||||
** build goes into its own subdir $(dir.dout.$(BuildDef::zBaseName).
|
||||
** Builds which produce deliverables we'd like to keep/distribute copy
|
||||
** their final results into the build dir $(dir.dout). See the notes
|
||||
** for the CP_JS enum entry for more details on that.
|
||||
**
|
||||
** The final result of each build is a pair of JS/WASM files, but
|
||||
** getting there requires generation of several files, primarily as
|
||||
@@ -116,9 +115,9 @@ enum BuildDefFlags {
|
||||
**
|
||||
** --extern-post-js = gets injected immediately after
|
||||
** sqlite3InitModule(), in the global scope. In this step we replace
|
||||
** sqlite3InitModule() with a slightly customized, the main purpose of
|
||||
** which is to (A) give us (not Emscripten) control over the arguments
|
||||
** it accepts and (B) to run the library bootstrap step.
|
||||
** sqlite3InitModule() with a slightly customized one, the main
|
||||
** purpose of which is to (A) give us (not Emscripten) control over
|
||||
** the arguments it accepts and (B) to run the library bootstrap step.
|
||||
**
|
||||
** Then there's sqlite3-api.BuildName.js, which is the entire SQLite3
|
||||
** JS API (generated from the list defined in $(sqlite3-api.jses)). It
|
||||
@@ -126,9 +125,7 @@ enum BuildDefFlags {
|
||||
**
|
||||
** Each of those inputs has to be generated before passing them on to
|
||||
** Emscripten so that any build-specific capabilities can get filtered
|
||||
** in or out (using ./c-pp.c).
|
||||
**
|
||||
** [^1]: The legal BuildNames are in this file's BuildDef_map macro.
|
||||
** in or out (using ./c-pp-lite.c).
|
||||
*/
|
||||
struct BuildDef {
|
||||
/*
|
||||
@@ -143,8 +140,8 @@ struct BuildDef {
|
||||
**
|
||||
** The convention for 32- vs 64-bit pairs is to give them similar
|
||||
** emoji, e.g. a cookie for 32-bit and a donut or cake for 64.
|
||||
** Alternately, the same emoji a "64" suffix, excep that that throws
|
||||
** off the output alignment in parallel builds ;).
|
||||
** Alternately, the same emoji a "64" suffix, except that that
|
||||
** throws off the output alignment in parallel builds ;).
|
||||
*/
|
||||
const char *zEmo;
|
||||
/*
|
||||
@@ -161,7 +158,7 @@ struct BuildDef {
|
||||
const char *zCmppD; /* Extra -D... flags for c-pp */
|
||||
const char *zEmcc; /* Full flags for emcc. Normally NULL for default. */
|
||||
const char *zEmccExtra; /* Extra flags for emcc */
|
||||
const char *zDeps; /* Extra deps */
|
||||
const char *zDeps; /* Extra make target deps */
|
||||
const char *zEnv; /* emcc -sENVIRONMENT=... value */
|
||||
/*
|
||||
** Makefile code "ifeq (...)". If set, this build is enclosed in a
|
||||
@@ -196,9 +193,8 @@ typedef struct BuildDef BuildDef;
|
||||
** The set of WASM builds for the library (as opposed to the apps
|
||||
** (fiddle, speedtest1)). Their order in BuildDefs_map is mostly
|
||||
** insignificant, but some makefile vars used by some builds are set
|
||||
** up by prior builds. Because of that, the (sqlite3, vanilla),
|
||||
** (sqlite3, esm), and (sqlite3, bundler-friendly) builds should be
|
||||
** defined first (in that order).
|
||||
** up by prior builds. Because of that, the vanilla, esm, and
|
||||
** bundler-friendly builds should be defined first (in that order).
|
||||
*/
|
||||
struct BuildDefs {
|
||||
#define E(N) BuildDef N;
|
||||
@@ -284,7 +280,7 @@ const BuildDefs oBuildDefs = {
|
||||
" -DSQLITE_SPEEDTEST1_WASM"
|
||||
" $(SQLITE_OPT)"
|
||||
" -USQLITE_WASM_BARE_BONES"
|
||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c)"
|
||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.c)"
|
||||
" $(speedtest1.exit-runtime0)"
|
||||
" $(speedtest1.c.in)"
|
||||
" -lm",
|
||||
@@ -312,7 +308,7 @@ const BuildDefs oBuildDefs = {
|
||||
" -DSQLITE_SPEEDTEST1_WASM"
|
||||
" $(SQLITE_OPT)"
|
||||
" -USQLITE_WASM_BARE_BONES"
|
||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c)"
|
||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.c)"
|
||||
" $(speedtest1.exit-runtime0)"
|
||||
" $(speedtest1.c.in)"
|
||||
" -lm",
|
||||
@@ -346,7 +342,6 @@ const BuildDefs oBuildDefs = {
|
||||
.zDeps = 0,
|
||||
.zIfCond = 0,
|
||||
.flags = CP_JS | F_BUNDLER_FRIENDLY | F_ESM
|
||||
//| F_NOT_IN_ALL
|
||||
},
|
||||
|
||||
/* 64-bit bundler-friendly. */
|
||||
@@ -371,7 +366,7 @@ const BuildDefs oBuildDefs = {
|
||||
.node = {
|
||||
.zEmo = "🍟",
|
||||
.zBaseName = "sqlite3-node",
|
||||
.zDotWasm = 0,
|
||||
.zDotWasm = "sqlite3",
|
||||
.zCmppD = "-Dtarget:node $(c-pp.D.bundler)",
|
||||
.zEmcc = 0,
|
||||
.zEmccExtra = 0,
|
||||
@@ -382,21 +377,21 @@ const BuildDefs oBuildDefs = {
|
||||
** node. */,
|
||||
.zDeps = 0,
|
||||
.zIfCond = 0,
|
||||
.flags = CP_ALL | F_UNSUPPORTED | F_NODEJS
|
||||
.flags = CP_JS | F_UNSUPPORTED | F_ESM | F_NODEJS
|
||||
},
|
||||
|
||||
/* 64-bit node. */
|
||||
.node64 = {
|
||||
.zEmo = "🍔",
|
||||
.zBaseName = "sqlite3-node-64bit",
|
||||
.zDotWasm = 0,
|
||||
.zDotWasm = "sqlite3-64bit",
|
||||
.zCmppD = "-Dtarget:node $(c-pp.D.bundler)",
|
||||
.zEmcc = 0,
|
||||
.zEmccExtra = 0,
|
||||
.zEnv = "node",
|
||||
.zDeps = 0,
|
||||
.zIfCond = 0,
|
||||
.flags = CP_ALL | F_UNSUPPORTED | F_NODEJS | F_64BIT
|
||||
.flags = CP_JS | F_UNSUPPORTED | F_ESM | F_NODEJS | F_64BIT
|
||||
},
|
||||
|
||||
/* Entirely unsupported. */
|
||||
@@ -444,6 +439,11 @@ static void mk_prologue(void){
|
||||
ps("endif");
|
||||
}
|
||||
|
||||
ps("define label.unsupported-build\n"
|
||||
"$(emo.fire)$(emo.fire)$(emo.fire)Unsupported build:"
|
||||
" use at your own risk!\n"
|
||||
"endef");
|
||||
|
||||
ps(zBanner
|
||||
/** $1 = build name */
|
||||
"b.call.wasm-strip = "
|
||||
@@ -624,7 +624,8 @@ static void mk_pre_post(char const *zBuildName, BuildDef const * pB){
|
||||
** Module.instantiateWasm() to use that file instead of
|
||||
** the default.
|
||||
*/
|
||||
pf("$(pre-js.%s.js): $(pre-js.in.js) $(MAKEFILE_LIST)", zBuildName);
|
||||
pf("$(pre-js.%s.js): $(pre-js.in.js) $(bin.c-pp) $(MAKEFILE_LIST)",
|
||||
zBuildName);
|
||||
if( pB->zDotWasm ){
|
||||
pf(" $(dir.dout)/%s.wasm" /* This .wasm is from some other
|
||||
build, so this may trigger a full
|
||||
@@ -632,7 +633,7 @@ static void mk_pre_post(char const *zBuildName, BuildDef const * pB){
|
||||
pB->zDotWasm);
|
||||
}
|
||||
ps("");
|
||||
pf("\t@$(call b.c-pp.shcmd,"
|
||||
pf("\t@$(call b.mkdir@); $(call b.c-pp.shcmd,"
|
||||
"%s,"
|
||||
"$(pre-js.in.js),"
|
||||
"$(pre-js.%s.js),"
|
||||
@@ -658,7 +659,7 @@ static void mk_pre_post(char const *zBuildName, BuildDef const * pB){
|
||||
"))\n",
|
||||
zBuildName, zBuildName, zBuildName, zBuildName);
|
||||
|
||||
pf("$(post-js.%s.js): $(post-js.%s.in)\n",
|
||||
pf("$(post-js.%s.js): $(post-js.%s.in) $(bin.c-pp)\n",
|
||||
zBuildName, zBuildName);
|
||||
|
||||
ps("\n# --extern-post-js=...");
|
||||
@@ -771,13 +772,14 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){
|
||||
zBuildName, zBuildName, zBaseName);
|
||||
|
||||
pf("dir.dout.%s ?= $(dir.dout)/%s\n", zBuildName, zBuildName);
|
||||
pf("out.%s.base ?= $(dir.dout.%s)/%s\n",
|
||||
zBuildName, zBuildName, zBaseName);
|
||||
|
||||
pf("c-pp.D.%s ?= %s\n", zBuildName, pB->zCmppD ? pB->zCmppD : "");
|
||||
if( pB->flags & F_64BIT ){
|
||||
pf("c-pp.D.%s += $(c-pp.D.64bit)\n", zBuildName);
|
||||
}
|
||||
if( pB->flags & F_UNSUPPORTED ){
|
||||
pf("c-pp.D.%s += -Dunsupported-build\n", zBuildName);
|
||||
}
|
||||
|
||||
pf("emcc.environment.%s ?= %s\n", zBuildName,
|
||||
pB->zEnv ? pB->zEnv : oBuildDefs.vanilla.zEnv);
|
||||
@@ -803,8 +805,8 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){
|
||||
emit_compile_start(zBuildName);
|
||||
|
||||
if( F_UNSUPPORTED & pB->flags ){
|
||||
pf("\t@echo '$(logtag.%s) $(emo.fire)$(emo.fire)$(emo.fire): "
|
||||
"unsupported build. Use at your own risk.'\n", zBuildName);
|
||||
pf("\t@echo '$(logtag.%s) $(label.unsupported-build)'\n",
|
||||
zBuildName);
|
||||
}
|
||||
|
||||
/* emcc ... */
|
||||
@@ -900,14 +902,17 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){
|
||||
|
||||
}
|
||||
}
|
||||
pf("\t@$(call b.echo,%s,$(emo.done) done!)\n", zBuildName);
|
||||
pf("\t@$(call b.echo,%s,$(emo.done) done!%s)\n",
|
||||
zBuildName,
|
||||
(F_UNSUPPORTED & pB->flags)
|
||||
? " $(label.unsupported-build)"
|
||||
: "");
|
||||
|
||||
pf("\n%dbit: $(out.%s.js)\n"
|
||||
"$(out.%s.wasm): $(out.%s.js)\n"
|
||||
"b-%s: $(out.%s.js) $(out.%s.wasm)\n",
|
||||
"b-%s: $(out.%s.wasm)\n",
|
||||
(F_64BIT & pB->flags) ? 64 : 32, zBuildName,
|
||||
zBuildName, zBuildName,
|
||||
zBuildName, zBuildName, zBuildName);
|
||||
zBuildName, zBuildName, zBuildName, zBuildName);
|
||||
|
||||
if( CP_JS & pB->flags ){
|
||||
pf("$(dir.dout)/%s%s: $(out.%s.js)\n",
|
||||
@@ -982,7 +987,7 @@ static void mk_fiddle(void){
|
||||
zBuildName, zBuildName);
|
||||
emit_compile_start(zBuildName);
|
||||
pf("\t$(b.cmd@)$(bin.emcc) -o $@"
|
||||
" $(emcc.flags.%s)" /* set in fiddle.make */
|
||||
" $(emcc.flags.%s)" /* set in GNUmakefile */
|
||||
" $(pre-post.%s.flags)"
|
||||
" $(fiddle.c.in)"
|
||||
"\n",
|
||||
|
||||
@@ -12,11 +12,19 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1 id='color-target'>sqlite3 tester #1: Worker thread (@bitness@-bit WASM)</h1>
|
||||
<div>Variants:
|
||||
<a href='tester1.html' target='tester1.html'>conventional UI thread</a>,
|
||||
<a href='tester1-worker.html' target='tester1-worker.html'>conventional worker</a>,
|
||||
<a href='tester1-esm.html' target='tester1-esm.html'>ESM in UI thread</a>,
|
||||
<a href='tester1-worker.html?esm' target='tester1-worker.html?esm'>ESM worker</a>
|
||||
<div>Variants (32-bit):
|
||||
conventional UI thread:
|
||||
(<a href='tester1.html' target='tester1.html'>32-bit</a>,
|
||||
<a href='tester1-64bit.html' target='tester1-64bit.html'>64-bit</a>),
|
||||
conventional worker:
|
||||
(<a href='tester1-worker.html' target='tester1-worker.html'>32-bit</a>,
|
||||
<a href='tester1-worker-64bit.html' target='tester1-worker-64bit.html'>64-bit</a>),
|
||||
ESM in UI thread:
|
||||
(<a href='tester1-esm.html' target='tester1-esm.html'>32-bit</a>,
|
||||
<a href='tester1-esm-64bit.html' target='tester1-esm-64bit.html'>64-bit</a>),
|
||||
ESM worker:</a>
|
||||
(<a href='tester1-worker.html?esm' target='tester1-worker.html?esm'>32-bit</a>
|
||||
<a href='tester1-worker-64bit.html?esm' target='tester1-worker-64bit.html?esm'>64-bit</a>)
|
||||
</div>
|
||||
<div class='input-wrapper'>
|
||||
<input type='checkbox' id='cb-log-reverse'>
|
||||
|
||||
@@ -11,11 +11,19 @@
|
||||
<style></style>
|
||||
</head>
|
||||
<body><h1 id='color-target'></h1>
|
||||
<div>Variants:
|
||||
<a href='tester1.html' target='tester1.html'>conventional UI thread</a>,
|
||||
<a href='tester1-worker.html' target='tester1-worker.html'>conventional worker</a>,
|
||||
<a href='tester1-esm.html' target='tester1-esm.html'>ESM in UI thread</a>,
|
||||
<a href='tester1-worker.html?esm' target='tester1-worker.html?esm'>ESM worker</a>
|
||||
<div>Variants (32-bit):
|
||||
conventional UI thread:
|
||||
(<a href='tester1.html' target='tester1.html'>32-bit</a>,
|
||||
<a href='tester1-64bit.html' target='tester1-64bit.html'>64-bit</a>),
|
||||
conventional worker:
|
||||
(<a href='tester1-worker.html' target='tester1-worker.html'>32-bit</a>,
|
||||
<a href='tester1-worker-64bit.html' target='tester1-worker-64bit.html'>64-bit</a>),
|
||||
ESM in UI thread:
|
||||
(<a href='tester1-esm.html' target='tester1-esm.html'>32-bit</a>,
|
||||
<a href='tester1-esm-64bit.html' target='tester1-esm-64bit.html'>64-bit</a>),
|
||||
ESM worker:</a>
|
||||
(<a href='tester1-worker.html?esm' target='tester1-worker.html?esm'>32-bit</a>
|
||||
<a href='tester1-worker-64bit.html?esm' target='tester1-worker-64bit.html?esm'>64-bit</a>)
|
||||
</div>
|
||||
<div class='input-wrapper'>
|
||||
<input type='checkbox' id='cb-log-reverse'>
|
||||
|
||||
+181
-104
@@ -369,6 +369,88 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
clearOnInit: true,
|
||||
initialCapacity: 6
|
||||
};
|
||||
|
||||
//#if enable-see
|
||||
/**
|
||||
Code consolidator for SEE sanity checks for various VFSes. ctor
|
||||
is the VFS's oo1.DB-type constructor. ctorOptFunc(bool) is a
|
||||
function which must return a constructor args object for ctor. It
|
||||
is passed true if the db needs to be cleaned up/unlinked before
|
||||
opening it (OPFS) and false if not (how that is done is
|
||||
VFS-dependent). dbUnlink is a function which is expected to
|
||||
unlink() the db file if the ctorOpfFunc does not do so when
|
||||
passed true (kvvfs).
|
||||
|
||||
This function initializes the db described by ctorOptFunc(...),
|
||||
writes some secret info into it, and re-opens it twice to
|
||||
confirmi that it can be read with an SEE key and cannot be read
|
||||
without one.
|
||||
*/
|
||||
T.seeBaseCheck = function(ctor, ctorOptFunc, dbUnlink){
|
||||
let initDb = true;
|
||||
const tryKey = function(keyKey, key, expectCount){
|
||||
let db;
|
||||
//console.debug('tryKey()',arguments);
|
||||
try {
|
||||
if (initDb) {
|
||||
const ctoropt = ctorOptFunc(initDb);
|
||||
initDb = false;
|
||||
db = new ctor({
|
||||
...ctoropt,
|
||||
[keyKey]: key
|
||||
});
|
||||
db.exec([
|
||||
"drop table if exists t;",
|
||||
"create table t(a);"
|
||||
]);
|
||||
db.close();
|
||||
db = null;
|
||||
// Ensure that it's actually encrypted...
|
||||
let err;
|
||||
try {
|
||||
db = new ctor(ctorOptFunc(false));
|
||||
T.assert(db, 'db opened') /* opening is fine, but... */;
|
||||
db.exec("select 1 from sqlite_schema");
|
||||
console.warn("(should not be reached) sessionStorage =", sessionStorage);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
} finally {
|
||||
db.close()
|
||||
db = null;
|
||||
}
|
||||
T.assert(err, "Expecting an exception")
|
||||
.assert(capi.SQLITE_NOTADB == err.resultCode,
|
||||
"Expecting NOTADB");
|
||||
}/*initDb*/
|
||||
db = new ctor({
|
||||
...ctorOptFunc(false),
|
||||
[keyKey]: key
|
||||
});
|
||||
db.exec("insert into t(a) values (1),(2)");
|
||||
T.assert(expectCount === db.selectValue('select sum(a) from t'));
|
||||
} finally {
|
||||
if (db) db.close();
|
||||
}
|
||||
};
|
||||
const hexFoo = new Uint8Array([0x66,0x6f,0x6f]/*=="foo"*/);
|
||||
dbUnlink();
|
||||
tryKey('textkey', 'foo', 3);
|
||||
T.assert( !initDb );
|
||||
tryKey('textkey', 'foo', 6);
|
||||
dbUnlink();
|
||||
initDb = true;
|
||||
tryKey('key', 'foo', 3);
|
||||
T.assert( !initDb );
|
||||
tryKey('key', hexFoo, 6);
|
||||
dbUnlink();
|
||||
initDb = true;
|
||||
tryKey('hexkey', hexFoo, 3);
|
||||
T.assert( !initDb );
|
||||
tryKey('hexkey', hexFoo, 6);
|
||||
dbUnlink();
|
||||
},
|
||||
//#endif enable-see
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// End of infrastructure setup. Now define the tests...
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -945,7 +1027,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
let ptr = k1.pointer;
|
||||
k1.dispose();
|
||||
T.assert(undefined === k1.pointer).
|
||||
mustThrowMatching(()=>{k1.$pP=1}, /disposed instance/);
|
||||
mustThrowMatching(()=>{k1.$pP=1}, /disposed struct instance/);
|
||||
}finally{
|
||||
k1.dispose();
|
||||
k2.dispose();
|
||||
@@ -1549,6 +1631,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
T.assert(blob instanceof Uint8Array).
|
||||
assert(0x68===blob[0] && 0x69===blob[1]);
|
||||
blob = null;
|
||||
blob = db.selectValue("select ?1", new Uint8Array([97,0,98,0,99]),
|
||||
sqlite3.capi.SQLITE_TEXT);
|
||||
T.assert("a\0b\0c"===blob, "Something is amiss with embedded NULs");
|
||||
let counter = 0, colNames = [];
|
||||
list.length = 0;
|
||||
db.exec(new TextEncoder('utf-8').encode("SELECT a a, b b FROM t"),{
|
||||
@@ -2836,71 +2921,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
predicate: ()=>(isUIThread()
|
||||
|| "Only available in main thread."),
|
||||
test: function(sqlite3){
|
||||
this.kvvfsUnlink();
|
||||
let initDb = true;
|
||||
const tryKey = function(keyKey, key, expectCount){
|
||||
let db;
|
||||
//console.debug('tryKey()',arguments);
|
||||
const ctoropt = {
|
||||
filename: this.kvvfsDbFile
|
||||
//vfs: 'kvvfs'
|
||||
//,flags: 'ct'
|
||||
};
|
||||
try {
|
||||
if (initDb) {
|
||||
initDb = false;
|
||||
db = new this.JDb({
|
||||
...ctoropt,
|
||||
[keyKey]: key
|
||||
});
|
||||
db.exec([
|
||||
"drop table if exists t;",
|
||||
"create table t(a);"
|
||||
]);
|
||||
db.close();
|
||||
// Ensure that it's actually encrypted...
|
||||
let err;
|
||||
try {
|
||||
db = new this.JDb(ctoropt);
|
||||
T.assert(db, 'db opened') /* opening is fine, but... */;
|
||||
db.exec("select 1 from sqlite_schema");
|
||||
console.warn("(should not be reached) sessionStorage =", sessionStorage);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
} finally {
|
||||
db.close()
|
||||
}
|
||||
T.assert(err, "Expecting an exception")
|
||||
.assert(sqlite3.capi.SQLITE_NOTADB == err.resultCode,
|
||||
"Expecting NOTADB");
|
||||
}/*initDb*/
|
||||
//console.debug('tryKey()',arguments);
|
||||
db = new sqlite3.oo1.DB({
|
||||
...ctoropt,
|
||||
vfs: 'kvvfs',
|
||||
[keyKey]: key
|
||||
});
|
||||
db.exec("insert into t(a) values (1),(2)");
|
||||
T.assert(expectCount === db.selectValue('select sum(a) from t'));
|
||||
} finally {
|
||||
if (db) db.close();
|
||||
}
|
||||
}.bind(this);
|
||||
const hexFoo = new Uint8Array([0x66,0x6f,0x6f]/*=="foo"*/);
|
||||
tryKey('textkey', 'foo', 3);
|
||||
T.assert( !initDb );
|
||||
tryKey('textkey', 'foo', 6);
|
||||
this.kvvfsUnlink();
|
||||
initDb = true;
|
||||
tryKey('key', 'foo', 3);
|
||||
T.assert( !initDb );
|
||||
tryKey('key', hexFoo, 6);
|
||||
this.kvvfsUnlink();
|
||||
initDb = true;
|
||||
tryKey('hexkey', hexFoo, 3);
|
||||
T.assert( !initDb );
|
||||
tryKey('hexkey', hexFoo, 6);
|
||||
this.kvvfsUnlink();
|
||||
T.seeBaseCheck(sqlite3.oo1.JsStorageDb, (isInit)=>{
|
||||
return {filename: "session"};
|
||||
}, ()=>this.kvvfsUnlink());
|
||||
}
|
||||
})/*kvvfs with SEE*/
|
||||
//#endif enable-see
|
||||
@@ -3311,6 +3334,21 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
"entryExists(",testDir,") should have failed");
|
||||
}
|
||||
}/*OPFS util sanity checks*/)
|
||||
//#if enable-see
|
||||
.t({
|
||||
name: 'OPFS with SEE encryption',
|
||||
test: function(sqlite3){
|
||||
T.seeBaseCheck(
|
||||
sqlite3.oo1.OpfsDb,
|
||||
function(isInit){
|
||||
const opt = {filename: 'file:///sqlite3-see.edb'};
|
||||
if( isInit ) opt.filename += '?delete-before-open=1';
|
||||
return opt;
|
||||
},
|
||||
()=>{});
|
||||
}
|
||||
})/*OPFS with SEE*/
|
||||
//#endif enable-see
|
||||
;/* end OPFS tests */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -3492,7 +3530,36 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
.assert(true === await u3.removeVfs())
|
||||
.assert(false === await P3b.removeVfs());
|
||||
}
|
||||
}/*OPFS SAH Pool sanity checks*/);
|
||||
}/*OPFS SAH Pool sanity checks*/)
|
||||
//#if enable-see
|
||||
.t({
|
||||
name: 'OPFS SAHPool with SEE encryption',
|
||||
test: async function(sqlite3){
|
||||
const inst = sqlite3.installOpfsSAHPoolVfs,
|
||||
catcher = (e)=>{
|
||||
error("Cannot load SAH pool VFS.",
|
||||
"This might not be a problem,",
|
||||
"depending on the environment.");
|
||||
return false;
|
||||
};
|
||||
const poolConfig = {
|
||||
name: 'opfs-sahpool-see',
|
||||
clearOnInit: true,
|
||||
initialCapacity: 6
|
||||
}
|
||||
let poolUtil;
|
||||
const P1 = await inst(poolConfig).then(u=>poolUtil = u).catch(catcher);
|
||||
const dbFile = '/sqlite3-see.edb';
|
||||
T.seeBaseCheck(
|
||||
poolUtil.OpfsSAHPoolDb,
|
||||
(isInit)=>{return {filename: dbFile}},
|
||||
()=>poolUtil.unlink(dbFile)
|
||||
);
|
||||
poolUtil.removeVfs();
|
||||
}
|
||||
})/*opfs-sahpool with SEE*/
|
||||
//#endif enable-see
|
||||
;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
T.g('Misc. APIs')
|
||||
@@ -3556,44 +3623,54 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
.t("Misc. stmt_...", function(sqlite3){
|
||||
const db = new sqlite3.oo1.DB();
|
||||
db.exec("create table t(a doggiebiscuits); insert into t(a) values(123)");
|
||||
const stmt = db.prepare("select a, a+1 from t");
|
||||
T.assert( stmt.isReadOnly() )
|
||||
.assert( 0===capi.sqlite3_stmt_isexplain(stmt) )
|
||||
.assert( 0===capi.sqlite3_stmt_explain(stmt, 1) )
|
||||
.assert( 0!==capi.sqlite3_stmt_isexplain(stmt) )
|
||||
.assert( 0===capi.sqlite3_stmt_explain(stmt, 2) )
|
||||
.assert( 0!==capi.sqlite3_stmt_isexplain(stmt) )
|
||||
.assert( 0===capi.sqlite3_stmt_explain(stmt, 0) )
|
||||
.assert( 0===capi.sqlite3_stmt_isexplain(stmt) );
|
||||
let n = 0;
|
||||
while( capi.SQLITE_ROW === capi.sqlite3_step(stmt) ){
|
||||
++n;
|
||||
T.assert( 0!==capi.sqlite3_stmt_explain(stmt, 1),
|
||||
"Because stmt is busy" )
|
||||
.assert( capi.sqlite3_stmt_busy(stmt) )
|
||||
.assert( stmt.isBusy() )
|
||||
.assert( 0!==capi.sqlite3_stmt_readonly(stmt) )
|
||||
.assert( true===stmt.isReadOnly() );
|
||||
const sv = capi.sqlite3_column_value(stmt, 0);
|
||||
T.assert( 123===capi.sqlite3_value_int(sv) )
|
||||
.assert( "doggiebiscuits"===capi.sqlite3_column_decltype(stmt,0) )
|
||||
.assert( null===capi.sqlite3_column_decltype(stmt,1) );
|
||||
let stmt;
|
||||
try{
|
||||
stmt = db.prepare("select a, a+1 from t");
|
||||
T.assert( stmt.isReadOnly() )
|
||||
.assert( 0===capi.sqlite3_stmt_isexplain(stmt) )
|
||||
.assert( 0===capi.sqlite3_stmt_explain(stmt, 1) )
|
||||
.assert( 0!==capi.sqlite3_stmt_isexplain(stmt) )
|
||||
.assert( 0===capi.sqlite3_stmt_explain(stmt, 2) )
|
||||
.assert( 0!==capi.sqlite3_stmt_isexplain(stmt) )
|
||||
.assert( 0===capi.sqlite3_stmt_explain(stmt, 0) )
|
||||
.assert( 0===capi.sqlite3_stmt_isexplain(stmt) );
|
||||
let n = 0;
|
||||
while( capi.SQLITE_ROW === capi.sqlite3_step(stmt) ){
|
||||
++n;
|
||||
T.assert( 0!==capi.sqlite3_stmt_explain(stmt, 1),
|
||||
"Because stmt is busy" )
|
||||
.assert( capi.sqlite3_stmt_busy(stmt) )
|
||||
.assert( stmt.isBusy() )
|
||||
.assert( 0!==capi.sqlite3_stmt_readonly(stmt) )
|
||||
.assert( true===stmt.isReadOnly() );
|
||||
const sv = capi.sqlite3_column_value(stmt, 0);
|
||||
T.assert( 123===capi.sqlite3_value_int(sv) )
|
||||
.assert( "doggiebiscuits"===capi.sqlite3_column_decltype(stmt,0) )
|
||||
.assert( null===capi.sqlite3_column_decltype(stmt,1) );
|
||||
}
|
||||
T.assert( 1===n )
|
||||
.assert( 0===capi.sqlite3_stmt_busy(stmt) )
|
||||
.assert( !stmt.isBusy() );
|
||||
|
||||
if( wasm.exports.sqlite3_column_origin_name ){
|
||||
log("Column metadata APIs enabled");
|
||||
T.assert( "t" === capi.sqlite3_column_table_name(stmt, 0))
|
||||
.assert("a" === capi.sqlite3_column_origin_name(stmt, 0))
|
||||
.assert("main" === capi.sqlite3_column_database_name(stmt, 0))
|
||||
}else{
|
||||
log("Column metadata APIs not enabled");
|
||||
} // column metadata APIs
|
||||
stmt.finalize();
|
||||
stmt = null;
|
||||
stmt = db.prepare("select ?1").bind(new Uint8Array([97,0,98,0,99]));
|
||||
stmt.step();
|
||||
const sv = capi.sqlite3_column_value(stmt,0);
|
||||
T.assert("a\0b\0c"===capi.sqlite3_value_text(sv),
|
||||
"Expecting NULs to have survived.");
|
||||
}finally{
|
||||
if(stmt) stmt.finalize();
|
||||
db.close();
|
||||
}
|
||||
T.assert( 1===n )
|
||||
.assert( 0===capi.sqlite3_stmt_busy(stmt) )
|
||||
.assert( !stmt.isBusy() );
|
||||
|
||||
if( wasm.exports.sqlite3_column_origin_name ){
|
||||
log("Column metadata APIs enabled");
|
||||
T.assert( "t" === capi.sqlite3_column_table_name(stmt, 0))
|
||||
.assert("a" === capi.sqlite3_column_origin_name(stmt, 0))
|
||||
.assert("main" === capi.sqlite3_column_database_name(stmt, 0))
|
||||
}else{
|
||||
log("Column metadata APIs not enabled");
|
||||
} // column metadata APIs
|
||||
|
||||
stmt.finalize();
|
||||
db.close();
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -952,25 +952,6 @@ FUZZDATA = \
|
||||
#
|
||||
TESTOPTS = --verbose=file --output=test-out.txt
|
||||
|
||||
#
|
||||
# Extra compiler options for various shell tools
|
||||
#
|
||||
# Note that some of these will only apply when embedding sqlite3.c
|
||||
# into the shell, as these flags are not otherwise passed on to the
|
||||
# library.
|
||||
SHELL_OPT += -DSQLITE_DQS=0
|
||||
SHELL_OPT += -DSQLITE_ENABLE_FTS4
|
||||
#SHELL_OPT += -DSQLITE_ENABLE_FTS5
|
||||
SHELL_OPT += -DSQLITE_ENABLE_RTREE
|
||||
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
SHELL_OPT += -DSQLITE_ENABLE_PERCENTILE
|
||||
SHELL_OPT += -DSQLITE_STRICT_SUBTYPE=1
|
||||
FUZZERSHELL_OPT =
|
||||
FUZZCHECK_OPT += -I$(TOP)/test
|
||||
FUZZCHECK_OPT += -I$(TOP)/ext/recover
|
||||
@@ -2154,11 +2135,6 @@ threadtest5: sqlite3.c $(TOP)/test/threadtest5.c
|
||||
$(T.link) $(TOP)/test/threadtest5.c sqlite3.c -o $@ $(LDFLAGS.libsqlite3)
|
||||
xbin: threadtest5
|
||||
|
||||
resfmt-test: sqlite3.o $(TOP)/ext/misc/resfmt-tester.c $(TOP)/ext/misc/resfmt.c $(TOP)/ext/misc/resfmt.h
|
||||
$(T.link) -I$(TOP)/ext/misc -I. \
|
||||
$(TOP)/ext/misc/resfmt-tester.c $(TOP)/ext/misc/resfmt.c sqlite3.o \
|
||||
-o $@ $(LDFLAGS.libsqlite3)
|
||||
|
||||
#
|
||||
# STATIC_CLI_SHELL = 1 to statically link sqlite3$(T.exe), else
|
||||
# 0. Requires static versions of all requisite libraries. Primarily
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
C Fix\sa\sva_list\smisuse.
|
||||
D 2025-10-22T12:38:39.500
|
||||
C Pervent\sthe\sparser\sstack\sfrom\sgrowing\sto\sbe\slarger\sthan\s100\splus\sfour\stimes\nthe\sSQLITE_LIMIT_EXPR_DEPTH\ssetting.
|
||||
D 2025-11-18T02:24:46.688
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
|
||||
F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d
|
||||
F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b
|
||||
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
|
||||
F Makefile.msc 8dd676302f3165984c046f81af14b6676a334418fa30255efaf439f8033042fa
|
||||
F README.md e28077cfbef795e99c9c75ed95aa7257a1166709b562076441a8506ac421b7c1
|
||||
F VERSION 16eddb43056a79c1977427ab7a05f3457c373fa159dcdced8754eb89ce7e06b8
|
||||
F Makefile.msc 523bab2f6569e912a0aaf2d13e0b3f9bcb36d52310b236d950b354068c9de3f3
|
||||
F README.md dae499194b75deed76a13a4a83c82493f2530331882d7dfe5754d63287d3f8f7
|
||||
F VERSION 74672bfd4c7826c0fc6f84762488a707c52e7d2d94af42ccb0edcc6c74311c41
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -18,11 +18,11 @@ F art/sqlite370.svg 40b7e2fe8aac3add5d56dd86ab8d427a4eca5bcb3fe4f8946cb3794e1821
|
||||
F auto.def 44a0d1bf09d78355fc88251ccbf8e64e6341fd89c11de68a01c3645e53a2bade
|
||||
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
|
||||
F autoconf/Makefile.in 306f500fce8cae9e1af9459f1ac7fe89ce46999594ef3fdc62dc9d7d651fb091
|
||||
F autoconf/Makefile.msc 05b345da3a512c6c387d0e78d812deb0a42748962c115a6eac781c160a95d7cc
|
||||
F autoconf/Makefile.msc 803aa9e23b6a764751f6a91d0673620eefa46729fb80faf51391120e1d752966
|
||||
F autoconf/README.first f1d3876e9a7852c22f275a6f06814e64934cecbc0b5b9617d64849094c1fd136
|
||||
F autoconf/README.txt b749816b8452b3af994dc6d607394bef3df1736d7e09359f1087de8439a52807
|
||||
F autoconf/auto.def 3d994f3a9cc9b712dbce92a5708570ddcf3b988141b6eb738f2ed16127a9f0ac
|
||||
F autoconf/tea/Makefile.in bf6b43eafcd18766d81a8f0085cfc9cb051d8abae9031a8e7c3f5f1246e8f166
|
||||
F autoconf/tea/Makefile.in 00e60cf3bf5580f31bfdcf3c914e9ba1831d676948363962de92ce65e5be4431
|
||||
F autoconf/tea/README.txt 23475876343498ef2b514cc7510e8f1559a17e8e03fbc7a41c1c8a3b89e7b7e3
|
||||
F autoconf/tea/_teaish.tester.tcl.in 8253b44be88e2e3f21de95a65d3a90c2be8e70b7bdd08a5b80e337ba7402f8f1
|
||||
F autoconf/tea/auto.def ce95b9450e2fa4ba5dc857e208fe10f4e6f2d737796ac3278aee6079db417529
|
||||
@@ -46,21 +46,21 @@ F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e
|
||||
F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1821baf61bc86a7e
|
||||
F autosetup/jimsh0.c a57c16e65dcffc9c76e496757cb3f7fb47e01ecbd1631a0a5e01751fc856f049
|
||||
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
|
||||
F autosetup/proj.tcl ec30c4bc301b6e9eb937655744a7315f863f804fc66400d975bcf9352ac96a1d
|
||||
F autosetup/sqlite-config.tcl b530d62d05972c61933b6fc02658be0612ca667048bf64929f7a91ca8ecad2a5
|
||||
F autosetup/proj.tcl 6fc14ef82b19b77a95788ffbcfad7989b4e3cb4ce96a21dcb5cf7312f362fba9
|
||||
F autosetup/sqlite-config.tcl 1fd7c55394051fbfba2fb9fa9192c027ee7d74612dbf772b06e27feb9f1de5df
|
||||
F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9
|
||||
F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca
|
||||
F autosetup/teaish/core.tcl aee092fc71986d1272b835ea7492bb55ffc213a289502e4f14da80cf67b7e3c3
|
||||
F autosetup/teaish/core.tcl e014dd95900c7f9a34e8e0f460f47e94841059827bce8b4c49668b0c7ae3f1a0
|
||||
F autosetup/teaish/feature.tcl 18194fb79a24d30e5bbdeab40999616f39278b53a27525349ded033af2fd73be
|
||||
F autosetup/teaish/tester.tcl 1799514c2652db49561b3386c5242b94534d1663f2cfac861a955e071895fdd0
|
||||
F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x
|
||||
F contrib/sqlitecon.tcl eb4c6578e08dd353263958da0dc620f8400b869a50d06e271ab0be85a51a08d3
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/compile-for-unix.md c9dce1ddd4bf0d25efccc5c63eb047e78c01ce06a6ff29c73e0a8af4a0f4adbc
|
||||
F doc/compile-for-windows.md 5141661e783c9ca9e3fd30e813345898712f5c311d71316f183db87038fa28a6
|
||||
F doc/compile-for-windows.md f9e74d74da88f384edd5809f825035e071608f00f7f39c0e448df7b3982f979c
|
||||
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
|
||||
F doc/jsonb.md acd77fc3a709f51242655ad7803510c886aa8304202fa9cf2abc5f5c4e9d7ae5
|
||||
F doc/lemon.html 89ea833a6f71773ab1a9063fbb7fb9b32147bc0b1057b53ecab94a3b30c0aef5
|
||||
F doc/lemon.html 0e4b854b5ca0cf3600fec4da454197f651e8a0d411a90653703e75474486ad31
|
||||
F doc/pager-invariants.txt 83aa3a4724b2d7970cc3f3461f0295c46d4fc19a835a5781cbb35cb52feb0577
|
||||
F doc/tcl-extension-testing.md b88861804fc1eaf83249f8e206334189b61e150c360e1b80d0dcf91af82354f5
|
||||
F doc/testrunner.md 5ee928637e03f136a25fef852c5ed975932e31927bd9b05a574424ae18c31019
|
||||
@@ -284,14 +284,14 @@ F ext/intck/intck_common.tcl a61fd2697ae55b0a3d89847ca0b590c6e0d8ff64bebb70920d9
|
||||
F ext/intck/intckbusy.test d5ed4ef85a4b1dc1dee2484bd14a4bb68529659cca743327df0c775f005fa387
|
||||
F ext/intck/intckcorrupt.test f6c302792326fb3db9dcfc70b554c55369bc4b52882eaaf039cfe0b74c821029
|
||||
F ext/intck/intckfault.test cff3f75dff74abb3edfcb13f6aa53f6436746ab64b09fe5e2028f051e985efab
|
||||
F ext/intck/sqlite3intck.c 0d10df36e2b7b438aa80ecd3f5e584d41b747586b038258fe6b407f66b81e7c5
|
||||
F ext/intck/sqlite3intck.c b1c8a86f90fc00741d13314db9c58f7e2f92d1d19c5ad1c6904ec83a6bbd5c96
|
||||
F ext/intck/sqlite3intck.h 2b40c38e7063ab822c974c0bd4aed97dabb579ccfe2e180a4639bb3bbef0f1c9
|
||||
F ext/intck/test_intck.c 4f9eaadaedccb9df1d26ba41116a0a8e5b0c5556dc3098c8ff68633adcccdea8
|
||||
F ext/jni/GNUmakefile 8a94e3a1953b88cf117fb2a5380480feada8b4f5316f02572cab425030a720b4
|
||||
F ext/jni/README.md e3fbd47c774683539b7fdc95a667eb9cd6e64d8510f3ee327e7fa0c61c8aa787
|
||||
F ext/jni/README.md 1479c83dbe26125264a060ee6873531795a7082dbc0d43c4067683371331559f
|
||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||
F ext/jni/src/c/sqlite3-jni.c 3d84a0176af779737ae977ba1c90d2ffe2537b8299c5d9f6552620493f12ac4b
|
||||
F ext/jni/src/c/sqlite3-jni.h ac180ba9b21978727006c790d3006a95a2402a4c3ec7a0def92707ed89b79945
|
||||
F ext/jni/src/c/sqlite3-jni.c 6ccc50b0e98b8ef8fd6a8b837223e1c8ebb92bfe6b976128cc757c26257d994a
|
||||
F ext/jni/src/c/sqlite3-jni.h df43024cced914c49485633d0f90168689e70577b3b17b0ecbdaf16e4a417bff
|
||||
F ext/jni/src/org/sqlite/jni/annotation/Experimental.java 8603498634e41d0f7c70f661f64e05df64376562ea8f126829fd1e0cdd47e82b
|
||||
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java be6cc3e8e114485822331630097cc0f816377e8503af2fc02f9305ff2b353917
|
||||
F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 56e3dee1f3f703a545dfdeddc1c3d64d1581172b1ad01ffcae95c18547fafd90
|
||||
@@ -301,7 +301,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0e28a0df51368c7127e505f
|
||||
F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a
|
||||
F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759
|
||||
F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca
|
||||
F ext/jni/src/org/sqlite/jni/capi/CApi.java 3d275f5f4fbdbe4fff15f4d42cf5ff559f9a4897e7373fa99f3b1dc9cf7f849c
|
||||
F ext/jni/src/org/sqlite/jni/capi/CApi.java a9701cbe736b8bef5bc72ae465be0250e137f67bdb5a3ab62497972b6f51572d
|
||||
F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 1b3baf5b772f266e8baf8f35f0ddc5bd87fc8c4927ec69115c46fd6fba6701c3
|
||||
F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a
|
||||
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
|
||||
@@ -319,7 +319,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385
|
||||
F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 3c0babc067d8560627a9ed1b07979f9d4393464e2282c2fca4832052e982c7bc
|
||||
F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615
|
||||
F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java 9133bb7685901d2edf07801191284975e33b5583ce09dce1c05202ff91e7bb99
|
||||
F ext/jni/src/org/sqlite/jni/capi/Tester1.java 4c3d16fdf6e979f839b2ecdb14d0a0c04bd3d0e41500fc9e8110b588883b140b
|
||||
F ext/jni/src/org/sqlite/jni/capi/Tester1.java 378d142435d220b20b7ce7343c62a03e853bb8c51e80447ee0f8ac5c37362d9a
|
||||
F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723
|
||||
F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56
|
||||
F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 2ce069f3e007fdbbe1f4e507a5a407fc9679da31a0aa40985e6317ed4d5ec7b5
|
||||
@@ -346,7 +346,7 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md d7987b432870d23f7c72a780
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 326ffba29aab836a6ea189703c3d7fb573305fd93da2d14b0f9e9dcf314c8290
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java e920f7a031e04975579240d4a07ac5e4a9d0f8de31b0aa7a4be753c98ae596c9
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java c82bc00c1988f86246a89f721d3c41f0d952f33f934aa6677ec87f7ca42519a0
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java ce8aef867e06a21685658eb0173768c355e9e1e2dfdc75f382643fa62c7ee779
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 08f92d52be2cec28a7b4555479cc54b7ebeeb94985256144eeb727154ec3f85b
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java a84e90c43724a69c2ecebd601bc8e5139f869b7d08cb705c77ef757dacdd0593
|
||||
@@ -355,7 +355,7 @@ F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43
|
||||
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
|
||||
F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0
|
||||
F ext/misc/README.md 6243cdc4d7eb791c41ef0716f3980b8b5f6aa8c61ff76a3958cbf0031c6ebfa7
|
||||
F ext/misc/amatch.c 2db45b1499b275d8340af6337a13d6216e4ceb2ddb41f4042b9801be7b5e593d
|
||||
F ext/misc/amatch.c 0e0124c1e03ee4cb99b25969f6b7b39c53a847b8bf12279efbcb896b0df1059a
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
|
||||
F ext/misc/base64.c 8dc0a08cee11722822858a62625f1b63e5d5f1adac1cf4492d5732b571e37aa0
|
||||
@@ -372,7 +372,7 @@ F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a0
|
||||
F ext/misc/decimal.c d4883de142f6dcd36eda23da40b55e2b51374e7b01eb54a7173940191389fc5e
|
||||
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
|
||||
F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b
|
||||
F ext/misc/fileio.c 88cb2e5744296de6638af02ef6349fd468c2eb5e5f41ba405f88d9b4ad500f8e
|
||||
F ext/misc/fileio.c 61af623160c073b605b4ff1f67d278c4c348956efa08f6201756577c7a050d17
|
||||
F ext/misc/fossildelta.c 2fc2dd4f34f478df674887db62586b1071c4cd3c9e73ee40f9ee669670e482d1
|
||||
F ext/misc/fuzzer.c 6b231352815304ba60d8e9ec2ee73d4918e74d9b76bda8940ba2b64e8777515e
|
||||
F ext/misc/ieee754.c 176c061c94857b543313959289cb60cf777c999fd002f82b53d194b95e9f347a
|
||||
@@ -381,18 +381,14 @@ F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2
|
||||
F ext/misc/mmapwarm.c a81af4aaec00f24f308e2f4c19bf1d88f3ac3ce848c36daa7a4cd38145c4080d
|
||||
F ext/misc/nextchar.c 7877914c2a80c2f181dd04c3dbef550dfb54c93495dc03da2403b5dd58f34edd
|
||||
F ext/misc/noop.c f1a21cc9b7a4e667e5c8458d80ba680b8bd4315a003f256006046879f679c5a0
|
||||
F ext/misc/normalize.c 4782be3b74b9bd9f67281036ff1f41e5edcad20ad486171a2d671c4bb2586011
|
||||
F ext/misc/normalize.c fbb144a861809686ff2b5b6eee8bb2e1207f9bf13ce7376e5273c700a1eafbd5
|
||||
F ext/misc/pcachetrace.c f4227ce03fb16aa8d6f321b72dd051097419d7a028a9853af048bee7645cb405
|
||||
F ext/misc/percentile.c 72e05a21db20a2fa85264b99515941f00ae698824c9db82d7edfbb16cea8ec80
|
||||
F ext/misc/prefixes.c 82645f79229877afab08c8b08ca1e7fa31921280906b90a61c294e4f540cd2a6
|
||||
F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47cc06c
|
||||
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
|
||||
F ext/misc/regexp.c 548151f3e57506fda678e6a65e85a763f4eece653287e1ad44e167f9485e0c6b
|
||||
F ext/misc/regexp.c f1f7cfe90fc027b33d2b5ae7d6235eecce69c3aca71c9afce56fec62342c8b44
|
||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||
F ext/misc/resfmt-tester.c 3188324e10f945429fd684c1d1a468a1bde43e1379af60f0d34c5411a04b0edc
|
||||
F ext/misc/resfmt.c fc9c8b26b4fb8958fb3fba85f0368a373fb2d1aaf707d57769f6eff791800b1c
|
||||
F ext/misc/resfmt.h ebb635f87324499a1487cdad812f64ab9f98a1b09accf0ba45fea0e274e2bd3b
|
||||
F ext/misc/resfmt.md 6f6cefd95fa11ce30e4f34ea84052e7a8291dd48b7e666352bd7cf2e22c22ec4
|
||||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
|
||||
F ext/misc/series.c 22c6d8f00cc1b5089b1b37392e9097e9df9a5db53be86daf9a7669d95bb179f4
|
||||
@@ -414,7 +410,7 @@ F ext/misc/uuid.c 5bb2264c1b64d163efa46509544fd7500cb8769cb7c16dd52052da8d961505
|
||||
F ext/misc/vfslog.c 3932ab932eeb2601dbc4447cb14d445aaa9fbe43b863ef5f014401c3420afd20
|
||||
F ext/misc/vfsstat.c 0b23c0a69a2b63dc0ef0af44f9c1fc977300c480a1f7a9814500369d8211f56e
|
||||
F ext/misc/vfstrace.c 0e4b8b17ac0675ea90f6d168d8214687e06ca3efbc0060aad4814994d82b41fb
|
||||
F ext/misc/vtablog.c 9f7e02e9e8de585f3bfb48405db36c2eb4b680a23a67d7a4b738dd20f6ad7aec
|
||||
F ext/misc/vtablog.c 2d04386c2f5a3bb93bc9ae978f0b7dcd5a264e126abd640dd6d82aa9067cbd48
|
||||
F ext/misc/vtshim.c e5bce24ab8c532f4fdc600148718fe1802cb6ed57417f1c1032d8961f72b0e8f
|
||||
F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f65b4fc0668
|
||||
F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
|
||||
@@ -497,7 +493,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 86967c5a501f895b9705366b8cd9c37f15a9ebdff770ceb719c7deeeb2c22b72
|
||||
F ext/rtree/rtree.c 95401e6812a399b5ef2e5de1249ab7e2844601cb4153ca2c3f14122ff3625569
|
||||
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
|
||||
F ext/rtree/rtree1.test e0608db762b2aadca0ecb6f97396cf66244490adc3ba88f2a292b27be3e1da3e
|
||||
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
|
||||
@@ -579,8 +575,7 @@ F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009e
|
||||
F ext/session/sqlite3session.c b3de195ce668cace9b324599bf6255a70290cbfb5451e826e946f3aee6e64c54
|
||||
F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a
|
||||
F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb
|
||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
||||
F ext/wasm/GNUmakefile be5cbc4733403459589daf2e0784653c23e7ca8353e78398ef223565d63aa68b
|
||||
F ext/wasm/GNUmakefile 01f5e1bc688911b0c0accb0b152dccb19818cb301a90ba9772e3b329a7f625b0
|
||||
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
|
||||
F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259
|
||||
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
|
||||
@@ -588,35 +583,31 @@ F ext/wasm/SQLTester/SQLTester.mjs 6b3c52ed36a5573ca4883176f326332a8d4c0cecf5efd
|
||||
F ext/wasm/SQLTester/SQLTester.run.mjs 57f2adb33f43f2784abbf8026c1bfd049d8013af1998e7dcb8b50c89ffc332e0
|
||||
F ext/wasm/SQLTester/index.html 64f3435084c7d6139b08d1f2a713828a73f68de2ae6a3112cbb5980d991ba06f
|
||||
F ext/wasm/SQLTester/touint8array.c 2d5ece04ec1393a6a60c4bf96385bda5e1a10ad49f3038b96460fc5e5aa7e536
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core ef34398a903d0a2425fbbfbd4ed2cd596daea55b8515e2617c8dc7ad7c0767dd
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras 9eae68943ce91ab145892b31370819c2103525240eb72e0fce53c498b8d8275a
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
|
||||
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
|
||||
F ext/wasm/api/README.md f4c0d67caaee21a77b8938c30b5f79667bfc9d0c95d01b51df77ea35ee773884
|
||||
F ext/wasm/api/extern-post-js.c-pp.js 205f55aacfc62c580985db5c790300779de3876a76a5c7e1bfb13e71c8b4506b
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp d609c22bc05e25991bdd2eeed4497485a3756446158b2794471426e5e3517056
|
||||
F ext/wasm/api/README.md aae128e14711dafac29e7b645ff1b6be42305b73f74b1303d8401351f8448631
|
||||
F ext/wasm/api/extern-post-js.c-pp.js 4b310c9891886e7c1ea4e2419966ff45dfeda825b897fdaa4119332509f7e3d1
|
||||
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
|
||||
F ext/wasm/api/post-js-footer.js 5bd7170b5e8ce7b62102702bbcf47ef7b3b49cd56ed40c043fd990aa715b74ee
|
||||
F ext/wasm/api/post-js-header.js 79d078aec33d93b640a19c574b504d88bb2446432f38e2fbb3bb8e36da436e70
|
||||
F ext/wasm/api/pre-js.c-pp.js a876c6399dff29b6fe9e434036beb89889164cc872334e184291723ecc7cb072
|
||||
F ext/wasm/api/sqlite3-api-cleanup.js a3d6b9e449aefbb8bba283c2ba9477e2333a0eeb94a7a26b5bf952736f65a6dd
|
||||
F ext/wasm/api/sqlite3-api-glue.c-pp.js d2b8263b3ce0cefc6c5a68d0a4d448a9770eda4bf9d9ded9d7eb0198e4ce4da1
|
||||
F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b
|
||||
F ext/wasm/api/post-js-header.js d24bd0d065f3489c8b78ddf3ead6321e5d047187a162cd503c41700e03dd1f06
|
||||
F ext/wasm/api/pre-js.c-pp.js ad2546290e0c8ce5ca2081bff6e85cc25eeb904a3303921f1184290a7ff1b32f
|
||||
F ext/wasm/api/sqlite3-api-glue.c-pp.js 79a54b54ca6324d28e31e19b56bbaebb7d2cc4b3079066e7e901333fa5047c53
|
||||
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 31dbfd470c91ffd96d77399b749bab6b69e3ba9074188833f97ac13f087cf07b
|
||||
F ext/wasm/api/sqlite3-api-prologue.js b5a55ae74efcdcd0aa6a143d59e34137e43ae732f02b563dcab22d735f1599a4
|
||||
F ext/wasm/api/sqlite3-api-prologue.js a7cab3e8f78d5a93d7173657677fef18265f48d4e0b1e1755740f734a69cae6d
|
||||
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938
|
||||
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 26cb41d5a62f46a106b6371eb00fef02de3cdbfaa51338ba087a45f53028e0d0
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 418c33fe284739564daab3c7a7a88882fdd3c99137497900f98eddec1e409af5
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js aa330fa0e8ef35cbd92eb0d52e05fbaa07e61540c5cb164e693c82428ce1d763
|
||||
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72a76124213cbc9469d757676da86
|
||||
F ext/wasm/api/sqlite3-wasm.c dd7fc1d535281f0d5d2732bb1b662d1d403a762f07b63c2ea5663053377b2804
|
||||
F ext/wasm/api/sqlite3-wasm.c 03451f8335f4ba8ea9a79dfc170560b1ee5376de64ff49c1a114274ccf50ab3d
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bda1c75bd674a92a0e27cc2f3d46dbbf21e422413f8046814515a0bd7409328a
|
||||
F ext/wasm/api/sqlite3-worker1.c-pp.js 802d69ead8c38dc1be52c83afbfc77e757da8a91a2e159e7ed3ecda8b8dba2e7
|
||||
F ext/wasm/c-pp-lite.c b2098c8abb8d42f061a53c6857fbc1863298dc8a2d9eb5f114fca67c36f39a68
|
||||
F ext/wasm/c-pp-lite.c 943be1a36774d58385dca32de36fc18d4f432fe79f7aa35e6c85dd6a6b825bd0
|
||||
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
|
||||
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
|
||||
F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
|
||||
F ext/wasm/common/whwasmutil.js 0d539324097fc83b953e9844267359ba0fd02286caa784ea2f597ced279ea640
|
||||
F ext/wasm/common/whwasmutil.js 804409dec98458f732b23e6e86788934ac6dec002107435cc4055355585d1c15
|
||||
F ext/wasm/config.make.in c424ae1cc3c89274520ad312509d36c4daa34a3fce5d0c688e5f8f4365e1049a
|
||||
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
|
||||
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
|
||||
@@ -633,10 +624,10 @@ F ext/wasm/fiddle/fiddle.js 84fd75967e0af8b69d3dd849818342227d0f81d13db92e0dcbc6
|
||||
F ext/wasm/fiddle/index.html a27b8127ef9ecf19612da93b2a6a73bdb3777b5c56b5450bb7200a94bc108ff9
|
||||
F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290
|
||||
F ext/wasm/index.html 54e27db740695ab2cb296e02d42c4c66b3f11b65797340d19fa6590f5b287da1
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js bbac67bc7a79dca34afe6215fd16b27768d84e22273507206f888c117e2ede7d
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 1e734c624205cdf621f322972dfb0fc8013d573a5882f57492a6830e5ec23e17
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f
|
||||
F ext/wasm/mkdist.sh 29f8a37a7aba41fa5df8e89b1fab02b83b35c43473c5cf808584872e022514b8 x
|
||||
F ext/wasm/mkwasmbuilds.c 0216fd7273314b9e433ca17d7692cce844a362b31a192e44d31fc13cdb27ad8c
|
||||
F ext/wasm/mkdist.sh 64d53f469c823ed311f6696f69cec9093f745e467334b34f5ceabdf9de3c5b28 x
|
||||
F ext/wasm/mkwasmbuilds.c ef42e404236dd98cedb6ecea47b6d2474e3c593633ce6d992d316289dfc442b6
|
||||
F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
|
||||
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
|
||||
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
|
||||
@@ -650,9 +641,9 @@ F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d826
|
||||
F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
|
||||
F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f
|
||||
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
|
||||
F ext/wasm/tester1-worker.c-pp.html 883881eeac14eeeecc8ff22acf9fe0f18a97cacb48be08ebb0bae891ceded584
|
||||
F ext/wasm/tester1.c-pp.html 949920126dcf477925d8d540093d9cc374d3ab4c4ddee920c1dcadcf37917306
|
||||
F ext/wasm/tester1.c-pp.js 614cac06524ec2202027c7f6cc5e94d91482b0eb6aa969f252517047596e404e
|
||||
F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a
|
||||
F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb
|
||||
F ext/wasm/tester1.c-pp.js 2c255093205a0dac9dae7475030665c2c9d6dccc857de68ee7daf49aa82e6de8
|
||||
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
|
||||
@@ -662,12 +653,12 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk bf63775585a99e8e7158c4d67c30aeeae45b84572c474f9d41c7bba927788f46
|
||||
F main.mk 29078d11f7545a8fae4347305b164bb4e777b801da16baeb48214014a8d63a06
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
|
||||
F mptest/crash02.subtest f4ef05adcd15d60e5d2bd654204f2c008b519df8
|
||||
F mptest/mptest.c aa41ace6dbc5050d76b02548d3521e6bbccae4f0
|
||||
F mptest/mptest.c 7ecf39040c1187d9cbc487409bc052f194e93c165f667c55b052690a741d9d71
|
||||
F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
|
||||
@@ -679,31 +670,31 @@ F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399
|
||||
F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c cb5b8ceb9baa02a63a2f83dec09c4153e1cfbdf9c2adef5c62c26d2160eeb067
|
||||
F src/btree.c 8850125300b9780fa54bc45a41af88eb2796b90f2f97942279094beef9b0e971
|
||||
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
|
||||
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
|
||||
F src/build.c 611e07299d72ff04bbcb9e7109183467e30925d203c3e121ef9bb3cf6876289b
|
||||
F src/callback.c acae8c8dddda41ee85cfdf19b926eefe830f371069f8aadca3aa39adf5b1c859
|
||||
F src/carray.c a6f26cb349ca700d706c0e76d5b2895d76e2a1c392a2b909cf543a0dd4d4d047
|
||||
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
|
||||
F src/carray.c ff6081a31878fc34df8fa1052a9cbf17ddc22652544dcb3e2326886ed1053b55
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/date.c e19e0cfff9a41bfdd884c655755f6f00bca4c1a22272b56e0dd6667b7ea893a2
|
||||
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
|
||||
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
|
||||
F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
|
||||
F src/expr.c 4d63c8f6d50fe20637de8bdaf57757a0e424e4ac5e2c3313e621d64727a48a1c
|
||||
F src/expr.c 17b0cbe08e004c1653030f5de9b6b050e84feaa112239f7f576af2dc5e53a5fb
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
|
||||
F src/func.c 4d945b54a0e931f7454dd9e07d34fd297531355730ec91cb3c06d28a96c7e938
|
||||
F src/func.c 0b802107498048d3dcac0b757720bcb8506507ce02159e213ab8161458eb293b
|
||||
F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b
|
||||
F src/hash.c 73934a7f7ab1cb110614a9388cb516893b0cf5b7b69e4fd1a0780ac4ce166be7
|
||||
F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca
|
||||
F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
F src/hwtime.h d4d1b98c1afdc56986a5c0eba882786ef017e2180a320da25b4231b8e7e463e8
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
|
||||
F src/json.c fb031340edee159c07ad37dbe668ffe945ed86f525b0eb3822e4a67cbc498a72
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c a3bc9a2522dc3b960e38b7582d1818f6245a49289387c2c7b19f27bfeabf1e81
|
||||
F src/main.c ce69a2650e3d359ed6a8a2867ccafb27ac62ce1d39f3120a84ff513320952a6c
|
||||
F src/loadext.c 4747f72084dc80520a2d23e5bb0bc0760672208a81a2b115ce0b657acd65edf4
|
||||
F src/main.c eaf5215917b7e8b34ddea013524287f6d5021ba0fc70202e7602e225ef0d16bf
|
||||
F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@@ -724,33 +715,33 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
|
||||
F src/os_kv.c fb7ba8d6204197357f1eb7e1c7450d09c10043bf7e99aba602f4aa46b8fb11a3
|
||||
F src/os_setup.h 8efc64eda6a6c2f221387eefc2e7e45fd5a3d5c8337a7a83519ba4fbd2957ae2
|
||||
F src/os_unix.c b3da55bc4bb214b2bfb1e430b10e9d3ebcf6b11741921ab044c9b9539c8fcc4f
|
||||
F src/os_win.c f81a7cffdfe8c593a840895b3f64290714f0186b06302d2c397012252d830374
|
||||
F src/os_unix.c 7945ede1e85b2d1b910e1b4af9ba342e964b1e30e79f4176480a60736445cb36
|
||||
F src/os_win.c a89b501fc195085c7d6c9eec7f5bd782625e94bb2a96b000f4d009703df1083f
|
||||
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
|
||||
F src/pager.c 113f9149092ccff6cf90e97c2611200e5a237f13d26c394bc9fd933377852764
|
||||
F src/pager.c a81461de271ac4886ad75b7ca2cca8157a48635820c4646cd2714acdc2c17e5f
|
||||
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
|
||||
F src/parse.y 619c3e92a54686c5e47923688c4b9bf7ec534a4690db5677acc28b299c403250
|
||||
F src/parse.y 04c6c7278939e3c6307ed3c6ed7482d2928e692560dbe8e57f524851a934e25c
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
|
||||
F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f
|
||||
F src/prepare.c 2af0b5c1ec787c8eebd21baa9d79caf4a4dc3a18e76ce2edbf2027d706bca37a
|
||||
F src/printf.c 7297c2aeed4d90d80c5ba82920d9e57b7bfad04b3466be1d7e042db382fe296e
|
||||
F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c f8d1d011aba0964ff1bdccd049d4d2c2fec217efd90d202a4bb775e926b2c25d
|
||||
F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c b95181711d59c36d9789e67f76c4cfec64b99f9629a50be5e6566e117b87d957
|
||||
F src/shell.c.in d8f5c8aeec7beff61b42ea13bfab96076809bd356a4f694983222ee5fcf6a244
|
||||
F src/sqlite.h.in 10faecc456d3962c7cedae70d69305f7c80129f28dd8524bd8a06b3eac955e54
|
||||
F src/select.c ba9cd07ffa3277883c1986085f6ddc4320f4d35d5f212ab58df79a7ecc1a576a
|
||||
F src/shell.c.in ceb0a9cc008ac82d8d2e6ef353db14a54bc40dfd60a8cfbb6bc98d071f538761
|
||||
F src/sqlite.h.in 667dff873941366da98da3200cf757ac05dfb62ea785e6642e33dd586ae5285c
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 7f236ca1b175ffe03316d974ef57df79b3938466c28d2f95caef5e08c57f3a52
|
||||
F src/sqliteInt.h e16df0914718acba6fb7e5f03055f7cf519d0d61314c78ec2f5c9f6a45608d86
|
||||
F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
|
||||
F src/sqliteInt.h 88f7fc9ce1630d9a5f7e0a8e1f3287cdc63882fba985c18e7eee1b9f457f59aa
|
||||
F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 3c604c49e6cf4211960a9ddb9505280fd22cde32175f40884c641c0f5a286036
|
||||
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
|
||||
F src/test1.c f880ab766eeedf2c063662bd9538b923fd42c4341b7bfc2150a6d93ab8b9341c
|
||||
F src/test1.c 5d061afe479c7364842e0170be7220dea13389575fa6030d30b3e20bec4e1f75
|
||||
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
|
||||
F src/test3.c 432646f581d8af1bb495e58fc98234380250954f5d5535e507fc785eccc3987a
|
||||
F src/test4.c 0ac87fc13cdb334ab3a71823f99b6c32a6bebe5d603cd6a71d84c823d43a25a0
|
||||
@@ -760,7 +751,7 @@ F src/test8.c 206d8f3cc73950d252906656e2646b5de0d580b07187b635fcb3edd8c2c5fbc0
|
||||
F src/test9.c df9ddc7db6ef1b8cf745866ee229090779728bcbe660c7f297d3127ab21d92af
|
||||
F src/test_autoext.c 14d4bbd3d0bd1eec0f6d16b29e28cf1e2d0b020d454835f0721a5f68121ac10f
|
||||
F src/test_backup.c a2bfd90d2ff2511b8635507bdb30fa9b605ade19c16b533066cae3077f5bdb72
|
||||
F src/test_bestindex.c 3401bee51665cbf7f9ed2552b5795452a8b86365e4c9ece745b54155a55670c6
|
||||
F src/test_bestindex.c d75fad21369d80910238032bcf8d9ca1f2bffda13c1ceec63bfbb7f704448b15
|
||||
F src/test_blob.c 77b994e17f2c87055f44fd96c9a206c5a7155bae2cda2769af60c2f3582f962c
|
||||
F src/test_btree.c 28283787d32b8fa953eb77412ad0de2c9895260e4e5bd5a94b3c7411664f90d5
|
||||
F src/test_config.c 18aa596d37de1d5968c439fd58ebf38bc4d9c9d1db63621504e241fde375cecd
|
||||
@@ -798,7 +789,7 @@ F src/test_vfs.c b4135c1308516adf0dfd494e6d6c33114e03732be899eace0502919b674586b
|
||||
F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 8400646d2830afc2f2dc465a75e3a92e4bedeea623f19dbd79c0c12d0dd6dda2
|
||||
F src/tokenize.c cb3294cf23c11106b50d9af6998a6c1bf389b52e15b17698c9fab97bbaa9b37f
|
||||
F src/treeview.c 3ce7ac9835d2d70cc1c868b01b747ae8a062322e155701e58e3d62ca79aada7a
|
||||
F src/trigger.c d5cf2541ff048f30b6a0507eb3d1ec4e695c53584e3b2298a5bf248714fe185e
|
||||
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
|
||||
@@ -806,22 +797,22 @@ F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
|
||||
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
|
||||
F src/util.c 36fb1150062957280777655976f3f9a75db236cb8207a0770ceae8d5ec17fcd3
|
||||
F src/vacuum.c 1bacdd0a81d2b5dc1c508fbf0d938c89fa78dd8d5b46ec92686d44030d4f4789
|
||||
F src/vdbe.c 92cc9c523cfe11ce117b3bfd8b33846cdb8084bfe3268ba567c95389da6404c8
|
||||
F src/vdbe.c b44c366e83412d3b8c190feb1f029b7d02e1bd69252a57b32f195107f0d03964
|
||||
F src/vdbe.h be33bd7b17f2ec92939642416030491508c51071f6c14e27cd195983fec56b63
|
||||
F src/vdbeInt.h 52896dd4d5b62190c53db14b09fc2484434eb594c963df0fa66eb8a94527b02e
|
||||
F src/vdbeapi.c 869a0da5d855495055f4d35c6ada582f64ce995ce14b26ff9d336274d497266c
|
||||
F src/vdbeaux.c cb907297d03b374544a5a4f81ca981497ff4d09d13838f06de507118367f0b73
|
||||
F src/vdbeInt.h 2aaeb6df2938b181b4700a9328688a3986f2bba71e8b96f6a80671316618fa49
|
||||
F src/vdbeapi.c 6a2181cfd27c86b4cc1d8abb27ae11f3b3f0357567814fa276ec37b043542938
|
||||
F src/vdbeaux.c 908d8a191aed444b2e4c920159249127f3ff67b94c56a16fad1dfdf9c7488f20
|
||||
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
|
||||
F src/vdbemem.c e67d9c6484d868c879d20c70d00bf4a9058082f1d4058607ca15d50eb3aebc21
|
||||
F src/vdbemem.c 48e562ff27e6386eb8613207ac27d3d98c1f67fdc4775a1ab13759d2c2a1c021
|
||||
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41
|
||||
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
|
||||
F src/vtab.c 828221bdbeaaa6d62126ee6d07fd4ec0d09dcaea846f87ad01944d8b7e548859
|
||||
F src/vtab.c 5437ce986db2f70e639ce8a3fe68dcdfe64b0f1abb14eaebecdabd5e0766cc68
|
||||
F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab
|
||||
F src/wal.c a278339ecf5f194fd71fff1f0da1368de50e3a32edc3e9944e1ee1f4610476ff
|
||||
F src/wal.c 505a98fbc599a971d92cb90371cf54546c404cd61e04fd093e7b0c8ff978f9b6
|
||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
|
||||
F src/where.c 7d17cd5cb883b2166097957e20c4aab2d0d98e0c1141002ef77b5f6b9deed844
|
||||
F src/where.c 1b554a868134cbc9ca2192385403c0b63e5073ff01a6cdd600a846c09f843165
|
||||
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
|
||||
F src/wherecode.c 71c5c6804b7f882dec8ec858758accae02fcfca13df3cc720f1f258e663ec7c5
|
||||
F src/whereexpr.c 403a44eeec1a0f0914fccc6a59376b6924bc00ef6728fe6ffce4cf3051b320fc
|
||||
@@ -918,7 +909,7 @@ F test/bestindexA.test e1b5def6b190797cacf008e6815ffb78fb30261999030d60a728d572e
|
||||
F test/bestindexB.test 328b97b69cd1a20928d5997f9ecb04d2e00f1d18e19ab27f9e9adb44d7bc51ce
|
||||
F test/bestindexC.test 95b4a527b1a5d07951d731604a6d4cf7e5a806b39cea0e7819d4c9667e11c3fc
|
||||
F test/bestindexD.test 6a8f6f84990bcf17dfa59652a1f935beddb7afd96f8302830fbc86b0a13df3c3
|
||||
F test/bestindexE.test f0c7105d1e7facaa8f5e6c498849cc6dcadd533b35ea9e5e1176e54a9a2d70f1
|
||||
F test/bestindexE.test 297f3ea8500a8f3c17d6f78e55bdfee089064c6144ee84a110bd005a03338f49
|
||||
F test/between.test e7587149796101cbe8d5f8abae8d2a7b87f04d8226610aa1091615005dcf4d54
|
||||
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
|
||||
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
|
||||
@@ -1043,7 +1034,7 @@ F test/dblwidth-a.sql eb4141518610e52f931a55a984310075e98dc31eee5a28ae806b1e3537
|
||||
F test/dbpage.test 63fab1eb026bada121107e53436fa749bbf83281dc9dea17af422f7a5c0f289f
|
||||
F test/dbpagefault.test ea39de2ca86041a9c6df1135645180a76d0a8da93ac159e2fafe38e39636530b
|
||||
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
|
||||
F test/dbstatus2.test 28dffdc7c7b700c04fdf4f237e7e46eef4b0ead28879434358d161e45f5fc875
|
||||
F test/dbstatus2.test a36518c0f0951d8fd5a3dc36f99948ad1af93fb7fc0d2e03e5bb5a643186cf52
|
||||
F test/decimal.test a11b87a2c3294eb4c11b55f3168aeac63d683fa8ada35921a6ec1d511eff7648
|
||||
F test/default.test c7124864cded213a3f118bc7e2e26f34b7c36dfa26cf6945cc8b7f5db1191277
|
||||
F test/delete.test 2686e1c98d552ef37d79ad55b17b93fe96fad9737786917ce3839767f734c48f
|
||||
@@ -1067,7 +1058,7 @@ F test/e_createtable.test 31b9bcb6ac8876bc7ec342d86d9c231a84c62b442093a6651dfd0f
|
||||
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
|
||||
F test/e_droptrigger.test 235c610f8bf8ec44513e222b9085c7e49fad65ad0c1975ac2577109dd06fd8fa
|
||||
F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7
|
||||
F test/e_expr.test 57a50ffd09c274b066883a59272efaf32a955c73af9f176d1c8889f0125bd2db
|
||||
F test/e_expr.test 0a1e175caddc78b27306647cb4ce2362c55790190f8cdd178b75fd6262eb8f76
|
||||
F test/e_fkey.test feeba6238aeff9d809fb6236b351da8df4ae9bda89e088e54526b31a0cbfeec5
|
||||
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
|
||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||
@@ -1097,10 +1088,10 @@ F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650
|
||||
F test/exclusive2.test cd70b1d9c6fffd336f9795b711dcc5d9ceba133ad3f7001da3fda63615bdc91e
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
|
||||
F test/existsexpr.test 9c4b77c4729281cc2ae63b9b460d0598ce28cc7876135e3e2c21629bbc8d077a
|
||||
F test/existsexpr.test e4674fb8d610e82540126ed252e6aa48922882e1bcec6522d7e5a44fe715be61
|
||||
F test/existsexpr2.test dc23e76389eff3d29f6488ff733012a3560cd67ec8cfaecbecd52cced5d5af11
|
||||
F test/existsfault.test ff41c11f3052c1bbd4f8dd557802310026253d67d7c4e3a180c16d2f0862973e
|
||||
F test/expr.test 4ada8eb822c45ef27a36851a258004d43c1e95e7c82585a1217e732084e4482c
|
||||
F test/expr.test db981f8a85520e99ae20aab7ad2e9b5b0437ed09159b57ced434c672075d2e61
|
||||
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
|
||||
F test/exprfault.test da33606d799718e2f8e34efd0e5858884a1ad87f608774c552a7f5517cc27181
|
||||
F test/exprfault2.test c49e84273898969af5dbc4fe6a3f4335f14639799f343590336c9ddf84425965
|
||||
@@ -1336,7 +1327,7 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2
|
||||
F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28
|
||||
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
|
||||
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
|
||||
F test/joinH.test fd76024ff104baec16417db5cafc0894ad4e0863e70803e63c1bba0322706339
|
||||
F test/joinH.test 1d2fc3190be68525fd9ce749b9468c40ba2930181e52fb5ee6f836051b38effb
|
||||
F test/joinI.test fc7d24a2b1e444979b83bd92c30ebb975cebb5b9eae4442ce94969bd8d083053
|
||||
F test/journal1.test bc61a4228db11bffca118bd358ba4b868524bf080f3532749de6c539656e20fa
|
||||
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
|
||||
@@ -1433,7 +1424,7 @@ F test/misc5.test 02fcaf4d42405be02ec975e946270a50b0282dac98c78303ade0d1392839d2
|
||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test d595599972ec0b436985f0f02f243b68500ffc977b9b3194ec66c0866cfddcab
|
||||
F test/misc8.test 08d2380bc435486b12161521f225043ac2be26f02471c2c1ea4cac0b1548edbd
|
||||
F test/misuse.test 46d42ffdf375833ea5828796e56f84660344f7548659b493059f152f00e66840
|
||||
F test/misuse.test 859f37014d9824ca66bd90c36372c08c80c51c9593a7cfa8a31d4f92cd4d5b7f
|
||||
F test/mjournal.test 28a08d5cb5fb5b5702a46e19176e45e964e0800d1f894677169e79f34030e152
|
||||
F test/mmap1.test 18de3fd7b70a777af6004ca2feecfcdd3d0be17fa04058e808baf530c94b1a1d
|
||||
F test/mmap2.test dba452dc7db91e9df10f70bdd73dc4190c7b8ee7b5133b4684f04277ada0b9ac
|
||||
@@ -1530,8 +1521,8 @@ F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2
|
||||
F test/reservebytes.test 6163640b5a5120c0dee6591481e673a0fa0bf0d12d4da7513bad692c1a49a162
|
||||
F test/resetdb.test 54c06f18bc832ac6d6319e5ab23d5c8dd49fdbeec7c696d791682a8006bd5fc3
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/returning1.test 212cd4111bb941a60abf608f20250db666c21eb1bc4d49217e96c87ff3ab9d1a
|
||||
F test/returningfault.test ae4c4b5e8745813287a359d9ccdb9d5c883c2e68afb18fb0767937d5de5692a4
|
||||
F test/returning1.test cd32517148948859db214dd814354597dd40e7489259590fac1a4f7bf44deb97
|
||||
F test/returningfault.test 5f9649d05680357ab077fa6bad574a3eb3f6e4858a6880b25171be516a4efcda
|
||||
F test/rollback.test 952c4d805bca96adc2be76f621ea22115fe40b330015af36fcc8028c8547fcee
|
||||
F test/rollback2.test 3f3a4e20401825017df7e7671e9f31b6de5fae5620c2b9b49917f52f8c160a8f
|
||||
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
|
||||
@@ -1604,10 +1595,10 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
|
||||
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test 396c04132628fe1c627fd4807a93a116f712cfb1cfe9ca5d553b1c89361a899f
|
||||
F test/shell1.test ebe953d64c937ad42a0f33170ac0d2d2568faae26813fc7a95203756446d54aa
|
||||
F test/shell2.test ab23f01ea2347e4b72bb2399af7ee82aa00f9c059141749f7c4064abca5ad728
|
||||
F test/shell3.test 603b448e917537cf77be0f265c05c6f63bc677c63a533c8e96aae923b56f4a0e
|
||||
F test/shell4.test ad7eee983b5e7f1dd92d8c87bc0f39474086bc32c980c00f3934c54aabc636a2
|
||||
F test/shell4.test 03593fa7908a55f255916ffeda707cdf55680c777736e3da62b1d78cde0d684d
|
||||
F test/shell5.test d17e7927ab8b7f720efbdd9b5d05fceb6c3c56c25917901b315400214bf24ef4
|
||||
F test/shell6.test e3b883b61d4916b6906678a35f9d19054861123ad91b856461e0a456273bdbb8
|
||||
F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d5c3
|
||||
@@ -1648,7 +1639,7 @@ F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
|
||||
F test/speedtest.md ee958457ae1b729d9715ae33c0320600000bf1d9ddea1a88dcf79f56729d6fad
|
||||
F test/speedtest.tcl 405411356fbc54af15987b7ffeec330a49138f71584220fb8fe1948b2f7ac907 x
|
||||
F test/speedtest.tcl 6b66974d833d35a63d0e9ec344e0ffa92fbbfac83e173556f700a61cb3be96fc x
|
||||
F test/speedtest1.c 6c01252e66f46de0b6b8d5316e03521e2151782104f3608c10262aa5dce85721
|
||||
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
|
||||
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
|
||||
@@ -1697,7 +1688,7 @@ F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 463ae33b8bf75ac77451df19bd65e7c415c2e9891227c7c9e657d0a2d8e1074a
|
||||
F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27
|
||||
F test/testrunner.tcl 9da764507f6bc752961555c0beb58eb6584b9fb0f989342c7eaab3336380f560 x
|
||||
F test/testrunner.tcl 86179a8e78997e9257cb8f738c5624cb23897da5297855578ba74715e64f1602 x
|
||||
F test/testrunner_data.tcl c507a9afa911c03446ed90442ffd4a98aca02882c3d51bd1177c24795674def8
|
||||
F test/testrunner_estwork.tcl 7927a84327259a32854926f68a75292e33a61e7e052fdbfcb01f18696c99c724
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
@@ -2005,7 +1996,7 @@ F test/walsetlk_recover.test adccbffc59e365063a4efd2da6b661ae2fcf15d775b6719fe46
|
||||
F test/walsetlk_snapshot.test 86d5588380f9927d8fcbbd75133b0a34fddf959378d6823c6f164a390123f70a
|
||||
F test/walshared.test 42e3808582504878af237ea02c42ca793e8a0efaa19df7df26ac573370dbc7a3
|
||||
F test/walslow.test 0c51843836c9dcf40a5ac05aa781bfb977b396ee2c872d92bd48b79d5dd9aa23
|
||||
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
|
||||
F test/walthread.test d562f51a61191ccfab64940df7aa1cef87c902fa5ab742590ef7f859dfe6a44b
|
||||
F test/walvfs.test e1a6ad0f3c78e98b55c3d5f0889cf366cc0d0a1cb2bccb44ac9ec67384adc4a1
|
||||
F test/where.test 5087c72d26fd075a1644c8512be9fe18de9bf2d2b0754f7fd9b74a1c6540c4fc
|
||||
F test/where2.test 52237a8cb27ebbf6583469429bb5733d1b94ac37d09c3dbd0f487952ed0ab3f8
|
||||
@@ -2110,10 +2101,10 @@ F tool/genfkey.README e550911fa984c8255ebed2ef97824125d83806eb5232582700de949edf
|
||||
F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a5a4f
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
|
||||
F tool/lemon.c 8f6c122e5727cb0e5f302b8efc91489b1947a8d98206d7a1b1cfc0ed685b6e7c
|
||||
F tool/lempar.c bdffd3b233a4e4e78056c9c01fadd2bb3fe902435abde3bce3d769fdf0d5cca2
|
||||
F tool/lemon.c fda0511d71764674919872a1457d2f86a7d48b13bfcf98741955c1b217a84570
|
||||
F tool/lempar.c a59c5474bdd148ca4c61f2977c7ce6b49e99c48a333b6d48fc7ceacf2292b43a
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/loadfts.c 63412f9790e5e8538fbde0b4f6db154aaaf80f7a10a01e3c94d14b773a8dd5a6
|
||||
F tool/logest.c c34e5944318415de513d29a6098df247a9618c96d83c38d4abd88641fe46e669
|
||||
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176
|
||||
@@ -2149,7 +2140,7 @@ F tool/showdb.c 3956d71e5193162609a60e8c9edfcf09274c00cfea2b1d221261427adb2b5cca
|
||||
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
|
||||
F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564
|
||||
F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809
|
||||
F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c2a1
|
||||
F tool/showstat4.c b706fcbc4cd1a6e4a73ac32549afc4b460479d650402d64b23e8d813516e8de4
|
||||
F tool/showwal.c 11eca547980a066b081f512636151233350ac679f29ecf4ebfce7f4530230b3d
|
||||
F tool/soak1.tcl a3892082ed1079671565c044e93b55c3c7f38829aedf53cc597c65d23ffdaddf
|
||||
F tool/spaceanal.tcl 1f83962090a6b60e1d7bf92495d643e622bef9fe82ea3f2d22350dcbce9a12d0
|
||||
@@ -2173,10 +2164,13 @@ F tool/vdbe-compress.tcl fa2f37ab39b2a0087fafb6a7f3ce19503e25e624ffa8ed9951717ab
|
||||
F tool/vdbe_profile.tcl 3ac5a4a9449f4baf77059358ea050db3e34395ccf59c5464d29b91746d5b961e
|
||||
F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6ddf2700c
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
||||
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 82dc13ec4887f90995bd984ede9c2670fb7512962ccceb1848a7e9aab7891c00
|
||||
R fa18e75fe233d98f1fe33dfd9aa9b399
|
||||
U stephan
|
||||
Z 380e5356f88927c6576fb8a521f933af
|
||||
P ea48567ac54e4949a8b68977a58a5de7946e074ae8737133071d02f40ac97f34
|
||||
R 94faba231c7b1fe01c357a8fbebddcb3
|
||||
T *branch * parser-recursion-limit
|
||||
T *sym-parser-recursion-limit *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z ef6a72fd333d3e7f2a3d9cd4902c91e6
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
branch resfmt
|
||||
tag resfmt
|
||||
branch parser-recursion-limit
|
||||
tag parser-recursion-limit
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3d044121768548df59a94bbbe4ee360d6464d1416a5cbe7437f4333b06496381
|
||||
5728129e5432500550096e2a1350897881f0379b49b60faf49481c505b1eb323
|
||||
|
||||
@@ -1037,6 +1037,10 @@ static void runScript(
|
||||
for(k=(int)strlen(zFilename)-1; k>=0 && !isDirSep(zFilename[k]); k--){}
|
||||
if( k>0 ){
|
||||
zNewFile = zToDel = sqlite3_mprintf("%.*s/%s", k,zFilename,zNewFile);
|
||||
if( zNewFile==0 ){
|
||||
fprintf(stderr, "out of memory\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
zNewScript = readFile(zNewFile);
|
||||
|
||||
+25
-1
@@ -3673,6 +3673,30 @@ static SQLITE_NOINLINE int btreeBeginTrans(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_EXPERIMENTAL_PRAGMA_20251114
|
||||
/* If both a read and write transaction will be opened by this call,
|
||||
** then issue a file-control as if the following pragma command had
|
||||
** been evaluated:
|
||||
**
|
||||
** PRAGMA experimental_pragma_20251114 = 1|2
|
||||
**
|
||||
** where the RHS is "1" if wrflag is 1 (RESERVED lock), or "2" if wrflag
|
||||
** is 2 (EXCLUSIVE lock). Ignore any result or error returned by the VFS.
|
||||
**
|
||||
** WARNING: This code will likely remain part of SQLite only temporarily -
|
||||
** it exists to allow users to experiment with certain types of blocking
|
||||
** locks in custom VFS implementations. It MAY BE REMOVED AT ANY TIME. */
|
||||
if( pBt->pPage1==0 && wrflag ){
|
||||
sqlite3_file *fd = sqlite3PagerFile(pPager);
|
||||
char *aFcntl[3] = {0,0,0};
|
||||
aFcntl[1] = "experimental_pragma_20251114";
|
||||
assert( wrflag==1 || wrflag==2 );
|
||||
aFcntl[2] = (wrflag==1 ? "1" : "2");
|
||||
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
|
||||
sqlite3_free(aFcntl[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call lockBtree() until either pBt->pPage1 is populated or
|
||||
** lockBtree() returns something other than SQLITE_OK. lockBtree()
|
||||
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
|
||||
@@ -9758,7 +9782,7 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
}while( rc==SQLITE_OK && nOut>0 );
|
||||
|
||||
if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){
|
||||
Pgno pgnoNew;
|
||||
Pgno pgnoNew = 0; /* Prevent harmless static-analyzer warning */
|
||||
MemPage *pNew = 0;
|
||||
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
|
||||
put4byte(pPgnoOut, pgnoNew);
|
||||
|
||||
@@ -507,6 +507,7 @@ void sqlite3SchemaClear(void *p){
|
||||
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
|
||||
sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
|
||||
}
|
||||
|
||||
sqlite3HashClear(&temp2);
|
||||
sqlite3HashInit(&pSchema->tblHash);
|
||||
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
||||
|
||||
+7
-6
@@ -66,8 +66,9 @@
|
||||
/*
|
||||
** Names of allowed datatypes
|
||||
*/
|
||||
static const char *azType[] = { "int32", "int64", "double", "char*",
|
||||
"struct iovec" };
|
||||
static const char *azCarrayType[] = {
|
||||
"int32", "int64", "double", "char*", "struct iovec"
|
||||
};
|
||||
|
||||
/*
|
||||
** Structure used to hold the sqlite3_carray_bind() information
|
||||
@@ -186,7 +187,7 @@ static int carrayColumn(
|
||||
case CARRAY_COLUMN_POINTER: return SQLITE_OK;
|
||||
case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break;
|
||||
case CARRAY_COLUMN_CTYPE: {
|
||||
sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
|
||||
sqlite3_result_text(ctx, azCarrayType[pCur->eType], -1, SQLITE_STATIC);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
default: {
|
||||
@@ -274,10 +275,10 @@ static int carrayFilter(
|
||||
}else{
|
||||
unsigned char i;
|
||||
const char *zType = (const char*)sqlite3_value_text(argv[2]);
|
||||
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
|
||||
for(i=0; i<sizeof(azCarrayType)/sizeof(azCarrayType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azCarrayType[i])==0 ) break;
|
||||
}
|
||||
if( i>=sizeof(azType)/sizeof(azType[0]) ){
|
||||
if( i>=sizeof(azCarrayType)/sizeof(azCarrayType[0]) ){
|
||||
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||
"unknown datatype: %Q", zType);
|
||||
return SQLITE_ERROR;
|
||||
|
||||
+1
-1
@@ -4844,7 +4844,7 @@ static SQLITE_NOINLINE int exprCodeTargetAndOr(
|
||||
pAlt = sqlite3ExprSimplifiedAndOr(pExpr);
|
||||
if( pAlt!=pExpr ){
|
||||
r1 = sqlite3ExprCodeTarget(pParse, pAlt, target);
|
||||
sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, target);
|
||||
sqlite3VdbeAddOp3(v, OP_And, r1, r1, target);
|
||||
return target;
|
||||
}
|
||||
skipOp = op==TK_AND ? OP_IfNot : OP_If;
|
||||
|
||||
+54
-1
@@ -485,7 +485,7 @@ static void *contextMalloc(sqlite3_context *context, i64 nByte){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
assert( nByte>0 );
|
||||
testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH] );
|
||||
testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
|
||||
testcase( nByte==(i64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
|
||||
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
sqlite3_result_error_toobig(context);
|
||||
z = 0;
|
||||
@@ -3083,6 +3083,56 @@ static void percentValue(sqlite3_context *pCtx){
|
||||
/****** End of percentile family of functions ******/
|
||||
#endif /* SQLITE_ENABLE_PERCENTILE */
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT)
|
||||
/*
|
||||
** Implementation of sqlite_filestat(SCHEMA).
|
||||
**
|
||||
** Return JSON text that describes low-level debug/diagnostic information
|
||||
** about the sqlite3_file object associated with SCHEMA.
|
||||
*/
|
||||
static void filestatFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zDbName;
|
||||
sqlite3_str *pStr;
|
||||
Btree *pBtree;
|
||||
|
||||
zDbName = (const char*)sqlite3_value_text(argv[0]);
|
||||
pBtree = sqlite3DbNameToBtree(db, zDbName);
|
||||
if( pBtree ){
|
||||
Pager *pPager;
|
||||
sqlite3_file *fd;
|
||||
int rc;
|
||||
sqlite3BtreeEnter(pBtree);
|
||||
pPager = sqlite3BtreePager(pBtree);
|
||||
assert( pPager!=0 );
|
||||
fd = sqlite3PagerFile(pPager);
|
||||
pStr = sqlite3_str_new(db);
|
||||
if( pStr==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
sqlite3_str_append(pStr, "{\"db\":", 6);
|
||||
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_FILESTAT, pStr);
|
||||
if( rc ) sqlite3_str_append(pStr, "null", 4);
|
||||
fd = sqlite3PagerJrnlFile(pPager);
|
||||
if( fd && fd->pMethods!=0 ){
|
||||
sqlite3_str_appendall(pStr, ",\"journal\":");
|
||||
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_FILESTAT, pStr);
|
||||
if( rc ) sqlite3_str_append(pStr, "null", 4);
|
||||
}
|
||||
sqlite3_str_append(pStr, "}", 1);
|
||||
sqlite3_result_text(context, sqlite3_str_finish(pStr), -1,
|
||||
sqlite3_free);
|
||||
}
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}else{
|
||||
sqlite3_result_text(context, "{}", 2, SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
@@ -3241,6 +3291,9 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
INLINE_FUNC(sqlite_offset, 1, INLINEFUNC_sqlite_offset, 0 ),
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT)
|
||||
FUNCTION(sqlite_filestat, 1, 0, 0, filestatFunc ),
|
||||
#endif
|
||||
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
|
||||
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
|
||||
|
||||
@@ -270,3 +270,4 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
|
||||
insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+19
-21
@@ -16,17 +16,18 @@
|
||||
#ifndef SQLITE_HWTIME_H
|
||||
#define SQLITE_HWTIME_H
|
||||
|
||||
/*
|
||||
** The following routine only works on Pentium-class (or newer) processors.
|
||||
** It uses the RDTSC opcode to read the cycle count value out of the
|
||||
** processor and returns that value. This can be used for high-res
|
||||
** profiling.
|
||||
*/
|
||||
#if !defined(__STRICT_ANSI__) && \
|
||||
(defined(__GNUC__) || defined(_MSC_VER)) && \
|
||||
(defined(i386) || defined(__i386__) || defined(_M_IX86))
|
||||
#if defined(_MSC_VER) && defined(_WIN32)
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#include <profileapi.h>
|
||||
|
||||
__inline sqlite3_uint64 sqlite3Hwtime(void){
|
||||
LARGE_INTEGER tm;
|
||||
QueryPerformanceCounter(&tm);
|
||||
return (sqlite3_uint64)tm.QuadPart;
|
||||
}
|
||||
|
||||
#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && \
|
||||
(defined(i386) || defined(__i386__) || defined(_M_IX86))
|
||||
|
||||
__inline__ sqlite_uint64 sqlite3Hwtime(void){
|
||||
unsigned int lo, hi;
|
||||
@@ -34,17 +35,6 @@
|
||||
return (sqlite_uint64)hi << 32 | lo;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
__declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
|
||||
__asm {
|
||||
rdtsc
|
||||
ret ; return value at EDX:EAX
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
|
||||
|
||||
__inline__ sqlite_uint64 sqlite3Hwtime(void){
|
||||
@@ -52,6 +42,14 @@
|
||||
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
||||
return (sqlite_uint64)hi << 32 | lo;
|
||||
}
|
||||
|
||||
#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__aarch64__)
|
||||
|
||||
__inline__ sqlite_uint64 sqlite3Hwtime(void){
|
||||
sqlite3_uint64 cnt;
|
||||
__asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r" (cnt));
|
||||
return cnt;
|
||||
}
|
||||
|
||||
#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
|
||||
|
||||
|
||||
+4
-1
@@ -522,7 +522,10 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_setlk_timeout,
|
||||
/* Version 3.51.0 and later */
|
||||
sqlite3_set_errmsg,
|
||||
sqlite3_db_status64
|
||||
sqlite3_db_status64,
|
||||
/* Version 3.52.0 and later */
|
||||
sqlite3_str_truncate,
|
||||
sqlite3_str_free
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
|
||||
+11
-1
@@ -1394,6 +1394,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
||||
/* Clear the TEMP schema separately and last */
|
||||
if( db->aDb[1].pSchema ){
|
||||
sqlite3SchemaClear(db->aDb[1].pSchema);
|
||||
assert( db->aDb[1].pSchema->trigHash.count==0 );
|
||||
}
|
||||
sqlite3VtabUnlockList(db);
|
||||
|
||||
@@ -2525,6 +2526,9 @@ void *sqlite3_wal_hook(
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return pRet;
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
UNUSED_PARAMETER(xCallback);
|
||||
UNUSED_PARAMETER(pArg);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -2540,6 +2544,11 @@ int sqlite3_wal_checkpoint_v2(
|
||||
int *pnCkpt /* OUT: Total number of frames checkpointed */
|
||||
){
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
UNUSED_PARAMETER(db);
|
||||
UNUSED_PARAMETER(zDb);
|
||||
UNUSED_PARAMETER(eMode);
|
||||
UNUSED_PARAMETER(pnLog);
|
||||
UNUSED_PARAMETER(pnCkpt);
|
||||
return SQLITE_OK;
|
||||
#else
|
||||
int rc; /* Return code */
|
||||
@@ -2722,7 +2731,7 @@ const char *sqlite3_errmsg(sqlite3 *db){
|
||||
*/
|
||||
int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zMsg){
|
||||
int rc = SQLITE_OK;
|
||||
if( !sqlite3SafetyCheckSickOrOk(db) ){
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
@@ -4902,6 +4911,7 @@ const char *sqlite3_filename_journal(const char *zFilename){
|
||||
}
|
||||
const char *sqlite3_filename_wal(const char *zFilename){
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
UNUSED_PARAMETER(zFilename);
|
||||
return 0;
|
||||
#else
|
||||
zFilename = sqlite3_filename_journal(zFilename);
|
||||
|
||||
+255
-5
@@ -596,6 +596,119 @@ static struct unix_syscall {
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT)
|
||||
/*
|
||||
** Extract Posix Advisory Locking information about file description fd
|
||||
** from the /proc/PID/fdinfo/FD pseudo-file. Fill the string buffer a[16]
|
||||
** with characters to indicate which SQLite-relevant locks are held.
|
||||
** a[16] will be a 15-character zero-terminated string with the following
|
||||
** schema:
|
||||
**
|
||||
** AAA/B.DDD.DDDDD
|
||||
**
|
||||
** Each of character A-D will be "w" or "r" or "-" to indicate either a
|
||||
** write-lock, a read-lock, or no-lock, respectively. The "." and "/"
|
||||
** characters are delimiters intended to make the string more easily
|
||||
** readable by humans. Here are the meaning of the specific letters:
|
||||
**
|
||||
** AAA -> The main database locks. PENDING_BYTE, RESERVED_BYTE,
|
||||
** and SHARED_FIRST, respectively.
|
||||
**
|
||||
** B -> The deadman switch lock. Offset 128 of the -shm file.
|
||||
**
|
||||
** CCC -> WAL locks: WRITE, CKPT, RECOVER
|
||||
**
|
||||
** DDDDD -> WAL read-locks 0 through 5
|
||||
**
|
||||
** Note that elements before the "/" apply to the main database file and
|
||||
** elements after the "/" apply to the -shm file in WAL mode.
|
||||
**
|
||||
** Here is another way of thinking about the meaning of the result string:
|
||||
**
|
||||
** AAA/B.CCC.DDDDD
|
||||
** ||| | ||| \___/
|
||||
** PENDING--'|| | ||| `----- READ 0-5
|
||||
** RESERVED--'| | ||`---- RECOVER
|
||||
** SHARED ----' | |`----- CKPT
|
||||
** DMS ------' `------ WRITE
|
||||
**
|
||||
** Return SQLITE_OK on success and SQLITE_ERROR_UNABLE if the /proc
|
||||
** pseudo-filesystem is unavailable.
|
||||
*/
|
||||
static int unixPosixAdvisoryLocks(
|
||||
int fd, /* The file descriptor to analyze */
|
||||
char a[16] /* Write a text description of PALs here */
|
||||
){
|
||||
int in;
|
||||
ssize_t n;
|
||||
char *p, *pNext, *x;
|
||||
char z[2000];
|
||||
|
||||
/* 1 */
|
||||
/* 012 4 678 01234 */
|
||||
memcpy(a, "---/-.---.-----", 16);
|
||||
sqlite3_snprintf(sizeof(z), z, "/proc/%d/fdinfo/%d", getpid(), fd);
|
||||
in = osOpen(z, O_RDONLY, 0);
|
||||
if( in<0 ){
|
||||
return SQLITE_ERROR_UNABLE;
|
||||
}
|
||||
n = osRead(in, z, sizeof(z)-1);
|
||||
osClose(in);
|
||||
if( n<=0 ) return SQLITE_ERROR_UNABLE;
|
||||
z[n] = 0;
|
||||
|
||||
/* We are looking for lines that begin with "lock:\t". Examples:
|
||||
**
|
||||
** lock: 1: POSIX ADVISORY READ 494716 08:02:5277597 1073741826 1073742335
|
||||
** lock: 1: POSIX ADVISORY WRITE 494716 08:02:5282282 120 120
|
||||
** lock: 2: POSIX ADVISORY READ 494716 08:02:5282282 123 123
|
||||
** lock: 3: POSIX ADVISORY READ 494716 08:02:5282282 128 128
|
||||
*/
|
||||
pNext = strstr(z, "lock:\t");
|
||||
while( pNext ){
|
||||
char cType = 0;
|
||||
sqlite3_int64 iFirst, iLast;
|
||||
p = pNext+6;
|
||||
pNext = strstr(p, "lock:\t");
|
||||
if( pNext ) pNext[-1] = 0;
|
||||
if( (x = strstr(p, " READ "))!=0 ){
|
||||
cType = 'r';
|
||||
x += 6;
|
||||
}else if( (x = strstr(p, " WRITE "))!=0 ){
|
||||
cType = 'w';
|
||||
x += 7;
|
||||
}else{
|
||||
continue;
|
||||
}
|
||||
x = strrchr(x, ' ');
|
||||
if( x==0 ) continue;
|
||||
iLast = strtoll(x+1, 0, 10);
|
||||
*x = 0;
|
||||
x = strrchr(p, ' ');
|
||||
if( x==0 ) continue;
|
||||
iFirst = strtoll(x+1, 0, 10);
|
||||
if( iLast>=PENDING_BYTE ){
|
||||
if( iFirst<=PENDING_BYTE && iLast>=PENDING_BYTE ) a[0] = cType;
|
||||
if( iFirst<=PENDING_BYTE+1 && iLast>=PENDING_BYTE+1 ) a[1] = cType;
|
||||
if( iFirst<=PENDING_BYTE+2 && iLast>=PENDING_BYTE+510 ) a[2] = cType;
|
||||
}else if( iLast<=128 ){
|
||||
if( iFirst<=128 && iLast>=128 ) a[4] = cType;
|
||||
if( iFirst<=120 && iLast>=120 ) a[6] = cType;
|
||||
if( iFirst<=121 && iLast>=121 ) a[7] = cType;
|
||||
if( iFirst<=122 && iLast>=122 ) a[8] = cType;
|
||||
if( iFirst<=123 && iLast>=123 ) a[10] = cType;
|
||||
if( iFirst<=124 && iLast>=124 ) a[11] = cType;
|
||||
if( iFirst<=125 && iLast>=125 ) a[12] = cType;
|
||||
if( iFirst<=126 && iLast>=126 ) a[13] = cType;
|
||||
if( iFirst<=127 && iLast>=127 ) a[14] = cType;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#else
|
||||
# define unixPosixAdvisoryLocks(A,B) SQLITE_ERROR_UNABLE
|
||||
#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */
|
||||
|
||||
/*
|
||||
** On some systems, calls to fchown() will trigger a message in a security
|
||||
** log if they come from non-root processes. So avoid calling fchown() if
|
||||
@@ -1708,7 +1821,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
|
||||
}
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK
|
||||
if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK
|
||||
&& pLock->l_start==SHARED_FIRST && pLock->l_len==SHARED_SIZE
|
||||
){
|
||||
rc = osFcntl(pFile->h, F_SETLKW, pLock);
|
||||
@@ -1719,6 +1832,13 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL)
|
||||
/* Forward reference */
|
||||
static int unixIsSharingShmNode(unixFile*);
|
||||
#else
|
||||
#define unixIsSharingShmNode(pFile) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Lock the file with the lock specified by parameter eFileLock - one
|
||||
** of the following:
|
||||
@@ -1907,7 +2027,9 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
||||
pInode->nLock++;
|
||||
pInode->nShared = 1;
|
||||
}
|
||||
}else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
|
||||
}else if( (eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1)
|
||||
|| unixIsSharingShmNode(pFile)
|
||||
){
|
||||
/* We are trying for an exclusive lock but another thread in this
|
||||
** same process is still holding a shared lock. */
|
||||
rc = SQLITE_BUSY;
|
||||
@@ -4002,6 +4124,10 @@ static int unixGetTempname(int nBuf, char *zBuf);
|
||||
#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL)
|
||||
static int unixFcntlExternalReader(unixFile*, int*);
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT)
|
||||
static void unixDescribeShm(sqlite3_str*,unixShm*);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Information and control of an open file handle.
|
||||
@@ -4144,6 +4270,66 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
return SQLITE_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT)
|
||||
case SQLITE_FCNTL_FILESTAT: {
|
||||
sqlite3_str *pStr = (sqlite3_str*)pArg;
|
||||
char aLck[16];
|
||||
unixInodeInfo *pInode;
|
||||
static const char *azLock[] = { "SHARED", "RESERVED",
|
||||
"PENDING", "EXCLUSIVE" };
|
||||
sqlite3_str_appendf(pStr, "{\"h\":%d", pFile->h);
|
||||
sqlite3_str_appendf(pStr, ",\"vfs\":\"%s\"", pFile->pVfs->zName);
|
||||
if( pFile->eFileLock ){
|
||||
sqlite3_str_appendf(pStr, ",\"eFileLock\":\"%s\"",
|
||||
azLock[pFile->eFileLock-1]);
|
||||
if( unixPosixAdvisoryLocks(pFile->h, aLck)==SQLITE_OK ){
|
||||
sqlite3_str_appendf(pStr, ",\"pal\":\"%s\"", aLck);
|
||||
}
|
||||
}
|
||||
unixEnterMutex();
|
||||
if( pFile->pShm ){
|
||||
sqlite3_str_appendall(pStr, ",\"shm\":");
|
||||
unixDescribeShm(pStr, pFile->pShm);
|
||||
}
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
if( pFile->mmapSize ){
|
||||
sqlite3_str_appendf(pStr, ",\"mmapSize\":%lld", pFile->mmapSize);
|
||||
sqlite3_str_appendf(pStr, ",\"nFetchOut\":%d", pFile->nFetchOut);
|
||||
}
|
||||
#endif
|
||||
if( (pInode = pFile->pInode)!=0 ){
|
||||
sqlite3_str_appendf(pStr, ",\"inode\":{\"nRef\":%d",pInode->nRef);
|
||||
sqlite3_mutex_enter(pInode->pLockMutex);
|
||||
sqlite3_str_appendf(pStr, ",\"nShared\":%d", pInode->nShared);
|
||||
if( pInode->eFileLock ){
|
||||
sqlite3_str_appendf(pStr, ",\"eFileLock\":\"%s\"",
|
||||
azLock[pInode->eFileLock-1]);
|
||||
}
|
||||
if( pInode->pUnused ){
|
||||
char cSep = '[';
|
||||
UnixUnusedFd *pUFd = pFile->pInode->pUnused;
|
||||
sqlite3_str_appendall(pStr, ",\"unusedFd\":");
|
||||
while( pUFd ){
|
||||
sqlite3_str_appendf(pStr, "%c{\"fd\":%d,\"flags\":%d",
|
||||
cSep, pUFd->fd, pUFd->flags);
|
||||
cSep = ',';
|
||||
if( unixPosixAdvisoryLocks(pUFd->fd, aLck)==SQLITE_OK ){
|
||||
sqlite3_str_appendf(pStr, ",\"pal\":\"%s\"", aLck);
|
||||
}
|
||||
sqlite3_str_append(pStr, "}", 1);
|
||||
pUFd = pUFd->pNext;
|
||||
}
|
||||
sqlite3_str_append(pStr, "]", 1);
|
||||
}
|
||||
sqlite3_mutex_leave(pInode->pLockMutex);
|
||||
sqlite3_str_append(pStr, "}", 1);
|
||||
}
|
||||
unixLeaveMutex();
|
||||
sqlite3_str_append(pStr, "}", 1);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */
|
||||
}
|
||||
return SQLITE_NOTFOUND;
|
||||
}
|
||||
@@ -4410,6 +4596,26 @@ struct unixShm {
|
||||
#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
|
||||
#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT)
|
||||
/*
|
||||
** Describe the pShm object using JSON. Used for diagnostics only.
|
||||
*/
|
||||
static void unixDescribeShm(sqlite3_str *pStr, unixShm *pShm){
|
||||
unixShmNode *pNode = pShm->pShmNode;
|
||||
char aLck[16];
|
||||
sqlite3_str_appendf(pStr, "{\"h\":%d", pNode->hShm);
|
||||
assert( unixMutexHeld() );
|
||||
sqlite3_str_appendf(pStr, ",\"nRef\":%d", pNode->nRef);
|
||||
sqlite3_str_appendf(pStr, ",\"id\":%d", pShm->id);
|
||||
sqlite3_str_appendf(pStr, ",\"sharedMask\":%d", pShm->sharedMask);
|
||||
sqlite3_str_appendf(pStr, ",\"exclMask\":%d", pShm->exclMask);
|
||||
if( unixPosixAdvisoryLocks(pNode->hShm, aLck)==SQLITE_OK ){
|
||||
sqlite3_str_appendf(pStr, ",\"pal\":\"%s\"", aLck);
|
||||
}
|
||||
sqlite3_str_append(pStr, "}", 1);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */
|
||||
|
||||
/*
|
||||
** Use F_GETLK to check whether or not there are any readers with open
|
||||
** wal-mode transactions in other processes on database file pFile. If
|
||||
@@ -4443,6 +4649,49 @@ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** If pFile has a -shm file open and it is sharing that file with some
|
||||
** other connection, either in the same process or in a separate process,
|
||||
** then return true. Return false if either pFile does not have a -shm
|
||||
** file open or if it is the only connection to that -shm file across the
|
||||
** entire system.
|
||||
**
|
||||
** This routine is not required for correct operation. It can always return
|
||||
** false and SQLite will continue to operate according to spec. However,
|
||||
** when this routine does its job, it adds extra robustness in cases
|
||||
** where database file locks have been erroneously deleted in a WAL-mode
|
||||
** database by doing close(open(DATABASE_PATHNAME)) or similar.
|
||||
**
|
||||
** With false negatives, SQLite still operates to spec, though with less
|
||||
** robustness. With false positives, the last database connection on a
|
||||
** WAL-mode database will fail to unlink the -wal and -shm files, which
|
||||
** is annoying but harmless. False positives will also prevent a database
|
||||
** connection from running "PRAGMA journal_mode=DELETE" in order to take
|
||||
** the database out of WAL mode, which is perhaps more serious, but is
|
||||
** still not a disaster.
|
||||
*/
|
||||
static int unixIsSharingShmNode(unixFile *pFile){
|
||||
int rc;
|
||||
unixShmNode *pShmNode;
|
||||
if( pFile->pShm==0 ) return 0;
|
||||
if( pFile->ctrlFlags & UNIXFILE_EXCL ) return 0;
|
||||
pShmNode = pFile->pShm->pShmNode;
|
||||
rc = 1;
|
||||
unixEnterMutex();
|
||||
if( ALWAYS(pShmNode->nRef==1) ){
|
||||
struct flock lock;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = UNIX_SHM_DMS;
|
||||
lock.l_len = 1;
|
||||
lock.l_type = F_WRLCK;
|
||||
osFcntl(pShmNode->hShm, F_GETLK, &lock);
|
||||
if( lock.l_type==F_UNLCK ){
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
unixLeaveMutex();
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
|
||||
@@ -4488,7 +4737,8 @@ static int unixShmSystemLock(
|
||||
|
||||
/* Locks are within range */
|
||||
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
|
||||
assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) );
|
||||
assert( ofst>=UNIX_SHM_BASE && ofst<=UNIX_SHM_DMS );
|
||||
assert( ofst+n-1<=UNIX_SHM_DMS );
|
||||
|
||||
if( pShmNode->hShm>=0 ){
|
||||
int res;
|
||||
@@ -4531,7 +4781,7 @@ static int unixShmSystemLock(
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5020,7 +5270,7 @@ static int assertLockingArrayOk(unixShmNode *pShmNode){
|
||||
return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif /* !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL) */
|
||||
|
||||
/*
|
||||
** Change the lock state for a shared-memory segment.
|
||||
|
||||
+29
-1
@@ -2663,6 +2663,7 @@ static BOOL winLockFile(
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** Lock a region of nByte bytes starting at offset offset of file hFile.
|
||||
** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock
|
||||
@@ -2745,6 +2746,7 @@ static int winHandleLockTimeout(
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif /* #ifndef SQLITE_OMIT_WAL */
|
||||
|
||||
/*
|
||||
** Unlock a file region.
|
||||
@@ -2779,6 +2781,7 @@ static BOOL winUnlockFile(
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** Remove an nByte lock starting at offset iOff from HANDLE h.
|
||||
*/
|
||||
@@ -2786,6 +2789,7 @@ static int winHandleUnlock(HANDLE h, int iOff, int nByte){
|
||||
BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0);
|
||||
return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
** The next group of routines implement the I/O methods specified
|
||||
@@ -2803,7 +2807,7 @@ static int winHandleUnlock(HANDLE h, int iOff, int nByte){
|
||||
** Seek the file handle h to offset nByte of the file.
|
||||
**
|
||||
** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite
|
||||
** error code.
|
||||
** error code.
|
||||
*/
|
||||
static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){
|
||||
int rc = SQLITE_OK; /* Return value */
|
||||
@@ -3123,6 +3127,7 @@ static int winWrite(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** Truncate the file opened by handle h to nByte bytes in size.
|
||||
*/
|
||||
@@ -3176,6 +3181,7 @@ static void winHandleClose(HANDLE h){
|
||||
osCloseHandle(h);
|
||||
}
|
||||
}
|
||||
#endif /* #ifndef SQLITE_OMIT_WAL */
|
||||
|
||||
/*
|
||||
** Truncate an open file to a specified size
|
||||
@@ -3953,6 +3959,28 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT)
|
||||
case SQLITE_FCNTL_FILESTAT: {
|
||||
sqlite3_str *pStr = (sqlite3_str*)pArg;
|
||||
sqlite3_str_appendf(pStr, "{\"h\":%llu", (sqlite3_uint64)pFile->h);
|
||||
sqlite3_str_appendf(pStr, ",\"vfs\":\"%s\"", pFile->pVfs->zName);
|
||||
if( pFile->locktype ){
|
||||
static const char *azLock[] = { "SHARED", "RESERVED",
|
||||
"PENDING", "EXCLUSIVE" };
|
||||
sqlite3_str_appendf(pStr, ",\"locktype\":\"%s\"",
|
||||
azLock[pFile->locktype-1]);
|
||||
}
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
if( pFile->mmapSize ){
|
||||
sqlite3_str_appendf(pStr, ",\"mmapSize\":%lld", pFile->mmapSize);
|
||||
sqlite3_str_appendf(pStr, ",\"nFetchOut\":%d", pFile->nFetchOut);
|
||||
}
|
||||
#endif
|
||||
sqlite3_str_append(pStr, "}", 1);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */
|
||||
|
||||
}
|
||||
OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
|
||||
return SQLITE_NOTFOUND;
|
||||
|
||||
+5
-1
@@ -813,6 +813,8 @@ int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
|
||||
(void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
|
||||
if( iRead ) return 0; /* Case (4) */
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(pgno);
|
||||
#endif
|
||||
assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 );
|
||||
if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd)
|
||||
@@ -1856,7 +1858,7 @@ static void pager_unlock(Pager *pPager){
|
||||
** have sqlite3WalEndReadTransaction() drop the write-lock, as it once
|
||||
** did, because this would break "BEGIN EXCLUSIVE" handling for
|
||||
** SQLITE_ENABLE_SETLK_TIMEOUT builds. */
|
||||
sqlite3WalEndWriteTransaction(pPager->pWal);
|
||||
(void)sqlite3WalEndWriteTransaction(pPager->pWal);
|
||||
}
|
||||
sqlite3WalEndReadTransaction(pPager->pWal);
|
||||
pPager->eState = PAGER_OPEN;
|
||||
@@ -4192,6 +4194,8 @@ int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
|
||||
sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a);
|
||||
pPager->pWal = 0;
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
#endif
|
||||
pager_reset(pPager);
|
||||
if( MEMDB ){
|
||||
|
||||
+14
-5
@@ -22,8 +22,8 @@
|
||||
}
|
||||
|
||||
// Function used to enlarge the parser stack, if needed
|
||||
%realloc parserStackRealloc
|
||||
%free sqlite3_free
|
||||
%reallocx parserStackRealloc
|
||||
%free sqlite3_free
|
||||
|
||||
// All token codes are small integers with #defines that begin with "TK_"
|
||||
%token_prefix TK_
|
||||
@@ -49,7 +49,7 @@
|
||||
}
|
||||
}
|
||||
%stack_overflow {
|
||||
sqlite3OomFault(pParse->db);
|
||||
if( pParse->nErr==0 ) sqlite3OomFault(pParse->db);
|
||||
}
|
||||
|
||||
// The name of the generated procedure that implements the parser
|
||||
@@ -583,8 +583,17 @@ cmd ::= select(X). {
|
||||
** sqlite3_realloc() that includes a call to sqlite3FaultSim() to facilitate
|
||||
** testing.
|
||||
*/
|
||||
static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){
|
||||
return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize);
|
||||
static void *parserStackRealloc(
|
||||
void *pOld, /* Old allocation, or NULL to get a new one */
|
||||
int newCount, /* Number of elements */
|
||||
int unitSize, /* Size of each element */
|
||||
Parse *pParse /* Parsing context */
|
||||
){
|
||||
if( sqlite3FaultSim(700) ) return 0;
|
||||
if( newCount > pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH]*4+100 ){
|
||||
sqlite3ErrorMsg(pParse, "Recursion limit reached");
|
||||
}
|
||||
return sqlite3_realloc64(pOld, newCount*unitSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1228,6 +1228,14 @@ int sqlite3_str_length(sqlite3_str *p){
|
||||
return p ? p->nChar : 0;
|
||||
}
|
||||
|
||||
/* Truncate the text of the string to be no more than N bytes. */
|
||||
void sqlite3_str_truncate(sqlite3_str *p, int N){
|
||||
if( p!=0 && N>=0 && (u32)N<p->nChar ){
|
||||
p->nChar = N;
|
||||
p->zText[p->nChar] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the current value for p */
|
||||
char *sqlite3_str_value(sqlite3_str *p){
|
||||
if( p==0 || p->nChar==0 ) return 0;
|
||||
@@ -1248,6 +1256,17 @@ void sqlite3_str_reset(StrAccum *p){
|
||||
p->zText = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy a dynamically allocate sqlite3_str object and all
|
||||
** of its content, all in one call.
|
||||
*/
|
||||
void sqlite3_str_free(sqlite3_str *p){
|
||||
if( p ){
|
||||
sqlite3_str_reset(p);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a string accumulator.
|
||||
**
|
||||
|
||||
+5
-2
@@ -373,10 +373,13 @@ static int lookupName(
|
||||
if( cnt>0 ){
|
||||
if( pItem->fg.isUsing==0
|
||||
|| sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
|
||||
|| pMatch==pItem
|
||||
){
|
||||
/* Two or more tables have the same column name which is
|
||||
** not joined by USING. This is an error. Signal as much
|
||||
** by clearing pFJMatch and letting cnt go above 1. */
|
||||
** not joined by USING. Or, a single table has two columns
|
||||
** that match a USING term (if pMatch==pItem). These are both
|
||||
** "ambiguous column name" errors. Signal as much by clearing
|
||||
** pFJMatch and letting cnt go above 1. */
|
||||
sqlite3ExprListDelete(db, pFJMatch);
|
||||
pFJMatch = 0;
|
||||
}else
|
||||
|
||||
@@ -6823,6 +6823,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
if( pFunc->bOBPayload ){
|
||||
/* extra columns for the function arguments */
|
||||
assert( ExprUseXList(pFunc->pFExpr) );
|
||||
assert( pFunc->pFExpr->x.pList!=0 );
|
||||
nExtra += pFunc->pFExpr->x.pList->nExpr;
|
||||
}
|
||||
if( pFunc->bUseSubtype ){
|
||||
|
||||
+108
-54
@@ -1516,7 +1516,7 @@ struct ShellState {
|
||||
int inputNesting; /* Track nesting level of .read and other redirects */
|
||||
int outCount; /* Revert to stdout when reaching zero */
|
||||
int cnt; /* Number of records displayed so far */
|
||||
int lineno; /* Line number of last line read from in */
|
||||
i64 lineno; /* Line number of last line read from in */
|
||||
int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
|
||||
FILE *in; /* Read commands from this stream */
|
||||
FILE *out; /* Write results here */
|
||||
@@ -1752,7 +1752,7 @@ static void failIfSafeMode(
|
||||
va_start(ap, zErrMsg);
|
||||
zMsg = sqlite3_vmprintf(zErrMsg, ap);
|
||||
va_end(ap);
|
||||
sqlite3_fprintf(stderr, "line %d: %s\n", p->lineno, zMsg);
|
||||
sqlite3_fprintf(stderr, "line %lld: %s\n", p->lineno, zMsg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -4963,6 +4963,9 @@ static void toggleSelectOrder(sqlite3 *db){
|
||||
sqlite3_exec(db, zStmt, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Forward reference */
|
||||
static int db_int(sqlite3 *db, const char *zSql, ...);
|
||||
|
||||
/*
|
||||
** This is a different callback routine used for dumping the database.
|
||||
** Each row received by this callback consists of a table name,
|
||||
@@ -4989,7 +4992,21 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
|
||||
noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
|
||||
|
||||
if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
|
||||
/* no-op */
|
||||
/* The sqlite_sequence table is repopulated last. Delete content
|
||||
** in the sqlite_sequence table added by prior repopulations prior to
|
||||
** repopulating sqlite_sequence itself. But only do this if the
|
||||
** table is non-empty, because if it is empty the table might not
|
||||
** have been recreated by prior repopulations. See forum posts:
|
||||
** 2024-10-13T17:10:01z and 2025-10-29T19:38:43z
|
||||
*/
|
||||
if( db_int(p->db, "SELECT count(*) FROM sqlite_sequence")>0 ){
|
||||
if( !p->writableSchema ){
|
||||
sqlite3_fputs("PRAGMA writable_schema=ON;\n", p->out);
|
||||
p->writableSchema = 1;
|
||||
}
|
||||
sqlite3_fputs("CREATE TABLE IF NOT EXISTS sqlite_sequence(name,seq);\n"
|
||||
"DELETE FROM sqlite_sequence;\n", p->out);
|
||||
}
|
||||
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
|
||||
if( !dataOnly ) sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
|
||||
}else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
|
||||
@@ -5308,6 +5325,7 @@ static const char *(azHelp[]) = {
|
||||
" --maxsize N Maximum size for --hexdb or --deserialized database",
|
||||
#endif
|
||||
" --new Initialize FILE to an empty database",
|
||||
" --normal FILE is an ordinary SQLite database",
|
||||
" --nofollow Do not follow symbolic links",
|
||||
" --readonly Open FILE readonly",
|
||||
" --zip FILE is a ZIP archive",
|
||||
@@ -5542,7 +5560,7 @@ static int showHelp(FILE *out, const char *zPattern){
|
||||
}
|
||||
|
||||
/* Forward reference */
|
||||
static int process_input(ShellState *p);
|
||||
static int process_input(ShellState *p, const char*);
|
||||
|
||||
/*
|
||||
** Read the content of file zName into memory obtained from sqlite3_malloc64()
|
||||
@@ -5649,18 +5667,26 @@ static int session_filter(void *pCtx, const char *zTab){
|
||||
** Otherwise, assume an ordinary database regardless of the filename if
|
||||
** the type cannot be determined from content.
|
||||
*/
|
||||
int deduceDatabaseType(const char *zName, int dfltZip){
|
||||
FILE *f = sqlite3_fopen(zName, "rb");
|
||||
int deduceDatabaseType(const char *zName, int dfltZip, int openFlags){
|
||||
FILE *f;
|
||||
size_t n;
|
||||
sqlite3 *db = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc = SHELL_OPEN_UNSPEC;
|
||||
char zBuf[100];
|
||||
if( f==0 ){
|
||||
if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
|
||||
return SHELL_OPEN_ZIPFILE;
|
||||
}else{
|
||||
return SHELL_OPEN_NORMAL;
|
||||
}
|
||||
if( access(zName,0)!=0 ) goto database_type_by_name;
|
||||
if( sqlite3_open_v2(zName, &db, openFlags, 0)==SQLITE_OK
|
||||
&& sqlite3_prepare_v2(db,"SELECT count(*) FROM sqlite_schema",-1,&pStmt,0)
|
||||
==SQLITE_OK
|
||||
&& sqlite3_step(pStmt)==SQLITE_ROW
|
||||
){
|
||||
rc = SHELL_OPEN_NORMAL;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_close(db);
|
||||
if( rc==SHELL_OPEN_NORMAL ) return SHELL_OPEN_NORMAL;
|
||||
f = sqlite3_fopen(zName, "rb");
|
||||
if( f==0 ) goto database_type_by_name;
|
||||
n = fread(zBuf, 16, 1, f);
|
||||
if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){
|
||||
fclose(f);
|
||||
@@ -5682,6 +5708,14 @@ int deduceDatabaseType(const char *zName, int dfltZip){
|
||||
}
|
||||
fclose(f);
|
||||
return rc;
|
||||
|
||||
database_type_by_name:
|
||||
if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
|
||||
rc = SHELL_OPEN_ZIPFILE;
|
||||
}else{
|
||||
rc = SHELL_OPEN_NORMAL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
@@ -5692,7 +5726,7 @@ int deduceDatabaseType(const char *zName, int dfltZip){
|
||||
*/
|
||||
static unsigned char *readHexDb(ShellState *p, int *pnData){
|
||||
unsigned char *a = 0;
|
||||
int nLine;
|
||||
i64 nLine;
|
||||
int n = 0; /* Size of db per first line of hex dump */
|
||||
i64 sz = 0; /* n rounded up to nearest page boundary */
|
||||
int pgsz = 0;
|
||||
@@ -5731,6 +5765,10 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
|
||||
for(nLine++; sqlite3_fgets(zLine, sizeof(zLine), in)!=0; nLine++){
|
||||
int j = 0; /* Page number from "| page" line */
|
||||
int k = 0; /* Offset from "| page" line */
|
||||
if( nLine>=2000000000 ){
|
||||
sqlite3_fprintf(stderr, "input too big\n");
|
||||
goto readHexDb_error;
|
||||
}
|
||||
rc = sscanf(zLine, "| page %d offset %d", &j, &k);
|
||||
if( rc==2 ){
|
||||
iOffset = k;
|
||||
@@ -5769,7 +5807,7 @@ readHexDb_error:
|
||||
p->lineno = nLine;
|
||||
}
|
||||
sqlite3_free(a);
|
||||
sqlite3_fprintf(stderr,"Error on line %d of --hexdb input\n", nLine);
|
||||
sqlite3_fprintf(stderr,"Error on line %lld of --hexdb input\n", nLine);
|
||||
return 0;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_DESERIALIZE */
|
||||
@@ -5846,7 +5884,7 @@ static void open_db(ShellState *p, int openFlags){
|
||||
p->openMode = SHELL_OPEN_NORMAL;
|
||||
}else{
|
||||
p->openMode = (u8)deduceDatabaseType(zDbFilename,
|
||||
(openFlags & OPEN_DB_ZIPFILE)!=0);
|
||||
(openFlags & OPEN_DB_ZIPFILE)!=0, p->openFlags);
|
||||
}
|
||||
}
|
||||
if( (p->openFlags & (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE))==0 ){
|
||||
@@ -7187,39 +7225,42 @@ static void clearTempFile(ShellState *p){
|
||||
p->zTempFile = 0;
|
||||
}
|
||||
|
||||
/* Forward reference */
|
||||
static char *find_home_dir(int clearFlag);
|
||||
|
||||
/*
|
||||
** Create a new temp file name with the given suffix.
|
||||
**
|
||||
** Because the classic temp folders like /tmp are no longer
|
||||
** accessible to web browsers, for security reasons, create the
|
||||
** temp file in the user's home directory.
|
||||
*/
|
||||
static void newTempFile(ShellState *p, const char *zSuffix){
|
||||
char *zHome; /* Home directory */
|
||||
int i; /* Loop counter */
|
||||
sqlite3_uint64 r = 0; /* Integer with 64 bits of randomness */
|
||||
char zRand[32]; /* Text string with 160 bits of randomness */
|
||||
#ifdef _WIN32
|
||||
const char cDirSep = '\\';
|
||||
#else
|
||||
const char cDirSep = '/';
|
||||
#endif
|
||||
|
||||
for(i=0; i<31; i++){
|
||||
if( (i%12)==0 ) sqlite3_randomness(sizeof(r),&r);
|
||||
zRand[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[r%36];
|
||||
r /= 36;
|
||||
}
|
||||
zRand[i] = 0;
|
||||
clearTempFile(p);
|
||||
sqlite3_free(p->zTempFile);
|
||||
p->zTempFile = 0;
|
||||
if( p->db ){
|
||||
sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
|
||||
}
|
||||
if( p->zTempFile==0 ){
|
||||
/* If p->db is an in-memory database then the TEMPFILENAME file-control
|
||||
** will not work and we will need to fallback to guessing */
|
||||
char *zTemp;
|
||||
sqlite3_uint64 r;
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
zTemp = getenv("TEMP");
|
||||
if( zTemp==0 ) zTemp = getenv("TMP");
|
||||
if( zTemp==0 ){
|
||||
#ifdef _WIN32
|
||||
zTemp = "\\tmp";
|
||||
#else
|
||||
zTemp = "/tmp";
|
||||
#endif
|
||||
}
|
||||
p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
|
||||
}else{
|
||||
p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
|
||||
}
|
||||
zHome = find_home_dir(0);
|
||||
p->zTempFile = sqlite3_mprintf("%s%ctemp-%s.%s",
|
||||
zHome,cDirSep,zRand,zSuffix);
|
||||
shell_check_oom(p->zTempFile);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The implementation of SQL scalar function fkey_collate_clause(), used
|
||||
** by the ".lint fkey-indexes" command. This scalar function is always
|
||||
@@ -8227,7 +8268,7 @@ static int arDotCommand(
|
||||
cmd.out = pState->out;
|
||||
cmd.db = pState->db;
|
||||
if( cmd.zFile ){
|
||||
eDbType = deduceDatabaseType(cmd.zFile, 1);
|
||||
eDbType = deduceDatabaseType(cmd.zFile, 1, 0);
|
||||
}else{
|
||||
eDbType = pState->openMode;
|
||||
}
|
||||
@@ -9223,6 +9264,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
p->showHeader = savedShowHeader;
|
||||
p->shellFlgs = savedShellFlags;
|
||||
rc = p->nErr>0;
|
||||
}else
|
||||
|
||||
if( c=='e' && cli_strncmp(azArg[0], "echo", n)==0 ){
|
||||
@@ -9549,7 +9591,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
ImportCtx sCtx; /* Reader context */
|
||||
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
|
||||
int eVerbose = 0; /* Larger for more console output */
|
||||
int nSkip = 0; /* Initial lines to skip */
|
||||
i64 nSkip = 0; /* Initial lines to skip */
|
||||
int useOutputMode = 1; /* Use output mode to determine separators */
|
||||
char *zCreate = 0; /* CREATE TABLE statement text */
|
||||
|
||||
@@ -9676,7 +9718,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
shell_out_of_memory();
|
||||
}
|
||||
/* Below, resources must be freed before exit. */
|
||||
while( (nSkip--)>0 ){
|
||||
while( nSkip>0 ){
|
||||
nSkip--;
|
||||
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
|
||||
}
|
||||
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
|
||||
@@ -10274,7 +10317,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
eputz("Usage: .nonce NONCE\n");
|
||||
rc = 1;
|
||||
}else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
|
||||
sqlite3_fprintf(stderr,"line %d: incorrect nonce: \"%s\"\n",
|
||||
sqlite3_fprintf(stderr,"line %lld: incorrect nonce: \"%s\"\n",
|
||||
p->lineno, azArg[1]);
|
||||
exit(1);
|
||||
}else{
|
||||
@@ -10329,6 +10372,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
openMode = SHELL_OPEN_DESERIALIZE;
|
||||
}else if( optionMatch(z, "hexdb") ){
|
||||
openMode = SHELL_OPEN_HEXDB;
|
||||
}else if( optionMatch(z, "normal") ){
|
||||
openMode = SHELL_OPEN_NORMAL;
|
||||
}else if( optionMatch(z, "maxsize") && iName+1<nArg ){
|
||||
p->szMax = integerValue(azArg[++iName]);
|
||||
#endif /* SQLITE_OMIT_DESERIALIZE */
|
||||
@@ -10731,7 +10776,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
if( c=='r' && n>=3 && cli_strncmp(azArg[0], "read", n)==0 ){
|
||||
FILE *inSaved = p->in;
|
||||
int savedLineno = p->lineno;
|
||||
i64 savedLineno = p->lineno;
|
||||
failIfSafeMode(p, "cannot run .read in safe mode");
|
||||
if( nArg!=2 ){
|
||||
eputz("Usage: .read FILE\n");
|
||||
@@ -10748,7 +10793,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
|
||||
rc = 1;
|
||||
}else{
|
||||
rc = process_input(p);
|
||||
rc = process_input(p, "<pipe>");
|
||||
pclose(p->in);
|
||||
}
|
||||
#endif
|
||||
@@ -10756,7 +10801,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
|
||||
rc = 1;
|
||||
}else{
|
||||
rc = process_input(p);
|
||||
rc = process_input(p, azArg[1]);
|
||||
fclose(p->in);
|
||||
}
|
||||
p->in = inSaved;
|
||||
@@ -12747,7 +12792,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
|
||||
**
|
||||
** Return the number of errors.
|
||||
*/
|
||||
static int process_input(ShellState *p){
|
||||
static int process_input(ShellState *p, const char *zSrc){
|
||||
char *zLine = 0; /* A single input line */
|
||||
char *zSql = 0; /* Accumulated SQL text */
|
||||
i64 nLine; /* Length of current line */
|
||||
@@ -12760,8 +12805,8 @@ static int process_input(ShellState *p){
|
||||
|
||||
if( p->inputNesting==MAX_INPUT_NESTING ){
|
||||
/* This will be more informative in a later version. */
|
||||
sqlite3_fprintf(stderr,"Input nesting limit (%d) reached at line %d."
|
||||
" Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
|
||||
sqlite3_fprintf(stderr,"%s: Input nesting limit (%d) reached at line %lld."
|
||||
" Check recursion.\n", zSrc, MAX_INPUT_NESTING, p->lineno);
|
||||
return 1;
|
||||
}
|
||||
++p->inputNesting;
|
||||
@@ -12826,7 +12871,15 @@ static int process_input(ShellState *p){
|
||||
memcpy(zSql+nSql, zLine, nLine+1);
|
||||
nSql += nLine;
|
||||
}
|
||||
if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
|
||||
if( nSql>0x7fff0000 ){
|
||||
char zSize[100];
|
||||
sqlite3_snprintf(sizeof(zSize),zSize,"%,lld",nSql);
|
||||
sqlite3_fprintf(stderr, "%s:%lld: Input SQL is too big: %s bytes\n",
|
||||
zSrc, startline, zSize);
|
||||
nSql = 0;
|
||||
errCnt++;
|
||||
break;
|
||||
}else if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
|
||||
echo_group_input(p, zSql);
|
||||
errCnt += runOneSqlLine(p, zSql, p->in, startline);
|
||||
CONTINUE_PROMPT_RESET;
|
||||
@@ -12994,7 +13047,7 @@ static void process_sqliterc(
|
||||
char *home_dir = NULL;
|
||||
char *sqliterc = (char*)sqliterc_override;
|
||||
FILE *inSaved = p->in;
|
||||
int savedLineno = p->lineno;
|
||||
i64 savedLineno = p->lineno;
|
||||
|
||||
if( sqliterc == NULL ){
|
||||
sqliterc = find_xdg_file("XDG_CONFIG_HOME",
|
||||
@@ -13016,7 +13069,7 @@ static void process_sqliterc(
|
||||
if( stdin_is_interactive ){
|
||||
sqlite3_fprintf(stderr,"-- Loading resources from %s\n", sqliterc);
|
||||
}
|
||||
if( process_input(p) && bail_on_error ) exit(1);
|
||||
if( process_input(p, sqliterc) && bail_on_error ) exit(1);
|
||||
fclose(p->in);
|
||||
}else if( sqliterc_override!=0 ){
|
||||
sqlite3_fprintf(stderr,"cannot open: \"%s\"\n", sqliterc);
|
||||
@@ -13745,6 +13798,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
rc = shell_exec(&data, z, &zErrMsg);
|
||||
if( zErrMsg!=0 ){
|
||||
shellEmitError(zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
if( bail_on_error ) return rc!=0 ? rc : 1;
|
||||
}else if( rc!=0 ){
|
||||
sqlite3_fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
|
||||
@@ -13847,7 +13901,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
linenoiseSetCompletionCallback(linenoise_completion, NULL);
|
||||
#endif
|
||||
data.in = 0;
|
||||
rc = process_input(&data);
|
||||
rc = process_input(&data, "<stdin>");
|
||||
if( zHistory ){
|
||||
shell_stifle_history(2000);
|
||||
shell_write_history(zHistory);
|
||||
@@ -13855,7 +13909,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
}
|
||||
}else{
|
||||
data.in = stdin;
|
||||
rc = process_input(&data);
|
||||
rc = process_input(&data, "<stdin>");
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
@@ -14037,7 +14091,7 @@ void fiddle_exec(const char * zSql){
|
||||
if('.'==*zSql) puts(zSql);
|
||||
shellState.wasm.zInput = zSql;
|
||||
shellState.wasm.zPos = zSql;
|
||||
process_input(&shellState);
|
||||
process_input(&shellState, "<stdin>");
|
||||
shellState.wasm.zInput = shellState.wasm.zPos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+48
-20
@@ -932,7 +932,7 @@ struct sqlite3_io_methods {
|
||||
** connection. See also [SQLITE_FCNTL_FILE_POINTER].
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
|
||||
** No longer in use.
|
||||
** The SQLITE_FCNTL_SYNC_OMITTED file-control is no longer used.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_SYNC]]
|
||||
** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and
|
||||
@@ -1229,6 +1229,15 @@ struct sqlite3_io_methods {
|
||||
** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
|
||||
** purges the contents of the in-memory page cache. If there is an open
|
||||
** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_FILESTAT]]
|
||||
** The [SQLITE_FCNTL_FILESTAT] opcode returns low-level diagnostic information
|
||||
** about the [sqlite3_file] objects used access the database and journal files
|
||||
** for the given schema. The fourth parameter to [sqlite3_file_control()]
|
||||
** should be an initialized [sqlite3_str] pointer. JSON text describing
|
||||
** various aspects of the sqlite3_file object is appended to the sqlite3_str.
|
||||
** The SQLITE_FCNTL_FILESTAT opcode is usually a no-op, unless compile-time
|
||||
** options are used to enable it.
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
@@ -1274,6 +1283,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_RESET_CACHE 42
|
||||
#define SQLITE_FCNTL_NULL_IO 43
|
||||
#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44
|
||||
#define SQLITE_FCNTL_FILESTAT 45
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@@ -2557,12 +2567,15 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
|
||||
** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
|
||||
** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
|
||||
** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
|
||||
** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
|
||||
** statistics. For statistics to be collected, the flag must be set on
|
||||
** the database handle both when the SQL statement is prepared and when it
|
||||
** is stepped. The flag is set (collection of statistics is enabled)
|
||||
** by default. <p>This option takes two arguments: an integer and a pointer to
|
||||
** [SQLITE_ENABLE_STMT_SCANSTATUS] builds. In this case, it sets or clears
|
||||
** a flag that enables collection of run-time performance statistics
|
||||
** used by [sqlite3_stmt_scanstatus_v2()] and the [nexec and ncycle]
|
||||
** columns of the [bytecode virtual table].
|
||||
** For statistics to be collected, the flag must be set on
|
||||
** the database handle both when the SQL statement is
|
||||
** [sqlite3_prepare|prepared] and when it is [sqlite3_step|stepped].
|
||||
** The flag is set (collection of statistics is enabled) by default.
|
||||
** <p>This option takes two arguments: an integer and a pointer to
|
||||
** an integer. The first argument is 1, 0, or -1 to enable, disable, or
|
||||
** leave unchanged the statement scanstatus option. If the second argument
|
||||
** is not NULL, then the value of the statement scanstatus setting after
|
||||
@@ -4207,7 +4220,7 @@ const char *sqlite3_errstr(int);
|
||||
int sqlite3_error_offset(sqlite3 *db);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Set Error Codes And Message
|
||||
** CAPI3REF: Set Error Code And Message
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** Set the error code of the database handle passed as the first argument
|
||||
@@ -4907,9 +4920,11 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** associated with the pointer P of type T. ^D is either a NULL pointer or
|
||||
** a pointer to a destructor function for P. ^SQLite will invoke the
|
||||
** destructor D with a single argument of P when it is finished using
|
||||
** P. The T parameter should be a static string, preferably a string
|
||||
** literal. The sqlite3_bind_pointer() routine is part of the
|
||||
** [pointer passing interface] added for SQLite 3.20.0.
|
||||
** P, even if the call to sqlite3_bind_pointer() fails. Due to a
|
||||
** historical design quirk, results are undefined if D is
|
||||
** SQLITE_TRANSIENT. The T parameter should be a static string,
|
||||
** preferably a string literal. The sqlite3_bind_pointer() routine is
|
||||
** part of the [pointer passing interface] added for SQLite 3.20.0.
|
||||
**
|
||||
** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
|
||||
** for the [prepared statement] or with a prepared statement for which
|
||||
@@ -8712,15 +8727,20 @@ sqlite3_str *sqlite3_str_new(sqlite3*);
|
||||
** errors were encountered during construction of the string. ^The
|
||||
** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the
|
||||
** string in [sqlite3_str] object X is zero bytes long.
|
||||
**
|
||||
** ^The [sqlite3_str_free(X)] interface destroys both the sqlite3_str object
|
||||
** X and the string content it contains. Calling sqlite3_str_free(X) is
|
||||
** the equivalent of calling [sqlite3_free](sqlite3_str_finish(X)).
|
||||
*/
|
||||
char *sqlite3_str_finish(sqlite3_str*);
|
||||
void sqlite3_str_free(sqlite3_str*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Add Content To A Dynamic String
|
||||
** METHOD: sqlite3_str
|
||||
**
|
||||
** These interfaces add content to an sqlite3_str object previously obtained
|
||||
** from [sqlite3_str_new()].
|
||||
** These interfaces add or remove content to an sqlite3_str object
|
||||
** previously obtained from [sqlite3_str_new()].
|
||||
**
|
||||
** ^The [sqlite3_str_appendf(X,F,...)] and
|
||||
** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf]
|
||||
@@ -8743,6 +8763,10 @@ char *sqlite3_str_finish(sqlite3_str*);
|
||||
** ^The [sqlite3_str_reset(X)] method resets the string under construction
|
||||
** inside [sqlite3_str] object X back to zero bytes in length.
|
||||
**
|
||||
** ^The [sqlite3_str_truncate(X,N)] method changes the length of the string
|
||||
** under construction to be N bytes are less. This routine is a no-op if
|
||||
** N is negative or if the string is already N bytes or smaller in size.
|
||||
**
|
||||
** These methods do not return a result code. ^If an error occurs, that fact
|
||||
** is recorded in the [sqlite3_str] object and can be recovered by a
|
||||
** subsequent call to [sqlite3_str_errcode(X)].
|
||||
@@ -8753,6 +8777,7 @@ void sqlite3_str_append(sqlite3_str*, const char *zIn, int N);
|
||||
void sqlite3_str_appendall(sqlite3_str*, const char *zIn);
|
||||
void sqlite3_str_appendchar(sqlite3_str*, int N, char C);
|
||||
void sqlite3_str_reset(sqlite3_str*);
|
||||
void sqlite3_str_truncate(sqlite3_str*,int N);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Of A Dynamic String
|
||||
@@ -10414,7 +10439,7 @@ int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
|
||||
** ){
|
||||
** // do something with pVal
|
||||
** }
|
||||
** if( rc!=SQLITE_OK ){
|
||||
** if( rc!=SQLITE_DONE ){
|
||||
** // an error has occurred
|
||||
** }
|
||||
** </pre></blockquote>)^
|
||||
@@ -10586,9 +10611,9 @@ int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
|
||||
** a variable pointed to by the "pOut" parameter.
|
||||
**
|
||||
** The "flags" parameter must be passed a mask of flags. At present only
|
||||
** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
|
||||
** one flag is defined - [SQLITE_SCANSTAT_COMPLEX]. If SQLITE_SCANSTAT_COMPLEX
|
||||
** is specified, then status information is available for all elements
|
||||
** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
|
||||
** of a query plan that are reported by "[EXPLAIN QUERY PLAN]" output. If
|
||||
** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
|
||||
** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
|
||||
** the EXPLAIN QUERY PLAN output) are available. Invoking API
|
||||
@@ -10602,7 +10627,8 @@ int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
|
||||
** elements used to implement the statement - a non-zero value is returned and
|
||||
** the variable that pOut points to is unchanged.
|
||||
**
|
||||
** See also: [sqlite3_stmt_scanstatus_reset()]
|
||||
** See also: [sqlite3_stmt_scanstatus_reset()] and the
|
||||
** [nexec and ncycle] columnes of the [bytecode virtual table].
|
||||
*/
|
||||
int sqlite3_stmt_scanstatus(
|
||||
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
|
||||
@@ -11153,9 +11179,11 @@ int sqlite3_deserialize(
|
||||
** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], or [SQLITE_CARRAY_BLOB] to
|
||||
** indicate the datatype of the array being bound. The X argument is not a
|
||||
** NULL pointer, then SQLite will invoke the function X on the P parameter
|
||||
** after it has finished using P.
|
||||
** after it has finished using P, even if the call to
|
||||
** sqlite3_carray_bind() fails. The special-case finalizer
|
||||
** SQLITE_TRANSIENT has no effect here.
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt, /* Statement to be bound */
|
||||
int i, /* Parameter index */
|
||||
void *aData, /* Pointer to array data */
|
||||
@@ -11165,7 +11193,7 @@ SQLITE_API int sqlite3_carray_bind(
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Datatypes for the CARRAY table-valued funtion
|
||||
** CAPI3REF: Datatypes for the CARRAY table-valued function
|
||||
**
|
||||
** The fifth argument to the [sqlite3_carray_bind()] interface musts be
|
||||
** one of the following constants, to specify the datatype of the array
|
||||
|
||||
+6
-1
@@ -371,7 +371,9 @@ struct sqlite3_api_routines {
|
||||
/* Version 3.51.0 and later */
|
||||
int (*set_errmsg)(sqlite3*,int,const char*);
|
||||
int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
|
||||
/* Version 3.52.0 and later */
|
||||
void (*str_truncate)(sqlite3_str*,int);
|
||||
void (*str_free)(sqlite3_str*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -710,6 +712,9 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
/* Version 3.51.0 and later */
|
||||
#define sqlite3_set_errmsg sqlite3_api->set_errmsg
|
||||
#define sqlite3_db_status64 sqlite3_api->db_status64
|
||||
/* Version 3.52.0 and later */
|
||||
#define sqlite3_str_truncate sqlite3_api->str_truncate
|
||||
#define sqlite3_str_free sqlite3_api->str_free
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+1
-1
@@ -5452,7 +5452,7 @@ void sqlite3Reindex(Parse*, Token*, Token*);
|
||||
void sqlite3AlterFunctions(void);
|
||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
|
||||
int sqlite3GetToken(const unsigned char *, int *);
|
||||
i64 sqlite3GetToken(const unsigned char *, int *);
|
||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
||||
void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
|
||||
|
||||
+33
@@ -4972,6 +4972,37 @@ static int SQLITE_TCLAPI test_errmsg16(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_set_errmsg DB ERRCODE ERRMSG
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_set_errmsg(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
const char *zDb = 0;
|
||||
const char *zErr = 0;
|
||||
int iErr = 0;
|
||||
sqlite3 *db = 0;
|
||||
int rc;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB ERRCODE ERRMSG");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zDb = Tcl_GetString(objv[1]);
|
||||
if( zDb[0] ){
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &iErr) ) return TCL_ERROR;
|
||||
zErr = Tcl_GetString(objv[3]);
|
||||
|
||||
rc = sqlite3_set_errmsg(db, iErr, (zErr[0] ? zErr : 0));
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_prepare DB sql bytes ?tailvar?
|
||||
**
|
||||
@@ -8274,6 +8305,7 @@ static int SQLITE_TCLAPI optimization_control(
|
||||
{ "balanced-merge", SQLITE_BalancedMerge },
|
||||
{ "propagate-const", SQLITE_PropagateConst },
|
||||
{ "one-pass", SQLITE_OnePass },
|
||||
{ "exists-to-join", SQLITE_ExistsToJoin },
|
||||
};
|
||||
|
||||
if( objc!=4 ){
|
||||
@@ -9077,6 +9109,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_errmsg", test_errmsg ,0 },
|
||||
{ "sqlite3_error_offset", test_error_offset ,0 },
|
||||
{ "sqlite3_errmsg16", test_errmsg16 ,0 },
|
||||
{ "sqlite3_set_errmsg", test_set_errmsg ,0 },
|
||||
{ "sqlite3_open", test_open ,0 },
|
||||
{ "sqlite3_open16", test_open16 ,0 },
|
||||
{ "sqlite3_open_v2", test_open_v2 ,0 },
|
||||
|
||||
+107
-11
@@ -101,6 +101,7 @@
|
||||
typedef struct tcl_vtab tcl_vtab;
|
||||
typedef struct tcl_cursor tcl_cursor;
|
||||
typedef struct TestFindFunction TestFindFunction;
|
||||
typedef struct TestVtabContext TestVtabContext;
|
||||
|
||||
/*
|
||||
** A fs virtual-table object
|
||||
@@ -125,6 +126,10 @@ struct TestFindFunction {
|
||||
TestFindFunction *pNext;
|
||||
};
|
||||
|
||||
struct TestVtabContext {
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *pDefault;
|
||||
};
|
||||
|
||||
/*
|
||||
** Dequote string z in place.
|
||||
@@ -178,25 +183,33 @@ static int tclConnect(
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
Tcl_Interp *interp = (Tcl_Interp*)pAux;
|
||||
TestVtabContext *pCtx = (TestVtabContext*)pAux;
|
||||
Tcl_Interp *interp = pCtx->interp;
|
||||
tcl_vtab *pTab = 0;
|
||||
char *zCmd = 0;
|
||||
Tcl_Obj *pScript = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( argc!=4 ){
|
||||
if( argc!=4 && (argc!=3 || pCtx->pDefault==0) ){
|
||||
*pzErr = sqlite3_mprintf("wrong number of arguments");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
zCmd = sqlite3_malloc64(strlen(argv[3])+1);
|
||||
if( argc==4 ){
|
||||
zCmd = sqlite3_malloc64(strlen(argv[3])+1);
|
||||
}
|
||||
pTab = (tcl_vtab*)sqlite3_malloc64(sizeof(tcl_vtab));
|
||||
if( zCmd && pTab ){
|
||||
memcpy(zCmd, argv[3], strlen(argv[3])+1);
|
||||
tclDequote(zCmd);
|
||||
if( (zCmd || argc==3) && pTab ){
|
||||
memset(pTab, 0, sizeof(tcl_vtab));
|
||||
|
||||
pTab->pCmd = Tcl_NewStringObj(zCmd, -1);
|
||||
if( zCmd ){
|
||||
memcpy(zCmd, argv[3], strlen(argv[3])+1);
|
||||
tclDequote(zCmd);
|
||||
pTab->pCmd = Tcl_NewStringObj(zCmd, -1);
|
||||
}else{
|
||||
pTab->pCmd = Tcl_DuplicateObj(pCtx->pDefault);
|
||||
}
|
||||
|
||||
pTab->interp = interp;
|
||||
pTab->db = db;
|
||||
Tcl_IncrRefCount(pTab->pCmd);
|
||||
@@ -208,7 +221,11 @@ static int tclConnect(
|
||||
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
|
||||
if( rc!=TCL_OK ){
|
||||
*pzErr = sqlite3_mprintf("%s", Tcl_GetStringResult(interp));
|
||||
rc = SQLITE_ERROR;
|
||||
if( sqlite3_stricmp(*pzErr, "database schema has changed")==0 ){
|
||||
rc = SQLITE_SCHEMA;
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3_declare_vtab(db, Tcl_GetStringResult(interp));
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -802,6 +819,38 @@ static int tclFindFunction(
|
||||
return iRet;
|
||||
}
|
||||
|
||||
static int tclUpdate(
|
||||
sqlite3_vtab *tab,
|
||||
int nArg,
|
||||
sqlite3_value **apVal,
|
||||
sqlite3_int64 *piRowid
|
||||
){
|
||||
tcl_vtab *pTab = (tcl_vtab*)tab;
|
||||
Tcl_Interp *interp = pTab->interp;
|
||||
Tcl_Obj *pEval = Tcl_DuplicateObj(pTab->pCmd);
|
||||
int rc = TCL_OK;
|
||||
|
||||
Tcl_IncrRefCount(pEval);
|
||||
Tcl_ListObjAppendElement(interp, pEval, Tcl_NewStringObj("xUpdate",-1));
|
||||
|
||||
rc = Tcl_EvalObjEx(interp, pEval, TCL_EVAL_GLOBAL);
|
||||
Tcl_DecrRefCount(pEval);
|
||||
|
||||
if( rc==TCL_OK ){
|
||||
Tcl_Obj *pRes = Tcl_GetObjResult(interp);
|
||||
Tcl_WideInt v;
|
||||
rc = Tcl_GetWideIntFromObj(interp, pRes, &v);
|
||||
*piRowid = (sqlite3_int64)v;
|
||||
}
|
||||
|
||||
if( rc!=TCL_OK ){
|
||||
tab->zErrMsg = sqlite3_mprintf("%s", Tcl_GetStringResult(pTab->interp));
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** A virtual table module that provides read-only access to a
|
||||
** Tcl global variable namespace.
|
||||
@@ -833,12 +882,47 @@ static sqlite3_module tclModule = {
|
||||
0, /* xShadowName */
|
||||
0 /* xIntegrity */
|
||||
};
|
||||
static sqlite3_module tclModuleUpdate = {
|
||||
0, /* iVersion */
|
||||
tclConnect,
|
||||
tclConnect,
|
||||
tclBestIndex,
|
||||
tclDisconnect,
|
||||
tclDisconnect,
|
||||
tclOpen, /* xOpen - open a cursor */
|
||||
tclClose, /* xClose - close a cursor */
|
||||
tclFilter, /* xFilter - configure scan constraints */
|
||||
tclNext, /* xNext - advance a cursor */
|
||||
tclEof, /* xEof - check for end of scan */
|
||||
tclColumn, /* xColumn - read data */
|
||||
tclRowid, /* xRowid - read data */
|
||||
tclUpdate, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
tclFindFunction, /* xFindFunction */
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
0 /* xIntegrity */
|
||||
};
|
||||
|
||||
/*
|
||||
** Decode a pointer to an sqlite3 object.
|
||||
*/
|
||||
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
|
||||
static void delTestVtabCtx(void *p){
|
||||
TestVtabContext *pCtx = (TestVtabContext*)p;
|
||||
if( pCtx->pDefault ){
|
||||
Tcl_DecrRefCount(pCtx->pDefault);
|
||||
}
|
||||
ckfree(pCtx);
|
||||
}
|
||||
|
||||
/*
|
||||
** Register the echo virtual table module.
|
||||
*/
|
||||
@@ -849,13 +933,25 @@ static int SQLITE_TCLAPI register_tcl_module(
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB ?DEFAULT-CMD?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3_create_module(db, "tcl", &tclModule, (void *)interp);
|
||||
{
|
||||
sqlite3_module *pMod = &tclModule;
|
||||
TestVtabContext *pCtx = (TestVtabContext*)ckalloc(sizeof(TestVtabContext));
|
||||
pCtx->interp = interp;
|
||||
pCtx->pDefault = 0;
|
||||
if( objc==3 ){
|
||||
pCtx->pDefault = objv[2];
|
||||
Tcl_IncrRefCount(pCtx->pDefault);
|
||||
}
|
||||
|
||||
if( objc==3 ){ pMod = &tclModuleUpdate; }
|
||||
sqlite3_create_module_v2(db, "tcl", pMod, (void*)pCtx, delTestVtabCtx);
|
||||
}
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+7
-6
@@ -270,8 +270,9 @@ static int analyzeFilterKeyword(const unsigned char *z, int lastToken){
|
||||
** Return the length (in bytes) of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
*/
|
||||
int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
int i, c;
|
||||
i64 sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
i64 i;
|
||||
int c;
|
||||
switch( aiClass[*z] ){ /* Switch on the character-class of the first byte
|
||||
** of the token. See the comment on the CC_ defines
|
||||
** above. */
|
||||
@@ -599,7 +600,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
int nErr = 0; /* Number of errors encountered */
|
||||
void *pEngine; /* The LEMON-generated LALR(1) parser */
|
||||
int n = 0; /* Length of the next token token */
|
||||
i64 n = 0; /* Length of the next token token */
|
||||
int tokenType; /* type of the next token */
|
||||
int lastTokenParsed = -1; /* type of the previous token */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
@@ -702,13 +703,13 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
}else if( tokenType!=TK_QNUMBER ){
|
||||
Token x;
|
||||
x.z = zSql;
|
||||
x.n = n;
|
||||
x.n = (u32)n;
|
||||
sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pParse->sLastToken.z = zSql;
|
||||
pParse->sLastToken.n = n;
|
||||
pParse->sLastToken.n = (u32)n;
|
||||
sqlite3Parser(pEngine, tokenType, pParse->sLastToken);
|
||||
lastTokenParsed = tokenType;
|
||||
zSql += n;
|
||||
@@ -784,7 +785,7 @@ char *sqlite3Normalize(
|
||||
){
|
||||
sqlite3 *db; /* The database connection */
|
||||
int i; /* Next unread byte of zSql[] */
|
||||
int n; /* length of current token */
|
||||
i64 n; /* length of current token */
|
||||
int tokenType; /* type of current token */
|
||||
int prevType = 0; /* Previous non-whitespace token */
|
||||
int nParen; /* Number of nested levels of parentheses */
|
||||
|
||||
@@ -1823,6 +1823,9 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
|
||||
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
#if SQLITE_MAX_LENGTH>2147483645
|
||||
if( nByte>2147483645 ){ goto too_big; }
|
||||
#endif
|
||||
if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
+1
-2
@@ -557,8 +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 */
|
||||
union {
|
||||
KeyInfo sKey;
|
||||
struct {
|
||||
u8 keyinfoSpace[SZ_KEYINFO_0]; /* Space to hold pKeyinfo[0] content */
|
||||
} uKey;
|
||||
};
|
||||
|
||||
@@ -736,6 +736,8 @@ static int doWalCallbacks(sqlite3 *db){
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
+1
-1
@@ -5538,7 +5538,7 @@ void sqlite3VdbePreUpdateHook(
|
||||
preupdate.pCsr = pCsr;
|
||||
preupdate.op = op;
|
||||
preupdate.iNewReg = iReg;
|
||||
preupdate.pKeyinfo = &preupdate.uKey.sKey;
|
||||
preupdate.pKeyinfo = (KeyInfo*)&preupdate.uKey;
|
||||
preupdate.pKeyinfo->db = db;
|
||||
preupdate.pKeyinfo->enc = ENC(db);
|
||||
preupdate.pKeyinfo->nKeyField = pTab->nCol;
|
||||
|
||||
@@ -1226,6 +1226,7 @@ int sqlite3VdbeMemSetStr(
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
assert( pMem->z!=0 );
|
||||
memcpy(pMem->z, z, nAlloc);
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
|
||||
+5
-5
@@ -26,10 +26,10 @@
|
||||
** a host parameter. If the text contains no host parameters, return
|
||||
** the total number of bytes in the text.
|
||||
*/
|
||||
static int findNextHostParameter(const char *zSql, int *pnToken){
|
||||
static i64 findNextHostParameter(const char *zSql, i64 *pnToken){
|
||||
int tokenType;
|
||||
int nTotal = 0;
|
||||
int n;
|
||||
i64 nTotal = 0;
|
||||
i64 n;
|
||||
|
||||
*pnToken = 0;
|
||||
while( zSql[0] ){
|
||||
@@ -76,8 +76,8 @@ char *sqlite3VdbeExpandSql(
|
||||
sqlite3 *db; /* The database connection */
|
||||
int idx = 0; /* Index of a host parameter */
|
||||
int nextIndex = 1; /* Index of next ? host parameter */
|
||||
int n; /* Length of a token prefix */
|
||||
int nToken; /* Length of the parameter token */
|
||||
i64 n; /* Length of a token prefix */
|
||||
i64 nToken; /* Length of the parameter token */
|
||||
int i; /* Loop counter */
|
||||
Mem *pVar; /* Value of a host parameter */
|
||||
StrAccum out; /* Accumulate the output here */
|
||||
|
||||
@@ -1279,9 +1279,12 @@ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
|
||||
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
|
||||
addModuleArgument(pParse, pTab, 0);
|
||||
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
|
||||
db->nSchemaLock++;
|
||||
rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr);
|
||||
db->nSchemaLock--;
|
||||
if( rc ){
|
||||
sqlite3ErrorMsg(pParse, "%s", zErr);
|
||||
pParse->rc = rc;
|
||||
sqlite3DbFree(db, zErr);
|
||||
sqlite3VtabEponymousTableClear(db, pMod);
|
||||
}
|
||||
|
||||
@@ -602,7 +602,7 @@ struct WalIterator {
|
||||
|
||||
/* Size (in bytes) of a WalIterator object suitable for N or fewer segments */
|
||||
#define SZ_WALITERATOR(N) \
|
||||
(offsetof(WalIterator,aSegment)*(N)*sizeof(struct WalSegment))
|
||||
(offsetof(WalIterator,aSegment)+(N)*sizeof(struct WalSegment))
|
||||
|
||||
/*
|
||||
** Define the parameters of the hash tables in the wal-index file. There
|
||||
@@ -3488,7 +3488,7 @@ void sqlite3WalEndReadTransaction(Wal *pWal){
|
||||
assert( pWal->writeLock==0 || pWal->readLock<0 );
|
||||
#endif
|
||||
if( pWal->readLock>=0 ){
|
||||
sqlite3WalEndWriteTransaction(pWal);
|
||||
(void)sqlite3WalEndWriteTransaction(pWal);
|
||||
walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
|
||||
pWal->readLock = -1;
|
||||
}
|
||||
@@ -4395,7 +4395,7 @@ int sqlite3WalCheckpoint(
|
||||
sqlite3WalDb(pWal, 0);
|
||||
|
||||
/* Release the locks. */
|
||||
sqlite3WalEndWriteTransaction(pWal);
|
||||
(void)sqlite3WalEndWriteTransaction(pWal);
|
||||
if( pWal->ckptLock ){
|
||||
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||
pWal->ckptLock = 0;
|
||||
|
||||
+16
-2
@@ -7424,8 +7424,22 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
|
||||
}
|
||||
#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
|
||||
if( pTabList->a[pLevel->iFrom].fg.fromExists ){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2);
|
||||
if( pTabList->a[pLevel->iFrom].fg.fromExists && i==pWInfo->nLevel-1 ){
|
||||
/* If the EXISTS-to-JOIN optimization was applied, then the EXISTS
|
||||
** loop(s) will be the inner-most loops of the join. There might be
|
||||
** multiple EXISTS loops, but they will all be nested, and the join
|
||||
** order will not have been changed by the query planner. If the
|
||||
** inner-most EXISTS loop sees a single successful row, it should
|
||||
** break out of *all* EXISTS loops. But only the inner-most of the
|
||||
** nested EXISTS loops should do this breakout. */
|
||||
int nOuter = 0; /* Nr of outer EXISTS that this one is nested within */
|
||||
while( nOuter<i ){
|
||||
if( !pTabList->a[pLevel[-nOuter-1].iFrom].fg.fromExists ) break;
|
||||
nOuter++;
|
||||
}
|
||||
testcase( nOuter>0 );
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel[-nOuter].addrBrk);
|
||||
VdbeComment((v, "EXISTS break"));
|
||||
}
|
||||
/* The common case: Advance to the next row */
|
||||
if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
|
||||
+62
-1
@@ -13,7 +13,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix bestindex1
|
||||
set testprefix bestindexE
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
@@ -124,7 +124,68 @@ do_bestindex_test 2.2 {
|
||||
{Customer: oid=?}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
reset_db
|
||||
register_tcl_module db eponymous_cmd
|
||||
|
||||
proc eponymous_cmd {method args} {
|
||||
switch -- $method {
|
||||
xConnect {
|
||||
db eval { SELECT * FROM sqlite_schema }
|
||||
return "CREATE TABLE t1 (a, b)"
|
||||
}
|
||||
|
||||
xBestIndex {
|
||||
return "idxnum 555"
|
||||
}
|
||||
|
||||
xFilter {
|
||||
return [list sql {SELECT 123, 'A', 'B'}]
|
||||
}
|
||||
|
||||
xUpdate {
|
||||
return 123
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
do_execsql_test 3.1.0 {
|
||||
PRAGMA table_info = tcl
|
||||
} {
|
||||
0 a {} 0 {} 0 1 b {} 0 {} 0
|
||||
}
|
||||
do_execsql_test 3.1.1 {
|
||||
SELECT rowid, * FROM tcl
|
||||
} {123 A B}
|
||||
do_execsql_test 3.1.2 {
|
||||
INSERT INTO tcl VALUES('i', 'ii') RETURNING *;
|
||||
} {i ii}
|
||||
do_test 3.1.3 {
|
||||
db last_insert_rowid
|
||||
} {123}
|
||||
|
||||
do_execsql_test 3.1.4 {
|
||||
CREATE TABLE x1(x);
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
register_tcl_module db eponymous_cmd
|
||||
sqlite3 db2 test.db
|
||||
|
||||
# Load the schema into connection [db]
|
||||
do_execsql_test 3.2.1 { SELECT * FROM x1 }
|
||||
|
||||
# Modify the schema on disk
|
||||
do_execsql_test -db db2 3.2.2 { CREATE TABLE x2(x) }
|
||||
|
||||
# Insert with RETURNING trigger on eponymous table.
|
||||
do_execsql_test 3.2.3 {
|
||||
INSERT INTO tcl VALUES('i', 'ii') RETURNING *;
|
||||
} {i ii}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+5
-5
@@ -129,7 +129,7 @@ if {$::TEMP_STORE<3} {
|
||||
CREATE TABLE data(a INTEGER, b BLOB);
|
||||
|
||||
-- Insert 5-6 MB of data.
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000 )
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<75000 )
|
||||
INSERT INTO data SELECT i, hex(randomblob(50)) FROM s;
|
||||
}
|
||||
|
||||
@@ -138,8 +138,8 @@ if {$::TEMP_STORE<3} {
|
||||
do_test 4.4 {
|
||||
execsql { SELECT a, b FROM data ORDER BY a }
|
||||
set nTmpSpill [lindex [db_temp_spill db 1] 1]
|
||||
expr ($nTmpSpill>5*1000*1000) && ($nTmpSpill<6*1000*1000)
|
||||
} 1
|
||||
expr {($nTmpSpill>7*1000*1000) && ($nTmpSpill<10*1000*1000)?"ok":$nTmpSpill}
|
||||
} ok
|
||||
|
||||
# The previous test case reset the status value.
|
||||
do_test 4.5 { db_temp_spill db 0 } {0 0 0}
|
||||
@@ -147,8 +147,8 @@ if {$::TEMP_STORE<3} {
|
||||
do_test 4.6 {
|
||||
execsql { CREATE INDEX i1 ON data(a) }
|
||||
set nTmpSpill [lindex [db_temp_spill db 1] 1]
|
||||
expr ($nTmpSpill>256*1000) && ($nTmpSpill<512*1000)
|
||||
} 1
|
||||
expr {($nTmpSpill>384*1000) && ($nTmpSpill<768*1000)?"ok":$nTmpSpill}
|
||||
} ok
|
||||
|
||||
# The previous test case reset the status value.
|
||||
do_test 4.7 { db_temp_spill db 0 } {0 0 0}
|
||||
|
||||
@@ -144,7 +144,6 @@ foreach op1 $oplist {
|
||||
foreach op {* AND OR + || & |} { unset untested($op,$op) }
|
||||
unset untested(+,-) ;# Since (a+b)-c == a+(b-c)
|
||||
unset untested(*,<<) ;# Since (a*b)<<c == a*(b<<c)
|
||||
foreach op {>> & * <<} {unset untested(AND,$op)}
|
||||
|
||||
do_test e_expr-1.1 { array names untested } {}
|
||||
|
||||
|
||||
@@ -429,4 +429,52 @@ do_execsql_test 8.0 {
|
||||
SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t0 LIMIT 0);
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE t1(xx);
|
||||
INSERT INTO t1 VALUES('big string value');
|
||||
} {}
|
||||
|
||||
do_execsql_test 9.1 {
|
||||
PRAGMA automatic_index = off;
|
||||
CREATE TABLE t2(ii);
|
||||
INSERT INTO t2 VALUES(100);
|
||||
INSERT INTO t2 VALUES(200);
|
||||
}
|
||||
|
||||
do_execsql_test 9.2 {
|
||||
CREATE TABLE t3(yy);
|
||||
INSERT INTO t3 VALUES(200);
|
||||
}
|
||||
|
||||
do_execsql_test 9.3 {
|
||||
SELECT 1 FROM t2 WHERE EXISTS ( SELECT 1 FROM t3 WHERE yy==t2.ii )
|
||||
} {1}
|
||||
|
||||
do_execsql_test 9.4 {
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM t2 WHERE EXISTS ( SELECT 1 FROM t3 WHERE yy==t2.ii )
|
||||
)
|
||||
} {1}
|
||||
|
||||
do_execsql_test 9.5 {
|
||||
SELECT 1234 WHERE EXISTS (
|
||||
SELECT 1 FROM t2 WHERE EXISTS ( SELECT 1 FROM t3 WHERE yy==t2.ii )
|
||||
)
|
||||
} {1234}
|
||||
|
||||
set Q {
|
||||
SELECT * FROM t1 WHERE
|
||||
EXISTS (
|
||||
SELECT 1 FROM t2 WHERE EXISTS ( SELECT 1 FROM t3 WHERE yy==t2.ii )
|
||||
)
|
||||
}
|
||||
|
||||
do_execsql_test 9.5 $Q {{big string value}}
|
||||
catch { optimization_control db exists-to-join 0 }
|
||||
db cache flush
|
||||
do_execsql_test 9.6 $Q {{big string value}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -71,6 +71,9 @@ test_expr expr-1.28 {i1=1, i2=2} {i1=2 AND i2=1} {0}
|
||||
test_expr expr-1.29 {i1=1, i2=2} {i1=1 AND i2=1} {0}
|
||||
test_expr expr-1.30 {i1=1, i2=2} {i1=2 AND i2=2} {0}
|
||||
test_expr expr-1.31 {i1=1, i2=2} {i1==1 OR i2=2} {1}
|
||||
test_expr expr-1.31b {i1=1} {0 OR 2} {1}
|
||||
test_expr expr-1.31c {i1=1} {false OR true} {1}
|
||||
test_expr expr-1.31d {i1=1} {99 OR false} {1}
|
||||
test_expr expr-1.32 {i1=1, i2=2} {i1=2 OR i2=1} {0}
|
||||
test_expr expr-1.33 {i1=1, i2=2} {i1=1 OR i2=1} {1}
|
||||
test_expr expr-1.34 {i1=1, i2=2} {i1=2 OR i2=2} {1}
|
||||
|
||||
@@ -411,4 +411,67 @@ do_execsql_test 15.2 {
|
||||
SELECT lower(x), quote(y) FROM x1 LEFT JOIN x2 USING (x) JOIN x3 USING (x) FULL JOIN t4;
|
||||
} {abc NULL}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 16.0 {
|
||||
CREATE TABLE t0_a (c0 INT);
|
||||
CREATE TABLE t0_b (c0 INT);
|
||||
|
||||
CREATE TABLE t2 (c0 INT);
|
||||
INSERT INTO t2 VALUES (1);
|
||||
}
|
||||
|
||||
do_execsql_test 16.1 {
|
||||
SELECT * FROM t2 LEFT JOIN t0_b
|
||||
} {1 {}}
|
||||
|
||||
do_execsql_test 16.2.1 {
|
||||
SELECT * FROM (t0_a RIGHT JOIN ( t2 LEFT JOIN t0_b))
|
||||
} {{} 1 {}}
|
||||
do_execsql_test 16.2.2 {
|
||||
SELECT * FROM (t0_a RIGHT JOIN (SELECT * FROM t2 LEFT JOIN t0_b))
|
||||
} {{} 1 {}}
|
||||
|
||||
|
||||
do_catchsql_test 16.3.1 {
|
||||
SELECT * FROM (t0_a RIGHT JOIN ( t2 LEFT JOIN t0_b) USING (c0));
|
||||
} {1 {ambiguous column name: c0}}
|
||||
|
||||
do_execsql_test 16.3.2 {
|
||||
SELECT * FROM (t0_a RIGHT JOIN (SELECT * FROM t2 LEFT JOIN t0_b) USING (c0));
|
||||
} {1 {}}
|
||||
|
||||
do_execsql_test 16.4.0 {
|
||||
CREATE TABLE x0(a TEXT);
|
||||
CREATE TABLE x1(a TEXT);
|
||||
CREATE TABLE x2(a TEXT);
|
||||
|
||||
INSERT INTO x1 VALUES('blue');
|
||||
INSERT INTO x2 VALUES('red');
|
||||
}
|
||||
|
||||
do_catchsql_test 16.4.1 {
|
||||
SELECT * FROM x0 RIGHT JOIN ( x1, x2) USING (a)
|
||||
} {1 {ambiguous column name: a}}
|
||||
|
||||
do_execsql_test 16.4.2 {
|
||||
SELECT * FROM x0 RIGHT JOIN (SELECT * FROM x1, x2) USING (a)
|
||||
} {blue red}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 16.5.0 {
|
||||
CREATE TABLE t0 (c0 INT);
|
||||
CREATE TABLE t1 (c0 INT);
|
||||
CREATE TABLE t2 (c0 INT);
|
||||
|
||||
INSERT INTO t1(c0) VALUES (NULL);
|
||||
INSERT INTO t2 VALUES (1);
|
||||
|
||||
CREATE VIEW v0(c0) AS SELECT 1 AS col_0 FROM t0;
|
||||
}
|
||||
|
||||
do_catchsql_test 16.5.2 {
|
||||
SELECT * FROM (t0 NATURAL RIGHT JOIN (t0 FULL JOIN (v0 NATURAL FULL JOIN t2) ON TRUE)) NATURAL FULL JOIN t1;
|
||||
} {1 {ambiguous column name: c0}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -211,4 +211,16 @@ if {[clang_sanitize_address]==0 && 0} {
|
||||
} {1 {(21) bad parameter or other API misuse}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test misuse-6.0 {
|
||||
sqlite3_set_errmsg db 1 "an error has occurred"
|
||||
} {SQLITE_OK}
|
||||
do_test misuse-6.1 {
|
||||
sqlite3_errmsg db
|
||||
} {an error has occurred}
|
||||
do_test misuse-6.2 {
|
||||
sqlite3_set_errmsg "" 1 "an error has occurred"
|
||||
} {SQLITE_MISUSE}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -544,4 +544,54 @@ do_catchsql_test 22.1 {
|
||||
} {1 {no such column: sqlite_master.name}}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 23.0 {
|
||||
PRAGMA recursive_triggers = 1;
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE TRIGGER t1insert AFTER INSERT ON t1 WHEN new.x<5 BEGIN
|
||||
INSERT INTO t1 VALUES(new.x+1, new.y);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 23.1 {
|
||||
INSERT INTO t1 VALUES(1, 'one') RETURNING *;
|
||||
} {1 one}
|
||||
|
||||
do_execsql_test 23.2 {
|
||||
SELECT * FROM t1
|
||||
} {1 one 2 one 3 one 4 one 5 one}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
ifcapable fts5 {
|
||||
|
||||
do_execsql_test 24.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(c);
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES('x');
|
||||
}
|
||||
|
||||
db close
|
||||
|
||||
sqlite3 db test.db
|
||||
sqlite3 db2 test.db
|
||||
|
||||
do_execsql_test 24.1 {
|
||||
SELECT * FROM t1
|
||||
} {x}
|
||||
|
||||
do_execsql_test -db db2 24.2 {
|
||||
CREATE TABLE t2(y);
|
||||
INSERT INTO t2 VALUES('y');
|
||||
} {}
|
||||
|
||||
db2 close
|
||||
|
||||
do_execsql_test 24.3 {
|
||||
INSERT INTO ft VALUES('hello world') RETURNING *
|
||||
} {{hello world}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -14,13 +14,15 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
set ::testprefix returningfault
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1 (b);
|
||||
} {}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test pagerfault-1 -faults oom-t* -prep {
|
||||
do_faultsim_test 1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
@@ -32,5 +34,52 @@ do_faultsim_test pagerfault-1 -faults oom-t* -prep {
|
||||
faultsim_test_result {1 {sub-select returns 5 columns - expected 1}}
|
||||
}
|
||||
|
||||
ifcapable vtab {
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(x);
|
||||
}
|
||||
|
||||
proc eponymous_cmd {method args} {
|
||||
switch -- $method {
|
||||
xConnect {
|
||||
db eval { SELECT * FROM sqlite_schema }
|
||||
return "CREATE TABLE t1 (a, b)"
|
||||
}
|
||||
|
||||
xBestIndex {
|
||||
return "idxnum 555"
|
||||
}
|
||||
|
||||
xFilter {
|
||||
return [list sql {SELECT 123, 'A', 'B'}]
|
||||
}
|
||||
|
||||
xUpdate {
|
||||
return 123
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 2 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
register_tcl_module db eponymous_cmd
|
||||
db eval { SELECT * FROM t1 }
|
||||
sqlite3 db2 test.db
|
||||
db2 eval { CREATE TABLE t2(y) }
|
||||
db2 close
|
||||
} -body {
|
||||
db eval {
|
||||
INSERT INTO tcl VALUES('hello', 'world') RETURNING *
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {hello world}} {1 {vtable constructor failed: tcl}}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -945,6 +945,71 @@ do_test shell1-4.1.6 {
|
||||
|
||||
}
|
||||
|
||||
# DELETE content of sqlite_sequence prior to repopulating,
|
||||
# but only if the sqlite_sequence table is non-empty.
|
||||
# Forum: 2024-10-13T17:10:01z and 2025-10-29T19:38:43z
|
||||
#
|
||||
do_test shell1-4.1.7 {
|
||||
db close
|
||||
forcedelete test2.db
|
||||
sqlite3 db test2.db
|
||||
db eval {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
|
||||
INSERT INTO t1 VALUES(1,2),(20,21),(15,16);
|
||||
}
|
||||
catchcmd test2.db {.dump}
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
INSERT INTO t1 VALUES(15,16);
|
||||
INSERT INTO t1 VALUES(20,21);
|
||||
PRAGMA writable_schema=ON;
|
||||
CREATE TABLE IF NOT EXISTS sqlite_sequence(name,seq);
|
||||
DELETE FROM sqlite_sequence;
|
||||
INSERT INTO sqlite_sequence VALUES('t1',20);
|
||||
PRAGMA writable_schema=OFF;
|
||||
COMMIT;}}
|
||||
do_test shell1-4.1.8 {
|
||||
db close
|
||||
forcedelete test2.db
|
||||
sqlite3 db test2.db
|
||||
db eval {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
|
||||
INSERT INTO t1 VALUES(1,2),(20,21),(15,16);
|
||||
CREATE TABLE t2(x,y);
|
||||
INSERT INTO t2 VALUES(99,88);
|
||||
DROP TABLE t1;
|
||||
}
|
||||
catchcmd test2.db {.dump}
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t2(x,y);
|
||||
INSERT INTO t2 VALUES(99,88);
|
||||
COMMIT;}}
|
||||
do_test shell1-4.1.9 {
|
||||
db close
|
||||
forcedelete test2.db
|
||||
sqlite3 db test2.db
|
||||
db eval {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
|
||||
INSERT INTO t1 VALUES(1,2),(20,21),(15,16);
|
||||
CREATE TABLE t2(x,y);
|
||||
INSERT INTO t2 VALUES(99,88);
|
||||
INSERT INTO sqlite_sequence VALUES('extra',999);
|
||||
DROP TABLE t1;
|
||||
}
|
||||
catchcmd test2.db {.dump}
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t2(x,y);
|
||||
INSERT INTO t2 VALUES(99,88);
|
||||
PRAGMA writable_schema=ON;
|
||||
CREATE TABLE IF NOT EXISTS sqlite_sequence(name,seq);
|
||||
DELETE FROM sqlite_sequence;
|
||||
INSERT INTO sqlite_sequence VALUES('extra',999);
|
||||
PRAGMA writable_schema=OFF;
|
||||
COMMIT;}}
|
||||
|
||||
# Test the output of ".mode insert"
|
||||
#
|
||||
|
||||
+1
-1
@@ -152,6 +152,6 @@ do_test shell4-4.1 {
|
||||
puts $fd ".read t1.txt"
|
||||
close $fd
|
||||
catchcmd ":memory:" ".read t1.txt"
|
||||
} {1 {Input nesting limit (25) reached at line 1. Check recursion.}}
|
||||
} {1 {t1.txt: Input nesting limit (25) reached at line 1. Check recursion.}}
|
||||
|
||||
finish_test
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user