Compare commits
233 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fe917cfa5 | |||
| 7a543f6fbf | |||
| bb9ab35ab1 | |||
| 598328209f | |||
| 6b36d0b461 | |||
| bf64cbd463 | |||
| cd6ea30b82 | |||
| 1ba138401e | |||
| f537bba1a1 | |||
| 1cfc040bba | |||
| 76da0dcbc4 | |||
| de70e8b9c4 | |||
| 267721e72a | |||
| aa08f885ba | |||
| 4093b29610 | |||
| 433e904d99 | |||
| 6db9206c18 | |||
| 4167033eaf | |||
| d059153deb | |||
| f5740f72ec | |||
| 4eb626350a | |||
| 533622fb8b | |||
| aff7664939 | |||
| 3d4d3fb59d | |||
| fe1d8210c7 | |||
| 92e970ae98 | |||
| 4cfc19f34c | |||
| 4ccf707c6e | |||
| 307f326ba3 | |||
| 805cd395a9 | |||
| 7a482b3bcd | |||
| e24cd27c39 | |||
| 2aae3a95a9 | |||
| 751c4e2152 | |||
| 4c13d3ca92 | |||
| 42203e1b75 | |||
| 0546a284fa | |||
| d9ac37fc44 | |||
| d82320ac9a | |||
| b2b7490862 | |||
| 71a32aede3 | |||
| 5a85cf5879 | |||
| c1805ab222 | |||
| 57c98747cb | |||
| 4ed0b117f3 | |||
| 8a630c2aa3 | |||
| ba5043f818 | |||
| 09e6c82d56 | |||
| 0810150532 | |||
| 15bff25111 | |||
| c2eff91bd3 | |||
| 0d7f0e49a4 | |||
| 95cf95841c | |||
| 3262ca83a7 | |||
| c52aebb443 | |||
| 7c1033b010 | |||
| 4449a1b66d | |||
| 611b9d3efd | |||
| 09259aff6c | |||
| 3e2ec83e0b | |||
| 9c36095367 | |||
| 60c435dc4b | |||
| 3a0e82611a | |||
| a3569fb2ca | |||
| 459f7b1090 | |||
| d9252d09c2 | |||
| c4dd6b42ec | |||
| fc76750f61 | |||
| 095f2c5082 | |||
| cf6fe5abe3 | |||
| 0a46ff995b | |||
| 52a4691fff | |||
| 2ae95649de | |||
| 0d201598a5 | |||
| 13264418ba | |||
| 5f3dd8668c | |||
| 40e614e393 | |||
| 97f7ead3f3 | |||
| b7fad0dca3 | |||
| baa1aba8d7 | |||
| f2194605f8 | |||
| 76dbb58700 | |||
| f062506002 | |||
| e982385619 | |||
| eb78d56ec5 | |||
| 4a5c96ace3 | |||
| e6289d6dd0 | |||
| 8a861a81e8 | |||
| 07117f8118 | |||
| 9e488a5a40 | |||
| 3e4195c60d | |||
| f7c78a2408 | |||
| 001d1e795c | |||
| 891f1dc054 | |||
| 9710fa119e | |||
| df25a8fd4b | |||
| 78e636bba6 | |||
| 87399a56db | |||
| cc1a39fd24 | |||
| ad6bc61804 | |||
| 5a890b4ed2 | |||
| 001caa714f | |||
| 7445659559 | |||
| ba5505657f | |||
| 7d2eaae83e | |||
| ce46e0eb11 | |||
| b89e64d822 | |||
| bfa0de86e6 | |||
| 2a27be2107 | |||
| 9d2446dc13 | |||
| 05980f5931 | |||
| 0b427eb796 | |||
| 7c12666fe9 | |||
| 1ddcf7dd95 | |||
| 5f2f8d0028 | |||
| 2f3ccb8886 | |||
| 5a238ffcae | |||
| f86a07b0c4 | |||
| 5b6b703461 | |||
| 00f3ac5544 | |||
| 82fc1b63f6 | |||
| 83ac79282a | |||
| a9c8469d03 | |||
| b597fea894 | |||
| 9df01b5ccf | |||
| 3207199c98 | |||
| 8dfbf4addc | |||
| 6a8581d828 | |||
| 91ec00c25a | |||
| e751596ee8 | |||
| 39b08db132 | |||
| 1f2d7c4312 | |||
| 88208296c2 | |||
| 5afd67b3c3 | |||
| fb923fc4cc | |||
| a0de45459e | |||
| 8eac91fab7 | |||
| 590aaff992 | |||
| 78f7d2f4c1 | |||
| fa43e21711 | |||
| ae2e972802 | |||
| 3cdb079476 | |||
| 49bfbc1ef3 | |||
| f26e26afc5 | |||
| 0b8b1c309d | |||
| 3fedb7e59e | |||
| 54318b382a | |||
| 910c77b049 | |||
| 3dfc063705 | |||
| 9c794b9bff | |||
| 9d373ca1c5 | |||
| 99c41692f1 | |||
| 732fb64ad3 | |||
| 43b4864a98 | |||
| dc138cb186 | |||
| 2ff73a5f3e | |||
| b7fd951be4 | |||
| 9af45dc482 | |||
| 16e8a5b2f3 | |||
| a3bf077b60 | |||
| 0a18a5807a | |||
| 78fa0186b8 | |||
| eb18ae3089 | |||
| c78c3c91ae | |||
| 8f8d481485 | |||
| c22d2b7b7f | |||
| c1e85742da | |||
| 53c2160db0 | |||
| 94c521295a | |||
| a11aaff05a | |||
| c44041e03b | |||
| 05db513435 | |||
| 2c26bde4ff | |||
| 4cd397c0d9 | |||
| 82136d90f8 | |||
| f0b8b16317 | |||
| 679c90850c | |||
| 768b6e32f6 | |||
| 6df61985d4 | |||
| 5ec9c916ad | |||
| 3af20cf3a0 | |||
| f4c2962558 | |||
| ebd173a79f | |||
| b5effc0605 | |||
| 03075fa868 | |||
| 063d0d4c3a | |||
| 5bfa7e65d1 | |||
| ca1ce7773c | |||
| 4b9ed1b256 | |||
| 38aeb97f27 | |||
| 68003d9f18 | |||
| 276042bd23 | |||
| 0ab1e25468 | |||
| 66795962b5 | |||
| 7394a6ef57 | |||
| 48222bef66 | |||
| ad27c437ff | |||
| bac2fe9f44 | |||
| bfc7e62be4 | |||
| 694beecf2b | |||
| da2578391d | |||
| 89fcfbb424 | |||
| ed088f5f8d | |||
| 6d7afd8ba8 | |||
| 2ba5534101 | |||
| 4b54d6cdaf | |||
| 748178a9fb | |||
| 1f8c7c7053 | |||
| 1ef232c0e1 | |||
| 1cab41e290 | |||
| 0d4a888485 | |||
| ef97f8360a | |||
| 940b23bc3a | |||
| b8950e0f45 | |||
| 26cd4b57df | |||
| bae2d0f2eb | |||
| e52854a9e6 | |||
| 48cca2422e | |||
| 88a61ff8ba | |||
| f5232b3a97 | |||
| 41c9e0b767 | |||
| af54826e4a | |||
| 5c268bbf67 | |||
| a0764f63a8 | |||
| 50b0e25a55 | |||
| e108029332 | |||
| 43d05ccc31 | |||
| b4fc827c0f | |||
| 4cad31912e | |||
| 03204e9106 | |||
| 1846de49a4 | |||
| eb28787b5f | |||
| a35ae44150 |
+8
-1
@@ -447,6 +447,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/prefixes.c \
|
||||
$(TOP)/ext/misc/qpvtab.c \
|
||||
$(TOP)/ext/misc/randomjson.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
$(TOP)/ext/misc/series.c \
|
||||
@@ -600,6 +601,7 @@ 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_STRICT_SUBTYPE=1
|
||||
FUZZERSHELL_OPT =
|
||||
FUZZCHECK_OPT += -I$(TOP)/test
|
||||
FUZZCHECK_OPT += -I$(TOP)/ext/recover
|
||||
@@ -630,7 +632,9 @@ FUZZCHECK_OPT += \
|
||||
-DSQLITE_MAX_MMAP_SIZE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_PRINTF_PRECISION_LIMIT=1000 \
|
||||
-DSQLITE_PRIVATE=""
|
||||
-DSQLITE_PRIVATE="" \
|
||||
-DSQLITE_STRICT_SUBTYPE=1 \
|
||||
-DSQLITE_STATIC_RANDOMJSON
|
||||
|
||||
FUZZCHECK_SRC += $(TOP)/test/fuzzcheck.c
|
||||
FUZZCHECK_SRC += $(TOP)/test/ossfuzz.c
|
||||
@@ -638,6 +642,7 @@ FUZZCHECK_SRC += $(TOP)/test/fuzzinvariants.c
|
||||
FUZZCHECK_SRC += $(TOP)/ext/recover/dbdata.c
|
||||
FUZZCHECK_SRC += $(TOP)/ext/recover/sqlite3recover.c
|
||||
FUZZCHECK_SRC += $(TOP)/test/vt02.c
|
||||
FUZZCHECK_SRC += $(TOP)/ext/misc/randomjson.c
|
||||
DBFUZZ_OPT =
|
||||
ST_OPT = -DSQLITE_OS_KV_OPTIONAL
|
||||
|
||||
@@ -1291,6 +1296,8 @@ TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_STATIC_RANDOMJSON
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_STRICT_SUBTYPE=1
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
|
||||
+10
-3
@@ -1584,6 +1584,7 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\prefixes.c \
|
||||
$(TOP)\ext\misc\qpvtab.c \
|
||||
$(TOP)\ext\misc\randomjson.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
$(TOP)\ext\misc\remember.c \
|
||||
$(TOP)\ext\misc\series.c \
|
||||
@@ -1692,6 +1693,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=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_STRICT_SUBTYPE=1
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
@@ -1728,6 +1730,8 @@ FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MMAP_SIZE=0
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRIVATE=""
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_STRICT_SUBTYPE=1
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_STATIC_RANDOMJSON
|
||||
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
@@ -1744,6 +1748,7 @@ FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\fuzzinvariants.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\vt02.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\dbdata.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\sqlite3recover.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\randomjson.c
|
||||
|
||||
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
||||
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
@@ -1823,8 +1828,8 @@ $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLIT
|
||||
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
|
||||
|
||||
# <<mark>>
|
||||
sqldiff.exe: $(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
|
||||
sqldiff.exe: $(TOP)\tool\sqldiff.c $(TOP)\ext\consio\console_io.h $(TOP)\ext\consio\console_io.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -I$(TOP)\ext\consio $(TOP)\tool\sqldiff.c $(TOP)\ext\consio\console_io.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
|
||||
|
||||
dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
@@ -2433,6 +2438,8 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CKSUMVFS_STATIC=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STATIC_RANDOMJSON
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STRICT_SUBTYPE=1
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
|
||||
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
|
||||
@@ -2543,7 +2550,7 @@ smoketest: $(TESTPROGS)
|
||||
shelltest: $(TESTPROGS)
|
||||
.\testfixture.exe $(TOP)\test\permutations.test shell
|
||||
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\consio\console_io.h $(TOP)\ext\consio\console_io.c $(SQLITE_TCL_DEP)
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@
|
||||
|
||||
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
|
||||
@@ -159,7 +159,7 @@ extension and only later escaped to the wild as an independent library.)
|
||||
|
||||
Test scripts and programs are found in the **test/** subdirectory.
|
||||
Additional test code is found in other source repositories.
|
||||
See [How SQLite Is Tested](http://www.sqlite.org/testing.html) for
|
||||
See [How SQLite Is Tested](https://www.sqlite.org/testing.html) for
|
||||
additional information.
|
||||
|
||||
The **ext/** subdirectory contains code for extensions. The
|
||||
@@ -183,7 +183,7 @@ manually-edited files and automatically-generated files.
|
||||
|
||||
The SQLite interface is defined by the **sqlite3.h** header file, which is
|
||||
generated from src/sqlite.h.in, ./manifest.uuid, and ./VERSION. The
|
||||
[Tcl script](http://www.tcl.tk) at tool/mksqlite3h.tcl does the conversion.
|
||||
[Tcl script](https://www.tcl.tk) at tool/mksqlite3h.tcl does the conversion.
|
||||
The manifest.uuid file contains the SHA3 hash of the particular check-in
|
||||
and is used to generate the SQLITE\_SOURCE\_ID macro. The VERSION file
|
||||
contains the current SQLite version number. The sqlite3.h header is really
|
||||
@@ -250,14 +250,14 @@ individual source file exceeds 32K lines in length.
|
||||
## How It All Fits Together
|
||||
|
||||
SQLite is modular in design.
|
||||
See the [architectural description](http://www.sqlite.org/arch.html)
|
||||
See the [architectural description](https://www.sqlite.org/arch.html)
|
||||
for details. Other documents that are useful in
|
||||
(helping to understand how SQLite works include the
|
||||
[file format](http://www.sqlite.org/fileformat2.html) description,
|
||||
the [virtual machine](http://www.sqlite.org/opcode.html) that runs
|
||||
[file format](https://www.sqlite.org/fileformat2.html) description,
|
||||
the [virtual machine](https://www.sqlite.org/opcode.html) that runs
|
||||
prepared statements, the description of
|
||||
[how transactions work](http://www.sqlite.org/atomiccommit.html), and
|
||||
the [overview of the query planner](http://www.sqlite.org/optoverview.html).
|
||||
[how transactions work](https://www.sqlite.org/atomiccommit.html), and
|
||||
the [overview of the query planner](https://www.sqlite.org/optoverview.html).
|
||||
|
||||
Years of effort have gone into optimizing SQLite, both
|
||||
for small size and high performance. And optimizations tend to result in
|
||||
@@ -353,7 +353,7 @@ hidden by also modifying the makefiles.
|
||||
|
||||
## Contacts
|
||||
|
||||
The main SQLite website is [http:/sqlite.org/](http://sqlite.org/)
|
||||
The main SQLite website is [https://sqlite.org/](https://sqlite.org/)
|
||||
with geographically distributed backups at
|
||||
[http://www2.sqlite.org/](http://www2.sqlite.org) and
|
||||
[http://www3.sqlite.org/](http://www3.sqlite.org).
|
||||
[https://www2.sqlite.org/](https://www2.sqlite.org) and
|
||||
[https://www3.sqlite.org/](https://www3.sqlite.org).
|
||||
|
||||
@@ -990,6 +990,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=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_STRICT_SUBTYPE=1
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
# The JSONB Format
|
||||
|
||||
This document describes SQLite's JSONB binary encoding of
|
||||
JSON.
|
||||
|
||||
## 1.0 What Is JSONB?
|
||||
|
||||
Beginning with version 3.45.0 (circa 2024-01-01), SQLite supports an
|
||||
alternative binary encoding of JSON which we call "JSONB". JSONB is
|
||||
a binary format that stored as a BLOB.
|
||||
|
||||
The advantage of JSONB over ordinary text RFC 8259 JSON is that JSONB
|
||||
is both slightly smaller (by between 5% and 10% in most cases) and
|
||||
can be processed in less than half the number of CPU cycles. The built-in
|
||||
[JSON SQL functions] of SQLite can accept either ordinary text JSON
|
||||
or the binary JSONB encoding for any of their JSON inputs.
|
||||
|
||||
The "JSONB" name is inspired by [PostgreSQL](https://postgresql.org), but the
|
||||
on-disk format for SQLite's JSONB is not the same as PostgreSQL's.
|
||||
The two formats have the same name, but they have wildly different internal
|
||||
representations and are not in any way binary compatible.
|
||||
|
||||
The central idea behind this JSONB specification is that each element
|
||||
begins with a header that includes the size and type of that element.
|
||||
The header takes the place of punctuation such as double-quotes,
|
||||
curly-brackes, square-brackets, commas, and colons. Since the size
|
||||
and type of each element is contained in its header, the element can
|
||||
be read faster since it is no longer necessary to carefully scan forward
|
||||
looking for the closing delimiter. The payload of JSONB is the same
|
||||
as for corresponding text JSON. The same payload bytes occur in the
|
||||
same order. The only real difference between JSONB and ordinary text
|
||||
JSON is that JSONB includes a binary header on
|
||||
each element and omits delimiter and separator punctuation.
|
||||
|
||||
### 1.1 Internal Use Only
|
||||
|
||||
The details of the JSONB are not intended to be visible to application
|
||||
developers. Application developers should look at JSONB as an opaque BLOB
|
||||
used internally by SQLite. Nevertheless, we want the format to be backwards
|
||||
compatible across all future versions of SQLite. To that end, the format
|
||||
is documented by this file in the source tree. But this file should be
|
||||
used only by SQLite core developers, not by developers of applications
|
||||
that only use SQLite.
|
||||
|
||||
## 2.0 The Purpose Of This Document
|
||||
|
||||
JSONB is not intended as an external format to be used by
|
||||
applications. JSONB is designed for internal use by SQLite only.
|
||||
Programmers do not need to understand the JSONB format in order to
|
||||
use it effectively.
|
||||
Applications should access JSONB only through the [JSON SQL functions],
|
||||
not by looking at individual bytes of the BLOB.
|
||||
|
||||
However, JSONB is intended to be portable and backwards compatible
|
||||
for all future versions of SQLite. In other words, you should not have
|
||||
to export and reimport your SQLite database files when you upgrade to
|
||||
a newer SQLite version. For that reason, the JSONB format needs to
|
||||
be well-defined.
|
||||
|
||||
This document is therefore similar in purpose to the
|
||||
[SQLite database file format] document that describes the on-disk
|
||||
format of an SQLite database file. Applications are not expected
|
||||
to directly read and write the bits and bytes of SQLite database files.
|
||||
The SQLite database file format is carefully documented so that it
|
||||
can be stable and enduring. In the same way, the JSONB representation
|
||||
of JSON is documented here so that it too can be stable and enduring,
|
||||
not so that applications can read or writes individual bytes.
|
||||
|
||||
## 3.0 Encoding
|
||||
|
||||
JSONB is a direct translation of the underlying text JSON. The difference
|
||||
is that JSONB uses a binary encoding that is faster to parse compared to
|
||||
the detailed syntax of text JSON.
|
||||
|
||||
Each JSON element is encoded as a header and a payload. The header
|
||||
determines type of element (string, numeric, boolean, null, object, or
|
||||
array) and the size of the payload. The header can be between 1 and
|
||||
9 bytes in size. The payload can be any size from zero bytes up to the
|
||||
maximum allowed BLOB size.
|
||||
|
||||
### 3.1 Payload Size
|
||||
|
||||
The upper four bits of the first byte of the header determine size of the
|
||||
header and possibly also the size of the payload.
|
||||
If the upper four bits have a value between 0 and 11, then the header is
|
||||
exactly one byte in size and the payload size is determined by those
|
||||
upper four bits. If the upper four bits have a value between 12 and 15,
|
||||
that means that the total header size is 2, 3, 5, or 9 bytes and the
|
||||
payload size is unsigned big-endian integer that is contained in the
|
||||
subsequent bytes. The size integer is the one byte that following the
|
||||
initial header byte if the upper four bits
|
||||
are 12, two bytes if the upper bits are 13, four bytes if the upper bits
|
||||
are 14, and eight bytes if the upper bits are 15. The current design
|
||||
of SQLite does not support BLOB values larger than 2GiB, so the eight-byte
|
||||
variant of the payload size integer will never be used by the current code.
|
||||
The eight-byte payload size integer is included in the specification
|
||||
to allow for future expansion.
|
||||
|
||||
The header for an element does *not* need to be in its simplest
|
||||
form. For example, consider the JSON numeric value "`1`".
|
||||
That element can be encode in five different ways:
|
||||
|
||||
* `0x13 0x31`
|
||||
* `0xc3 0x01 0x31`
|
||||
* `0xd3 0x00 0x01 0x31`
|
||||
* `0xe3 0x00 0x00 0x00 0x01 0x31`
|
||||
* `0xf3 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x31`
|
||||
|
||||
The shortest encoding is preferred, of course, and usually happens with
|
||||
primitive elements such as numbers. However the total size of an array
|
||||
or object might not be known exactly when the header of the element is
|
||||
first generated. It is convenient to reserve space for the largest
|
||||
possible header and then go back and fill in the correct payload size
|
||||
at the end. This technique can result in array or object headers that
|
||||
are larger than absolutely necessary.
|
||||
|
||||
### 3.2 Element Type
|
||||
|
||||
The least-significant four bits of the first byte of the header (the first
|
||||
byte masked against 0x0f) determine element type. The following codes are
|
||||
used:
|
||||
|
||||
<ol>
|
||||
<li type="0"><p><b>NULL</b> →
|
||||
The element is a JSON "null". The payload size for a true JSON NULL must
|
||||
must be zero. Future versions of SQLite might extend the JSONB format
|
||||
with elements that have a zero element type but a non-zero size. In that
|
||||
way, legacy versions of SQLite will interpret the element as a NULL
|
||||
for backwards compatibility while newer versions will interpret the
|
||||
element in some other way.
|
||||
|
||||
<li value="1"><p><b>TRUE</b> →
|
||||
The element is a JSON "true". The payload size must be zero for a actual
|
||||
"true" value. Elements with type 1 and a non-zero payload size are
|
||||
reserved for future expansion. Legacy implementations that see an element
|
||||
type of 1 with a non-zero payload size should continue to interpret that
|
||||
element as "true" for compatibility.
|
||||
|
||||
<li value="2"><p><b>FALSE</b> →
|
||||
The element is a JSON "false". The payload size must be zero for a actual
|
||||
"false" value. Elements with type 2 and a non-zero payload size are
|
||||
reserved for future expansion. Legacy implementations that see an element
|
||||
type of 2 with a non-zero payload size should continue to interpret that
|
||||
element as "false" for compatibility.
|
||||
|
||||
<li value="3"><p><b>INT</b> →
|
||||
The element is a JSON integer value in the canonical
|
||||
RFC 8259 format, without extensions. The payload is the ASCII
|
||||
text representation of that numeric value.
|
||||
|
||||
<li value="4"><p><b>INT5</b> →
|
||||
The element is a JSON integer value that is not in the
|
||||
canonical format. The payload is the ASCII
|
||||
text representation of that numeric value. Because the payload is in a
|
||||
non-standard format, it will need to be translated when the JSONB is
|
||||
converted into RFC 8259 text JSON.
|
||||
|
||||
<li value="5"><p><b>FLOAT</b> →
|
||||
The element is a JSON floating-point value in the canonical
|
||||
RFC 8259 format, without extensions. The payload is the ASCII
|
||||
text representation of that numeric value.
|
||||
|
||||
<li value="6"><p><b>FLOAT5</b> →
|
||||
The element is a JSON floating-point value that is not in the
|
||||
canonical format. The payload is the ASCII
|
||||
text representation of that numeric value. Because the payload is in a
|
||||
non-standard format, it will need to be translated when the JSONB is
|
||||
converted into RFC 8259 text JSON.
|
||||
|
||||
<li value="7"><p><b>TEXT</b> →
|
||||
The element is a JSON string value that does not contain
|
||||
any escapes nor any characters that need to be escaped for either SQL or
|
||||
JSON. The payload is the UTF8 text representation of the string value.
|
||||
The payload does <i>not</i> include string delimiters.
|
||||
|
||||
<li value="8"><p><b>TEXTJ</b> →
|
||||
The element is a JSON string value that contains
|
||||
RFC 8259 character escapes (such as "<tt>\n</tt>" or "<tt>\u0020</tt>").
|
||||
Those escapes will need to be translated into actual UTF8 if this element
|
||||
is [json_extract|extracted] into SQL.
|
||||
The payload is the UTF8 text representation of the escaped string value.
|
||||
The payload does <i>not</i> include string delimiters.
|
||||
|
||||
<li value="9"><p><b>TEXT5</b> →
|
||||
The element is a JSON string value that contains
|
||||
character escapes, including some character escapes that part of JSON5
|
||||
and which are not found in the canonical RFC 8259 spec.
|
||||
Those escapes will need to be translated into standard JSON prior to
|
||||
rendering the JSON as text, or into their actual UTF8 characters if this
|
||||
element is [json_extract|extracted] into SQL.
|
||||
The payload is the UTF8 text representation of the escaped string value.
|
||||
The payload does <i>not</i> include string delimiters.
|
||||
|
||||
<li value="10"><p><b>TEXTRAW</b> →
|
||||
The element is a JSON string value that contains
|
||||
UTF8 characters that need to be escaped if this string is rendered into
|
||||
standard JSON text.
|
||||
The payload does <i>not</i> include string delimiters.
|
||||
|
||||
<li value="11"><p><b>ARRAY</b> →
|
||||
The element is a JSON array. The payload contains
|
||||
JSONB elements that comprise values contained within the array.
|
||||
|
||||
<li value="12"><p><b>OBJECT</b> →
|
||||
The element is a JSON object. The payload contains
|
||||
pairs of JSONB elements that comprise entries for the JSON object.
|
||||
The first element in each pair must be a string (types 7 through 10).
|
||||
The second element of each pair may be any types, including nested
|
||||
arrays or objects.
|
||||
|
||||
<li value="13"><p><b>RESERVED-13</b> →
|
||||
Reserved for future expansion. Legacy implements that encounter this
|
||||
element type should raise an error.
|
||||
|
||||
<li value="14"><p><b>RESERVED-14</b> →
|
||||
Reserved for future expansion. Legacy implements that encounter this
|
||||
element type should raise an error.
|
||||
|
||||
<li value="15"><p><b>RESERVED-15</b> →
|
||||
Reserved for future expansion. Legacy implements that encounter this
|
||||
element type should raise an error.
|
||||
</ol>
|
||||
|
||||
Element types outside the range of 0 to 12 are reserved for future
|
||||
expansion. The current implement raises an error if see an element type
|
||||
other than those listed above. However, future versions of SQLite might
|
||||
use of the three remaining element types to implement indexing or similar
|
||||
optimizations, to speed up lookup against large JSON arrays and/or objects.
|
||||
|
||||
### 3.3 Design Rationale For Element Types
|
||||
|
||||
A key goal of JSONB is that it should be quick to translate
|
||||
to and from text JSON and/or be constructed from SQL values.
|
||||
When converting from text into JSONB, we do not want the
|
||||
converter subroutine to burn CPU cycles converting elements
|
||||
values into some standard format which might never be used.
|
||||
Format conversion is "lazy" - it is deferred until actually
|
||||
needed. This has implications for the JSONB format design:
|
||||
|
||||
1. Numeric values are stored as text, not a numbers. The values are
|
||||
a direct copy of the text JSON values from which they are derived.
|
||||
|
||||
2. There are multiple element types depending on the details of value
|
||||
formats. For example, INT is used for pure RFC-8259 integer
|
||||
literals and INT5 exists for JSON5 extensions such as hexadecimal
|
||||
notation. FLOAT is used for pure RFC-8259 floating point literals
|
||||
and FLOAT5 is used for JSON5 extensions. There are four different
|
||||
representations of strings, depending on where the string came from
|
||||
and how special characters within the string are escaped.
|
||||
|
||||
A second goal of JSONB is that it should be capable of serving as the
|
||||
"parse tree" for JSON when a JSON value is being processed by the
|
||||
various [JSON SQL functions] built into SQLite. Before JSONB was
|
||||
developed, operations such [json_replace()] and [json_patch()]
|
||||
and similar worked in three stages:
|
||||
|
||||
|
||||
1. Translate the text JSON into a internal format that is
|
||||
easier to scan and edit.
|
||||
2. Perform the requested operation on the JSON.
|
||||
3. Translate the internal format back into text.
|
||||
|
||||
JSONB seeks to serve as the internal format directly - bypassing
|
||||
the first and third stages of that process. Since most of the CPU
|
||||
cycles are spent on the first and third stages, that suggests that
|
||||
JSONB processing will be much faster than text JSON processing.
|
||||
|
||||
So when processing JSONB, only the second stage of the three-stage
|
||||
process is required. But when processing text JSON, it is still necessary
|
||||
to do stages one and three. If JSONB is to be used as the internal
|
||||
binary representation, this is yet another reason to store numeric
|
||||
values as text. Storing numbers as text minimizes the amount of
|
||||
conversion work needed for stages one and three. This is also why
|
||||
there are four different representations of text in JSONB. Different
|
||||
text representations are used for text coming from different sources
|
||||
(RFC-8259 JSON, JSON5, or SQL string values) and conversions only
|
||||
happen if and when they are actually needed.
|
||||
|
||||
### 3.4 Valid JSONB BLOBs
|
||||
|
||||
A valid JSONB BLOB consists of a single JSON element. The element must
|
||||
exactly fill the BLOB. This one element is often a JSON object or array
|
||||
and those usually contain additional elements as its payload, but the
|
||||
element can be a primite value such a string, number, boolean, or null.
|
||||
|
||||
When the built-in JSON functions are attempting to determine if a BLOB
|
||||
argument is a JSONB or just a random BLOB, they look at the header of
|
||||
the outer element to see that it is well-formed and that the element
|
||||
completely fills the BLOB. If these conditions are met, then the BLOB
|
||||
is accepted as a JSONB value.
|
||||
+69
-9
@@ -2,6 +2,26 @@
|
||||
|
||||
# The testrunner.tcl Script
|
||||
|
||||
<ul type=none>
|
||||
<li> 1. <a href=#overview>Overview</a>
|
||||
<li> 2. <a href=#binary_tests>Binary Tests</a>
|
||||
<ul type=none>
|
||||
<li> 2.1. <a href=#organization_tests>Organization of Tcl Tests</a>
|
||||
<li> 2.2. <a href=#run_tests>Commands to Run Tests</a>
|
||||
<li> 2.3. <a href=#binary_test_failures>Investigating Binary Test Failures</a>
|
||||
</ul>
|
||||
<li> 3. <a href=#source_code_tests>Source Tests</a>
|
||||
<ul type=none>
|
||||
<li> 3.1. <a href=#commands_to_run_tests>Commands to Run SQLite Tests</a>
|
||||
<li> 3.2. <a href=#zipvfs_tests>Running ZipVFS Tests</a>
|
||||
<li> 3.3. <a href=#source_code_test_failures>Investigating Source Code Test Failures</a>
|
||||
</ul>
|
||||
<li> 4. <a href=#testrunner_options>Extra testrunner.tcl Options</a>
|
||||
# 4. Extra testrunner.tcl Options
|
||||
<li> 5. <a href=#cpu_cores>Controlling CPU Core Utilization</a>
|
||||
</ul>
|
||||
|
||||
<a name=overview></a>
|
||||
# 1. Overview
|
||||
|
||||
testrunner.tcl is a Tcl script used to run multiple SQLite tests using
|
||||
@@ -44,6 +64,7 @@ Sometimes testrunner.tcl uses the [testfixture] binary that it is run with
|
||||
to run tests (see "Binary Tests" below). Sometimes it builds testfixture and
|
||||
other binaries in specific configurations to test (see "Source Tests").
|
||||
|
||||
<a name=binary_tests></a>
|
||||
# 2. Binary Tests
|
||||
|
||||
The commands described in this section all run various combinations of the Tcl
|
||||
@@ -61,6 +82,7 @@ these tests is therefore:
|
||||
The following sub-sections describe the various options that can be
|
||||
passed to testrunner.tcl to test binary testfixture builds.
|
||||
|
||||
<a name=organization_tests></a>
|
||||
## 2.1. Organization of Tcl Tests
|
||||
|
||||
Tcl tests are stored in files that match the pattern *\*.test*. They are
|
||||
@@ -91,6 +113,7 @@ Running **all** tests is to run all tests in the full test set, plus a dozen
|
||||
or so permutations. The specific permutations that are run as part of "all"
|
||||
are defined in file *testrunner_data.tcl*.
|
||||
|
||||
<a name=run_tests></a>
|
||||
## 2.2. Commands to Run Tests
|
||||
|
||||
To run the "veryquick" test set, use either of the following:
|
||||
@@ -114,6 +137,12 @@ a specified pattern (e.g. all tests that start with "fts5"), either of:
|
||||
./testfixture $TESTDIR/testrunner.tcl 'fts5*'
|
||||
```
|
||||
|
||||
Strictly speaking, for a test to be run the pattern must match the script
|
||||
filename, not including the directory, using the rules of Tcl's
|
||||
\[string match\] command. Except that before the matching is done, any "%"
|
||||
characters specified as part of the pattern are transformed to "\*".
|
||||
|
||||
|
||||
To run "all" tests (full + permutations):
|
||||
|
||||
```
|
||||
@@ -141,6 +170,7 @@ Or, if the failure occured as part of a permutation:
|
||||
|
||||
TODO: An example instead of "$PERMUTATION" and $PATH\_TO\_SCRIPT?
|
||||
|
||||
<a name=source_code_tests></a>
|
||||
# 3. Source Code Tests
|
||||
|
||||
The commands described in this section invoke the C compiler to build
|
||||
@@ -159,7 +189,8 @@ shell that supports SQLite 3.31.1 or newer via "package require sqlite3".
|
||||
|
||||
TODO: ./configure + Makefile.msc build systems.
|
||||
|
||||
## Commands to Run SQLite Tests
|
||||
<a name=commands_to_run_tests></a>
|
||||
## 3.1. Commands to Run SQLite Tests
|
||||
|
||||
The **mdevtest** command is equivalent to running the veryquick tests and
|
||||
the [make fuzztest] target once for each of two --enable-all builds - one
|
||||
@@ -201,7 +232,18 @@ of the specific tests run.
|
||||
tclsh $TESTDIR/testrunner.tcl release
|
||||
```
|
||||
|
||||
## Running ZipVFS Tests
|
||||
As with <a href=#source code tests>source code tests</a>, one or more patterns
|
||||
may be appended to any of the above commands (mdevtest, sdevtest or release).
|
||||
In that case only Tcl tests (no fuzz or other tests) that match the specified
|
||||
pattern are run. For example, to run the just the Tcl rtree tests in all
|
||||
builds and configurations supported by "release":
|
||||
|
||||
```
|
||||
tclsh $TESTDIR/testrunner.tcl release rtree%
|
||||
```
|
||||
|
||||
<a name=zipvfs_tests></a>
|
||||
## 3.2. Running ZipVFS Tests
|
||||
|
||||
testrunner.tcl can build a zipvfs-enabled testfixture and use it to run
|
||||
tests from the Zipvfs project with the following command:
|
||||
@@ -217,7 +259,8 @@ test both SQLite and Zipvfs with a single command:
|
||||
tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
|
||||
```
|
||||
|
||||
## Investigating Source Code Test Failures
|
||||
<a name=source_code_test_failures></a>
|
||||
## 3.3. Investigating Source Code Test Failures
|
||||
|
||||
Investigating a test failure that occurs during source code testing is a
|
||||
two step process:
|
||||
@@ -244,9 +287,31 @@ target to build. This may be used either to run a [make] command test directly,
|
||||
or else to build a testfixture (or testfixture.exe) binary with which to
|
||||
run a Tcl test script, as <a href=#binary_test_failures>described above</a>.
|
||||
|
||||
<a name=testrunner_options></a>
|
||||
# 4. Extra testrunner.tcl Options
|
||||
|
||||
The testrunner.tcl script options in this section may be used with both source
|
||||
code and binary tests.
|
||||
|
||||
# 4. Controlling CPU Core Utilization
|
||||
The **--buildonly** option instructs testrunner.tcl just to build the binaries
|
||||
required by a test, not to run any actual tests. For example:
|
||||
|
||||
```
|
||||
# Build binaries required by release test.
|
||||
tclsh $TESTDIR/testrunner.tcl --buildonly release"
|
||||
```
|
||||
|
||||
The **--dryrun** option prevents testrunner.tcl from building any binaries
|
||||
or running any tests. Instead, it just writes the shell commands that it
|
||||
would normally execute into the testrunner.log file. Example:
|
||||
|
||||
```
|
||||
# Log the shell commmands that make up the mdevtest test.
|
||||
tclsh $TESTDIR/testrunner.tcl --dryrun mdevtest"
|
||||
```
|
||||
|
||||
<a name=cpu_cores></a>
|
||||
# 5. Controlling CPU Core Utilization
|
||||
|
||||
When running either binary or source code tests, testrunner.tcl reports the
|
||||
number of jobs it intends to use to stdout. e.g.
|
||||
@@ -277,8 +342,3 @@ testrunner.log and testrunner.db files:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -24,9 +24,11 @@
|
||||
# include <stdlib.h>
|
||||
# include <limits.h>
|
||||
# include <assert.h>
|
||||
# include "console_io.h"
|
||||
# include "sqlite3.h"
|
||||
#endif
|
||||
#ifndef HAVE_CONSOLE_IO_H
|
||||
# include "console_io.h"
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_CIO_NO_TRANSLATE
|
||||
# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
|
||||
** translation for Windows is effected for the build.
|
||||
*/
|
||||
|
||||
#define HAVE_CONSOLE_IO_H 1
|
||||
#ifndef SQLITE_INTERNAL_LINKAGE
|
||||
# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
|
||||
# include <stdio.h>
|
||||
|
||||
@@ -223,10 +223,12 @@ proc main {data} {
|
||||
Fts5ExtensionApi {
|
||||
set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"]
|
||||
set map [list]
|
||||
set lKey [list]
|
||||
foreach {k v} [get_struct_members $data] {
|
||||
if {[string match x* $k]==0} continue
|
||||
lappend map $k "<a href=#$k>$k</a>"
|
||||
lappend lKey $k
|
||||
}
|
||||
foreach k [lsort -decr $lKey] { lappend map $k "<a href=#$k>$k</a>" }
|
||||
output [string map $map $struct]
|
||||
}
|
||||
|
||||
|
||||
+59
-9
@@ -88,8 +88,11 @@ struct Fts5PhraseIter {
|
||||
** created with the "columnsize=0" option.
|
||||
**
|
||||
** xColumnText:
|
||||
** This function attempts to retrieve the text of column iCol of the
|
||||
** current document. If successful, (*pz) is set to point to a buffer
|
||||
** If parameter iCol is less than zero, or greater than or equal to the
|
||||
** number of columns in the table, SQLITE_RANGE is returned.
|
||||
**
|
||||
** Otherwise, this function attempts to retrieve the text of column iCol of
|
||||
** the current document. If successful, (*pz) is set to point to a buffer
|
||||
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
|
||||
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
|
||||
** if an error occurs, an SQLite error code is returned and the final values
|
||||
@@ -99,8 +102,10 @@ struct Fts5PhraseIter {
|
||||
** Returns the number of phrases in the current query expression.
|
||||
**
|
||||
** xPhraseSize:
|
||||
** Returns the number of tokens in phrase iPhrase of the query. Phrases
|
||||
** are numbered starting from zero.
|
||||
** If parameter iCol is less than zero, or greater than or equal to the
|
||||
** number of phrases in the current query, as returned by xPhraseCount,
|
||||
** 0 is returned. Otherwise, this function returns the number of tokens in
|
||||
** phrase iPhrase of the query. Phrases are numbered starting from zero.
|
||||
**
|
||||
** xInstCount:
|
||||
** Set *pnInst to the total number of occurrences of all phrases within
|
||||
@@ -116,12 +121,13 @@ struct Fts5PhraseIter {
|
||||
** Query for the details of phrase match iIdx within the current row.
|
||||
** Phrase matches are numbered starting from zero, so the iIdx argument
|
||||
** should be greater than or equal to zero and smaller than the value
|
||||
** output by xInstCount().
|
||||
** output by xInstCount(). If iIdx is less than zero or greater than
|
||||
** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
|
||||
**
|
||||
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
|
||||
** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
|
||||
** to the column in which it occurs and *piOff the token offset of the
|
||||
** first token of the phrase. Returns SQLITE_OK if successful, or an error
|
||||
** code (i.e. SQLITE_NOMEM) if an error occurs.
|
||||
** first token of the phrase. SQLITE_OK is returned if successful, or an
|
||||
** error code (i.e. SQLITE_NOMEM) if an error occurs.
|
||||
**
|
||||
** This API can be quite slow if used with an FTS5 table created with the
|
||||
** "detail=none" or "detail=column" option.
|
||||
@@ -147,6 +153,10 @@ struct Fts5PhraseIter {
|
||||
** Invoking Api.xUserData() returns a copy of the pointer passed as
|
||||
** the third argument to pUserData.
|
||||
**
|
||||
** If parameter iPhrase is less than zero, or greater than or equal to
|
||||
** the number of phrases in the query, as returned by xPhraseCount(),
|
||||
** this function returns SQLITE_RANGE.
|
||||
**
|
||||
** If the callback function returns any value other than SQLITE_OK, the
|
||||
** query is abandoned and the xQueryPhrase function returns immediately.
|
||||
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
|
||||
@@ -261,9 +271,42 @@ struct Fts5PhraseIter {
|
||||
**
|
||||
** xPhraseNextColumn()
|
||||
** See xPhraseFirstColumn above.
|
||||
**
|
||||
** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
|
||||
** This is used to access token iToken of phrase iPhrase of the current
|
||||
** query. Before returning, output parameter *ppToken is set to point
|
||||
** to a buffer containing the requested token, and *pnToken to the
|
||||
** size of this buffer in bytes.
|
||||
**
|
||||
** If iPhrase or iToken are less than zero, or if iPhrase is greater than
|
||||
** or equal to the number of phrases in the query as reported by
|
||||
** xPhraseCount(), or if iToken is equal to or greater than the number of
|
||||
** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
|
||||
are both zeroed.
|
||||
**
|
||||
** The output text is not a copy of the query text that specified the
|
||||
** token. It is the output of the tokenizer module. For tokendata=1
|
||||
** tables, this includes any embedded 0x00 and trailing data.
|
||||
**
|
||||
** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
|
||||
** This is used to access token iToken of phrase hit iIdx within the
|
||||
** current row. If iIdx is less than zero or greater than or equal to the
|
||||
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
|
||||
** output variable (*ppToken) is set to point to a buffer containing the
|
||||
** matching document token, and (*pnToken) to the size of that buffer in
|
||||
** bytes. This API is not available if the specified token matches a
|
||||
** prefix query term. In that case both output variables are always set
|
||||
** to 0.
|
||||
**
|
||||
** The output text is not a copy of the document text that was tokenized.
|
||||
** It is the output of the tokenizer module. For tokendata=1 tables, this
|
||||
** includes any embedded 0x00 and trailing data.
|
||||
**
|
||||
** This API can be quite slow if used with an FTS5 table created with the
|
||||
** "detail=none" or "detail=column" option.
|
||||
*/
|
||||
struct Fts5ExtensionApi {
|
||||
int iVersion; /* Currently always set to 2 */
|
||||
int iVersion; /* Currently always set to 3 */
|
||||
|
||||
void *(*xUserData)(Fts5Context*);
|
||||
|
||||
@@ -298,6 +341,13 @@ struct Fts5ExtensionApi {
|
||||
|
||||
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
|
||||
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
|
||||
|
||||
/* Below this point are iVersion>=3 only */
|
||||
int (*xQueryToken)(Fts5Context*,
|
||||
int iPhrase, int iToken,
|
||||
const char **ppToken, int *pnToken
|
||||
);
|
||||
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+26
-7
@@ -196,6 +196,7 @@ struct Fts5Config {
|
||||
char *zContent; /* content table */
|
||||
char *zContentRowid; /* "content_rowid=" option value */
|
||||
int bColumnsize; /* "columnsize=" option value (dflt==1) */
|
||||
int bTokendata; /* "tokendata=" option value (dflt==0) */
|
||||
int eDetail; /* FTS5_DETAIL_XXX value */
|
||||
char *zContentExprlist;
|
||||
Fts5Tokenizer *pTok;
|
||||
@@ -384,17 +385,19 @@ struct Fts5IndexIter {
|
||||
/*
|
||||
** Values used as part of the flags argument passed to IndexQuery().
|
||||
*/
|
||||
#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
|
||||
#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
|
||||
#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
|
||||
#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
|
||||
#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
|
||||
#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
|
||||
#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
|
||||
#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
|
||||
|
||||
/* The following are used internally by the fts5_index.c module. They are
|
||||
** defined here only to make it easier to avoid clashes with the flags
|
||||
** above. */
|
||||
#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
|
||||
#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
|
||||
#define FTS5INDEX_QUERY_SKIPHASH 0x0040
|
||||
#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
|
||||
#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
|
||||
#define FTS5INDEX_QUERY_SKIPHASH 0x0040
|
||||
#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080
|
||||
#define FTS5INDEX_QUERY_SCANONETERM 0x0100
|
||||
|
||||
/*
|
||||
** Create/destroy an Fts5Index object.
|
||||
@@ -463,6 +466,10 @@ void *sqlite3Fts5StructureRef(Fts5Index*);
|
||||
void sqlite3Fts5StructureRelease(void*);
|
||||
int sqlite3Fts5StructureTest(Fts5Index*, void*);
|
||||
|
||||
/*
|
||||
** Used by xInstToken():
|
||||
*/
|
||||
int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);
|
||||
|
||||
/*
|
||||
** Insert or remove data to or from the index. Each time a document is
|
||||
@@ -540,6 +547,13 @@ int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
|
||||
int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin);
|
||||
int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid);
|
||||
|
||||
void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*);
|
||||
|
||||
/* Used to populate hash tables for xInstToken in detail=none/column mode. */
|
||||
int sqlite3Fts5IndexIterWriteTokendata(
|
||||
Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff
|
||||
);
|
||||
|
||||
/*
|
||||
** End of interface to code in fts5_index.c.
|
||||
**************************************************************************/
|
||||
@@ -645,6 +659,7 @@ void sqlite3Fts5HashScanNext(Fts5Hash*);
|
||||
int sqlite3Fts5HashScanEof(Fts5Hash*);
|
||||
void sqlite3Fts5HashScanEntry(Fts5Hash *,
|
||||
const char **pzTerm, /* OUT: term (nul-terminated) */
|
||||
int *pnTerm, /* OUT: Size of term in bytes */
|
||||
const u8 **ppDoclist, /* OUT: pointer to doclist */
|
||||
int *pnDoclist /* OUT: size of doclist in bytes */
|
||||
);
|
||||
@@ -771,6 +786,10 @@ int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
|
||||
|
||||
int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
|
||||
|
||||
int sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*);
|
||||
int sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*);
|
||||
void sqlite3Fts5ExprClearTokens(Fts5Expr*);
|
||||
|
||||
/*******************************************
|
||||
** The fts5_expr.c API above this point is used by the other hand-written
|
||||
** C code in this module. The interfaces below this point are called by
|
||||
|
||||
+4
-2
@@ -252,8 +252,10 @@ static void fts5HighlightFunction(
|
||||
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
|
||||
ctx.iRangeEnd = -1;
|
||||
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
|
||||
|
||||
if( ctx.zIn ){
|
||||
if( rc==SQLITE_RANGE ){
|
||||
sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
|
||||
rc = SQLITE_OK;
|
||||
}else if( ctx.zIn ){
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ void sqlite3Fts5BufferAppendBlob(
|
||||
){
|
||||
if( nData ){
|
||||
if( fts5BufferGrow(pRc, pBuf, nData) ) return;
|
||||
assert( pBuf->p!=0 );
|
||||
memcpy(&pBuf->p[pBuf->n], pData, nData);
|
||||
pBuf->n += nData;
|
||||
}
|
||||
@@ -169,6 +170,7 @@ int sqlite3Fts5PoslistNext64(
|
||||
i64 *piOff /* IN/OUT: Current offset */
|
||||
){
|
||||
int i = *pi;
|
||||
assert( a!=0 || i==0 );
|
||||
if( i>=n ){
|
||||
/* EOF */
|
||||
*piOff = -1;
|
||||
@@ -176,6 +178,7 @@ int sqlite3Fts5PoslistNext64(
|
||||
}else{
|
||||
i64 iOff = *piOff;
|
||||
u32 iVal;
|
||||
assert( a!=0 );
|
||||
fts5FastGetVarint32(a, i, iVal);
|
||||
if( iVal<=1 ){
|
||||
if( iVal==0 ){
|
||||
|
||||
@@ -398,6 +398,16 @@ static int fts5ConfigParseSpecial(
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){
|
||||
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
|
||||
*pzErr = sqlite3_mprintf("malformed tokendata=... directive");
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
pConfig->bTokendata = (zArg[0]=='1');
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
*pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
+164
-44
@@ -100,7 +100,9 @@ struct Fts5ExprNode {
|
||||
struct Fts5ExprTerm {
|
||||
u8 bPrefix; /* True for a prefix term */
|
||||
u8 bFirst; /* True if token must be first in column */
|
||||
char *zTerm; /* nul-terminated term */
|
||||
char *pTerm; /* Term data */
|
||||
int nQueryTerm; /* Effective size of term in bytes */
|
||||
int nFullTerm; /* Size of term in bytes incl. tokendata */
|
||||
Fts5IndexIter *pIter; /* Iterator for this term */
|
||||
Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
|
||||
};
|
||||
@@ -967,7 +969,7 @@ static int fts5ExprNearInitAll(
|
||||
p->pIter = 0;
|
||||
}
|
||||
rc = sqlite3Fts5IndexQuery(
|
||||
pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
|
||||
pExpr->pIndex, p->pTerm, p->nQueryTerm,
|
||||
(pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
|
||||
(pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
|
||||
pNear->pColset,
|
||||
@@ -1604,7 +1606,7 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
|
||||
Fts5ExprTerm *pSyn;
|
||||
Fts5ExprTerm *pNext;
|
||||
Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
|
||||
sqlite3_free(pTerm->zTerm);
|
||||
sqlite3_free(pTerm->pTerm);
|
||||
sqlite3Fts5IterClose(pTerm->pIter);
|
||||
for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
|
||||
pNext = pSyn->pSynonym;
|
||||
@@ -1702,6 +1704,7 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
||||
typedef struct TokenCtx TokenCtx;
|
||||
struct TokenCtx {
|
||||
Fts5ExprPhrase *pPhrase;
|
||||
Fts5Config *pConfig;
|
||||
int rc;
|
||||
};
|
||||
|
||||
@@ -1735,8 +1738,12 @@ static int fts5ParseTokenize(
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pSyn, 0, (size_t)nByte);
|
||||
pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
|
||||
memcpy(pSyn->zTerm, pToken, nToken);
|
||||
pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
|
||||
pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
|
||||
if( pCtx->pConfig->bTokendata ){
|
||||
pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
|
||||
}
|
||||
memcpy(pSyn->pTerm, pToken, nToken);
|
||||
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
|
||||
pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
|
||||
}
|
||||
@@ -1761,7 +1768,11 @@ static int fts5ParseTokenize(
|
||||
if( rc==SQLITE_OK ){
|
||||
pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
|
||||
memset(pTerm, 0, sizeof(Fts5ExprTerm));
|
||||
pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
|
||||
pTerm->pTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
|
||||
pTerm->nFullTerm = pTerm->nQueryTerm = nToken;
|
||||
if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){
|
||||
pTerm->nQueryTerm = (int)strlen(pTerm->pTerm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1828,6 +1839,7 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
|
||||
memset(&sCtx, 0, sizeof(TokenCtx));
|
||||
sCtx.pPhrase = pAppend;
|
||||
sCtx.pConfig = pConfig;
|
||||
|
||||
rc = fts5ParseStringFromToken(pToken, &z);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -1875,12 +1887,15 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
Fts5Expr **ppNew
|
||||
){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */
|
||||
Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */
|
||||
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
|
||||
TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */
|
||||
|
||||
pOrig = pExpr->apExprPhrase[iPhrase];
|
||||
pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
|
||||
TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */
|
||||
if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
|
||||
rc = SQLITE_RANGE;
|
||||
}else{
|
||||
pOrig = pExpr->apExprPhrase[iPhrase];
|
||||
pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
|
||||
sizeof(Fts5ExprPhrase*));
|
||||
@@ -1893,7 +1908,7 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
|
||||
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
|
||||
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
|
||||
if( pColsetOrig ){
|
||||
sqlite3_int64 nByte;
|
||||
@@ -1907,26 +1922,27 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
}
|
||||
}
|
||||
|
||||
if( pOrig->nTerm ){
|
||||
int i; /* Used to iterate through phrase terms */
|
||||
for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
|
||||
int tflags = 0;
|
||||
Fts5ExprTerm *p;
|
||||
for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
|
||||
const char *zTerm = p->zTerm;
|
||||
rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
|
||||
0, 0);
|
||||
tflags = FTS5_TOKEN_COLOCATED;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
|
||||
sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pOrig->nTerm ){
|
||||
int i; /* Used to iterate through phrase terms */
|
||||
sCtx.pConfig = pExpr->pConfig;
|
||||
for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
|
||||
int tflags = 0;
|
||||
Fts5ExprTerm *p;
|
||||
for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
|
||||
rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0);
|
||||
tflags = FTS5_TOKEN_COLOCATED;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
|
||||
sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* This happens when parsing a token or quoted phrase that contains
|
||||
** no token characters at all. (e.g ... MATCH '""'). */
|
||||
sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
|
||||
}
|
||||
}else{
|
||||
/* This happens when parsing a token or quoted phrase that contains
|
||||
** no token characters at all. (e.g ... MATCH '""'). */
|
||||
sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
|
||||
@@ -2296,11 +2312,13 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
|
||||
if( parseGrowPhraseArray(pParse) ){
|
||||
fts5ExprPhraseFree(pPhrase);
|
||||
}else{
|
||||
Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii];
|
||||
Fts5ExprTerm *pTo = &pPhrase->aTerm[0];
|
||||
pParse->apPhrase[pParse->nPhrase++] = pPhrase;
|
||||
pPhrase->nTerm = 1;
|
||||
pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup(
|
||||
&pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
|
||||
);
|
||||
pTo->pTerm = sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm);
|
||||
pTo->nQueryTerm = p->nQueryTerm;
|
||||
pTo->nFullTerm = p->nFullTerm;
|
||||
pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING,
|
||||
0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
|
||||
);
|
||||
@@ -2485,16 +2503,17 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
|
||||
|
||||
/* Determine the maximum amount of space required. */
|
||||
for(p=pTerm; p; p=p->pSynonym){
|
||||
nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
|
||||
nByte += pTerm->nQueryTerm * 2 + 3 + 2;
|
||||
}
|
||||
zQuoted = sqlite3_malloc64(nByte);
|
||||
|
||||
if( zQuoted ){
|
||||
int i = 0;
|
||||
for(p=pTerm; p; p=p->pSynonym){
|
||||
char *zIn = p->zTerm;
|
||||
char *zIn = p->pTerm;
|
||||
char *zEnd = &zIn[p->nQueryTerm];
|
||||
zQuoted[i++] = '"';
|
||||
while( *zIn ){
|
||||
while( zIn<zEnd ){
|
||||
if( *zIn=='"' ) zQuoted[i++] = '"';
|
||||
zQuoted[i++] = *zIn++;
|
||||
}
|
||||
@@ -2572,8 +2591,10 @@ static char *fts5ExprPrintTcl(
|
||||
|
||||
zRet = fts5PrintfAppend(zRet, " {");
|
||||
for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
|
||||
char *zTerm = pPhrase->aTerm[iTerm].zTerm;
|
||||
zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
|
||||
Fts5ExprTerm *p = &pPhrase->aTerm[iTerm];
|
||||
zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ",
|
||||
p->nQueryTerm, p->pTerm
|
||||
);
|
||||
if( pPhrase->aTerm[iTerm].bPrefix ){
|
||||
zRet = fts5PrintfAppend(zRet, "*");
|
||||
}
|
||||
@@ -2974,6 +2995,17 @@ static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** pToken is a buffer nToken bytes in size that may or may not contain
|
||||
** an embedded 0x00 byte. If it does, return the number of bytes in
|
||||
** the buffer before the 0x00. If it does not, return nToken.
|
||||
*/
|
||||
static int fts5QueryTerm(const char *pToken, int nToken){
|
||||
int ii;
|
||||
for(ii=0; ii<nToken && pToken[ii]; ii++){}
|
||||
return ii;
|
||||
}
|
||||
|
||||
static int fts5ExprPopulatePoslistsCb(
|
||||
void *pCtx, /* Copy of 2nd argument to xTokenize() */
|
||||
int tflags, /* Mask of FTS5_TOKEN_* flags */
|
||||
@@ -2985,22 +3017,33 @@ static int fts5ExprPopulatePoslistsCb(
|
||||
Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
|
||||
Fts5Expr *pExpr = p->pExpr;
|
||||
int i;
|
||||
int nQuery = nToken;
|
||||
i64 iRowid = pExpr->pRoot->iRowid;
|
||||
|
||||
UNUSED_PARAM2(iUnused1, iUnused2);
|
||||
|
||||
if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
|
||||
if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE;
|
||||
if( pExpr->pConfig->bTokendata ){
|
||||
nQuery = fts5QueryTerm(pToken, nQuery);
|
||||
}
|
||||
if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
|
||||
for(i=0; i<pExpr->nPhrase; i++){
|
||||
Fts5ExprTerm *pTerm;
|
||||
Fts5ExprTerm *pT;
|
||||
if( p->aPopulator[i].bOk==0 ) continue;
|
||||
for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
|
||||
int nTerm = (int)strlen(pTerm->zTerm);
|
||||
if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
|
||||
&& memcmp(pTerm->zTerm, pToken, nTerm)==0
|
||||
for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){
|
||||
if( (pT->nQueryTerm==nQuery || (pT->nQueryTerm<nQuery && pT->bPrefix))
|
||||
&& memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
|
||||
){
|
||||
int rc = sqlite3Fts5PoslistWriterAppend(
|
||||
&pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
|
||||
);
|
||||
if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){
|
||||
int iCol = p->iOff>>32;
|
||||
int iTokOff = p->iOff & 0x7FFFFFFF;
|
||||
rc = sqlite3Fts5IndexIterWriteTokendata(
|
||||
pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
|
||||
);
|
||||
}
|
||||
if( rc ) return rc;
|
||||
break;
|
||||
}
|
||||
@@ -3135,3 +3178,80 @@ int sqlite3Fts5ExprPhraseCollist(
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Does the work of the fts5_api.xQueryToken() API method.
|
||||
*/
|
||||
int sqlite3Fts5ExprQueryToken(
|
||||
Fts5Expr *pExpr,
|
||||
int iPhrase,
|
||||
int iToken,
|
||||
const char **ppOut,
|
||||
int *pnOut
|
||||
){
|
||||
Fts5ExprPhrase *pPhrase = 0;
|
||||
|
||||
if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
|
||||
return SQLITE_RANGE;
|
||||
}
|
||||
pPhrase = pExpr->apExprPhrase[iPhrase];
|
||||
if( iToken<0 || iToken>=pPhrase->nTerm ){
|
||||
return SQLITE_RANGE;
|
||||
}
|
||||
|
||||
*ppOut = pPhrase->aTerm[iToken].pTerm;
|
||||
*pnOut = pPhrase->aTerm[iToken].nFullTerm;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Does the work of the fts5_api.xInstToken() API method.
|
||||
*/
|
||||
int sqlite3Fts5ExprInstToken(
|
||||
Fts5Expr *pExpr,
|
||||
i64 iRowid,
|
||||
int iPhrase,
|
||||
int iCol,
|
||||
int iOff,
|
||||
int iToken,
|
||||
const char **ppOut,
|
||||
int *pnOut
|
||||
){
|
||||
Fts5ExprPhrase *pPhrase = 0;
|
||||
Fts5ExprTerm *pTerm = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
|
||||
return SQLITE_RANGE;
|
||||
}
|
||||
pPhrase = pExpr->apExprPhrase[iPhrase];
|
||||
if( iToken<0 || iToken>=pPhrase->nTerm ){
|
||||
return SQLITE_RANGE;
|
||||
}
|
||||
pTerm = &pPhrase->aTerm[iToken];
|
||||
if( pTerm->bPrefix==0 ){
|
||||
if( pExpr->pConfig->bTokendata ){
|
||||
rc = sqlite3Fts5IterToken(
|
||||
pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut
|
||||
);
|
||||
}else{
|
||||
*ppOut = pTerm->pTerm;
|
||||
*pnOut = pTerm->nFullTerm;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the token mappings for all Fts5IndexIter objects mannaged by
|
||||
** the expression passed as the only argument.
|
||||
*/
|
||||
void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
|
||||
int ii;
|
||||
for(ii=0; ii<pExpr->nPhrase; ii++){
|
||||
Fts5ExprTerm *pT;
|
||||
for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){
|
||||
sqlite3Fts5IndexIterClearTokendata(pT->pIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-19
@@ -36,10 +36,15 @@ struct Fts5Hash {
|
||||
|
||||
/*
|
||||
** Each entry in the hash table is represented by an object of the
|
||||
** following type. Each object, its key (a nul-terminated string) and
|
||||
** its current data are stored in a single memory allocation. The
|
||||
** key immediately follows the object in memory. The position list
|
||||
** data immediately follows the key data in memory.
|
||||
** following type. Each object, its key, and its current data are stored
|
||||
** in a single memory allocation. The key immediately follows the object
|
||||
** in memory. The position list data immediately follows the key data
|
||||
** in memory.
|
||||
**
|
||||
** The key is Fts5HashEntry.nKey bytes in size. It consists of a single
|
||||
** byte identifying the index (either the main term index or a prefix-index),
|
||||
** followed by the term data. For example: "0token". There is no
|
||||
** nul-terminator - in this case nKey=6.
|
||||
**
|
||||
** The data that follows the key is in a similar, but not identical format
|
||||
** to the doclist data stored in the database. It is:
|
||||
@@ -174,8 +179,7 @@ static int fts5HashResize(Fts5Hash *pHash){
|
||||
unsigned int iHash;
|
||||
Fts5HashEntry *p = apOld[i];
|
||||
apOld[i] = p->pHashNext;
|
||||
iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
|
||||
(int)strlen(fts5EntryKey(p)));
|
||||
iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey);
|
||||
p->pHashNext = apNew[iHash];
|
||||
apNew[iHash] = p;
|
||||
}
|
||||
@@ -259,7 +263,7 @@ int sqlite3Fts5HashWrite(
|
||||
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
|
||||
char *zKey = fts5EntryKey(p);
|
||||
if( zKey[0]==bByte
|
||||
&& p->nKey==nToken
|
||||
&& p->nKey==nToken+1
|
||||
&& memcmp(&zKey[1], pToken, nToken)==0
|
||||
){
|
||||
break;
|
||||
@@ -289,9 +293,9 @@ int sqlite3Fts5HashWrite(
|
||||
zKey[0] = bByte;
|
||||
memcpy(&zKey[1], pToken, nToken);
|
||||
assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
|
||||
p->nKey = nToken;
|
||||
p->nKey = nToken+1;
|
||||
zKey[nToken+1] = '\0';
|
||||
p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
|
||||
p->nData = nToken+1 + sizeof(Fts5HashEntry);
|
||||
p->pHashNext = pHash->aSlot[iHash];
|
||||
pHash->aSlot[iHash] = p;
|
||||
pHash->nEntry++;
|
||||
@@ -408,12 +412,17 @@ static Fts5HashEntry *fts5HashEntryMerge(
|
||||
*ppOut = p1;
|
||||
p1 = 0;
|
||||
}else{
|
||||
int i = 0;
|
||||
char *zKey1 = fts5EntryKey(p1);
|
||||
char *zKey2 = fts5EntryKey(p2);
|
||||
while( zKey1[i]==zKey2[i] ) i++;
|
||||
int nMin = MIN(p1->nKey, p2->nKey);
|
||||
|
||||
if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
|
||||
int cmp = memcmp(zKey1, zKey2, nMin);
|
||||
if( cmp==0 ){
|
||||
cmp = p1->nKey - p2->nKey;
|
||||
}
|
||||
assert( cmp!=0 );
|
||||
|
||||
if( cmp>0 ){
|
||||
/* p2 is smaller */
|
||||
*ppOut = p2;
|
||||
ppOut = &p2->pScanNext;
|
||||
@@ -455,7 +464,7 @@ static int fts5HashEntrySort(
|
||||
Fts5HashEntry *pIter;
|
||||
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
|
||||
if( pTerm==0
|
||||
|| (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
|
||||
|| (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
|
||||
){
|
||||
Fts5HashEntry *pEntry = pIter;
|
||||
pEntry->pScanNext = 0;
|
||||
@@ -494,12 +503,11 @@ int sqlite3Fts5HashQuery(
|
||||
|
||||
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
|
||||
zKey = fts5EntryKey(p);
|
||||
assert( p->nKey+1==(int)strlen(zKey) );
|
||||
if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
|
||||
if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break;
|
||||
}
|
||||
|
||||
if( p ){
|
||||
int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1;
|
||||
int nHashPre = sizeof(Fts5HashEntry) + nTerm;
|
||||
int nList = p->nData - nHashPre;
|
||||
u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10));
|
||||
if( pRet ){
|
||||
@@ -560,19 +568,22 @@ int sqlite3Fts5HashScanEof(Fts5Hash *p){
|
||||
void sqlite3Fts5HashScanEntry(
|
||||
Fts5Hash *pHash,
|
||||
const char **pzTerm, /* OUT: term (nul-terminated) */
|
||||
int *pnTerm, /* OUT: Size of term in bytes */
|
||||
const u8 **ppDoclist, /* OUT: pointer to doclist */
|
||||
int *pnDoclist /* OUT: size of doclist in bytes */
|
||||
){
|
||||
Fts5HashEntry *p;
|
||||
if( (p = pHash->pScan) ){
|
||||
char *zKey = fts5EntryKey(p);
|
||||
int nTerm = (int)strlen(zKey);
|
||||
int nTerm = p->nKey;
|
||||
fts5HashAddPoslistSize(pHash, p, 0);
|
||||
*pzTerm = zKey;
|
||||
*ppDoclist = (const u8*)&zKey[nTerm+1];
|
||||
*pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
|
||||
*pnTerm = nTerm;
|
||||
*ppDoclist = (const u8*)&zKey[nTerm];
|
||||
*pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm);
|
||||
}else{
|
||||
*pzTerm = 0;
|
||||
*pnTerm = 0;
|
||||
*ppDoclist = 0;
|
||||
*pnDoclist = 0;
|
||||
}
|
||||
|
||||
+784
-75
File diff suppressed because it is too large
Load Diff
+88
-42
@@ -118,7 +118,7 @@ struct Fts5FullTable {
|
||||
Fts5Global *pGlobal; /* Global (connection wide) data */
|
||||
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
|
||||
int iSavepoint; /* Successful xSavepoint()+1 */
|
||||
int bInSavepoint;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
struct Fts5TransactionState ts;
|
||||
#endif
|
||||
@@ -656,12 +656,15 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
}
|
||||
idxStr[iIdxStr] = '\0';
|
||||
|
||||
/* Set idxFlags flags for the ORDER BY clause */
|
||||
/* Set idxFlags flags for the ORDER BY clause
|
||||
**
|
||||
** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC".
|
||||
*/
|
||||
if( pInfo->nOrderBy==1 ){
|
||||
int iSort = pInfo->aOrderBy[0].iColumn;
|
||||
if( iSort==(pConfig->nCol+1) && bSeenMatch ){
|
||||
idxFlags |= FTS5_BI_ORDER_RANK;
|
||||
}else if( iSort==-1 ){
|
||||
}else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
|
||||
idxFlags |= FTS5_BI_ORDER_ROWID;
|
||||
}
|
||||
if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
|
||||
@@ -913,6 +916,16 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
);
|
||||
assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
|
||||
|
||||
/* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table,
|
||||
** clear any token mappings accumulated at the fts5_index.c level. In
|
||||
** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH,
|
||||
** we need to retain the mappings for the entire query. */
|
||||
if( pCsr->ePlan==FTS5_PLAN_MATCH
|
||||
&& ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata
|
||||
){
|
||||
sqlite3Fts5ExprClearTokens(pCsr->pExpr);
|
||||
}
|
||||
|
||||
if( pCsr->ePlan<3 ){
|
||||
int bSkip = 0;
|
||||
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
|
||||
@@ -1898,7 +1911,10 @@ static int fts5ApiColumnText(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
if( iCol<0 || iCol>=pTab->pConfig->nCol ){
|
||||
rc = SQLITE_RANGE;
|
||||
}else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
|
||||
|| pCsr->ePlan==FTS5_PLAN_SPECIAL
|
||||
){
|
||||
*pz = 0;
|
||||
@@ -1923,8 +1939,9 @@ static int fts5CsrPoslist(
|
||||
int rc = SQLITE_OK;
|
||||
int bLive = (pCsr->pSorter==0);
|
||||
|
||||
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
|
||||
|
||||
if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
|
||||
rc = SQLITE_RANGE;
|
||||
}else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
|
||||
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
|
||||
Fts5PoslistPopulator *aPopulator;
|
||||
int i;
|
||||
@@ -1948,15 +1965,21 @@ static int fts5CsrPoslist(
|
||||
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
|
||||
}
|
||||
|
||||
if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
|
||||
Fts5Sorter *pSorter = pCsr->pSorter;
|
||||
int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
|
||||
*pn = pSorter->aIdx[iPhrase] - i1;
|
||||
*pa = &pSorter->aPoslist[i1];
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
|
||||
Fts5Sorter *pSorter = pCsr->pSorter;
|
||||
int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
|
||||
*pn = pSorter->aIdx[iPhrase] - i1;
|
||||
*pa = &pSorter->aPoslist[i1];
|
||||
}else{
|
||||
*pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
|
||||
}
|
||||
}else{
|
||||
*pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
|
||||
*pa = 0;
|
||||
*pn = 0;
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2063,12 +2086,6 @@ static int fts5ApiInst(
|
||||
){
|
||||
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
|
||||
rc = SQLITE_RANGE;
|
||||
#if 0
|
||||
}else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
|
||||
*piPhrase = pCsr->aInst[iIdx*3];
|
||||
*piCol = pCsr->aInst[iIdx*3 + 2];
|
||||
*piOff = -1;
|
||||
#endif
|
||||
}else{
|
||||
*piPhrase = pCsr->aInst[iIdx*3];
|
||||
*piCol = pCsr->aInst[iIdx*3 + 1];
|
||||
@@ -2323,13 +2340,56 @@ static int fts5ApiPhraseFirstColumn(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** xQueryToken() API implemenetation.
|
||||
*/
|
||||
static int fts5ApiQueryToken(
|
||||
Fts5Context* pCtx,
|
||||
int iPhrase,
|
||||
int iToken,
|
||||
const char **ppOut,
|
||||
int *pnOut
|
||||
){
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
return sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** xInstToken() API implemenetation.
|
||||
*/
|
||||
static int fts5ApiInstToken(
|
||||
Fts5Context *pCtx,
|
||||
int iIdx,
|
||||
int iToken,
|
||||
const char **ppOut, int *pnOut
|
||||
){
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
int rc = SQLITE_OK;
|
||||
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
|
||||
|| SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
|
||||
){
|
||||
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
|
||||
rc = SQLITE_RANGE;
|
||||
}else{
|
||||
int iPhrase = pCsr->aInst[iIdx*3];
|
||||
int iCol = pCsr->aInst[iIdx*3 + 1];
|
||||
int iOff = pCsr->aInst[iIdx*3 + 2];
|
||||
i64 iRowid = fts5CursorRowid(pCsr);
|
||||
rc = sqlite3Fts5ExprInstToken(
|
||||
pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut
|
||||
);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
|
||||
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
|
||||
);
|
||||
|
||||
static const Fts5ExtensionApi sFts5Api = {
|
||||
2, /* iVersion */
|
||||
3, /* iVersion */
|
||||
fts5ApiUserData,
|
||||
fts5ApiColumnCount,
|
||||
fts5ApiRowCount,
|
||||
@@ -2349,6 +2409,8 @@ static const Fts5ExtensionApi sFts5Api = {
|
||||
fts5ApiPhraseNext,
|
||||
fts5ApiPhraseFirstColumn,
|
||||
fts5ApiPhraseNextColumn,
|
||||
fts5ApiQueryToken,
|
||||
fts5ApiInstToken
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2615,9 +2677,7 @@ static int fts5RenameMethod(
|
||||
){
|
||||
int rc;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
pTab->bInSavepoint = 1;
|
||||
rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
|
||||
pTab->bInSavepoint = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2634,26 +2694,12 @@ int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
|
||||
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
char *zSql = 0;
|
||||
|
||||
fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
|
||||
|
||||
if( pTab->bInSavepoint==0 ){
|
||||
zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
|
||||
pTab->p.pConfig->zDb, pTab->p.pConfig->zName, pTab->p.pConfig->zName
|
||||
);
|
||||
if( zSql ){
|
||||
pTab->bInSavepoint = 1;
|
||||
rc = sqlite3_exec(pTab->p.pConfig->db, zSql, 0, 0, 0);
|
||||
pTab->bInSavepoint = 0;
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab->iSavepoint = iSavepoint+1;
|
||||
}
|
||||
rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab->iSavepoint = iSavepoint+1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2685,8 +2731,8 @@ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
int rc = SQLITE_OK;
|
||||
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
|
||||
fts5TripCursors(pTab);
|
||||
pTab->p.pConfig->pgsz = 0;
|
||||
if( (iSavepoint+1)<=pTab->iSavepoint ){
|
||||
pTab->p.pConfig->pgsz = 0;
|
||||
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
|
||||
}
|
||||
return rc;
|
||||
@@ -2914,7 +2960,7 @@ static int fts5ShadowName(const char *zName){
|
||||
** if anything is found amiss. Return a NULL pointer if everything is
|
||||
** OK.
|
||||
*/
|
||||
static int fts5Integrity(
|
||||
static int fts5IntegrityMethod(
|
||||
sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */
|
||||
const char *zSchema, /* Name of schema in which this table lives */
|
||||
const char *zTabname, /* Name of the table itself */
|
||||
@@ -2972,7 +3018,7 @@ static int fts5Init(sqlite3 *db){
|
||||
/* xRelease */ fts5ReleaseMethod,
|
||||
/* xRollbackTo */ fts5RollbackToMethod,
|
||||
/* xShadowName */ fts5ShadowName,
|
||||
/* xIntegrity */ fts5Integrity
|
||||
/* xIntegrity */ fts5IntegrityMethod
|
||||
};
|
||||
|
||||
int rc;
|
||||
|
||||
@@ -673,7 +673,7 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg);
|
||||
}
|
||||
|
||||
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){
|
||||
|
||||
+207
-1
@@ -244,6 +244,9 @@ static int SQLITE_TCLAPI xF5tApi(
|
||||
{ "xGetAuxdataInt", 1, "CLEAR" }, /* 15 */
|
||||
{ "xPhraseForeach", 4, "IPHRASE COLVAR OFFVAR SCRIPT" }, /* 16 */
|
||||
{ "xPhraseColumnForeach", 3, "IPHRASE COLVAR SCRIPT" }, /* 17 */
|
||||
|
||||
{ "xQueryToken", 2, "IPHRASE ITERM" }, /* 18 */
|
||||
{ "xInstToken", 2, "IDX ITERM" }, /* 19 */
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -500,6 +503,38 @@ static int SQLITE_TCLAPI xF5tApi(
|
||||
break;
|
||||
}
|
||||
|
||||
CASE(18, "xQueryToken") {
|
||||
const char *pTerm = 0;
|
||||
int nTerm = 0;
|
||||
int iPhrase = 0;
|
||||
int iTerm = 0;
|
||||
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &iTerm) ) return TCL_ERROR;
|
||||
rc = p->pApi->xQueryToken(p->pFts, iPhrase, iTerm, &pTerm, &nTerm);
|
||||
if( rc==SQLITE_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(pTerm, nTerm));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
CASE(19, "xInstToken") {
|
||||
const char *pTerm = 0;
|
||||
int nTerm = 0;
|
||||
int iIdx = 0;
|
||||
int iTerm = 0;
|
||||
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &iIdx) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &iTerm) ) return TCL_ERROR;
|
||||
rc = p->pApi->xInstToken(p->pFts, iIdx, iTerm, &pTerm, &nTerm);
|
||||
if( rc==SQLITE_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(pTerm, nTerm));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
break;
|
||||
@@ -1117,6 +1152,176 @@ static int SQLITE_TCLAPI f5tRegisterTok(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
typedef struct OriginTextCtx OriginTextCtx;
|
||||
struct OriginTextCtx {
|
||||
sqlite3 *db;
|
||||
fts5_api *pApi;
|
||||
};
|
||||
|
||||
typedef struct OriginTextTokenizer OriginTextTokenizer;
|
||||
struct OriginTextTokenizer {
|
||||
Fts5Tokenizer *pTok; /* Underlying tokenizer object */
|
||||
fts5_tokenizer tokapi; /* API implementation for pTok */
|
||||
};
|
||||
|
||||
/*
|
||||
** Delete the OriginTextCtx object indicated by the only argument.
|
||||
*/
|
||||
static void f5tOrigintextTokenizerDelete(void *pCtx){
|
||||
OriginTextCtx *p = (OriginTextCtx*)pCtx;
|
||||
ckfree(p);
|
||||
}
|
||||
|
||||
static int f5tOrigintextCreate(
|
||||
void *pCtx,
|
||||
const char **azArg,
|
||||
int nArg,
|
||||
Fts5Tokenizer **ppOut
|
||||
){
|
||||
OriginTextCtx *p = (OriginTextCtx*)pCtx;
|
||||
OriginTextTokenizer *pTok = 0;
|
||||
void *pTokCtx = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
pTok = (OriginTextTokenizer*)sqlite3_malloc(sizeof(OriginTextTokenizer));
|
||||
if( pTok==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else if( nArg<1 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
/* Locate the underlying tokenizer */
|
||||
rc = p->pApi->xFindTokenizer(p->pApi, azArg[0], &pTokCtx, &pTok->tokapi);
|
||||
}
|
||||
|
||||
/* Create the new tokenizer instance */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pTok->tokapi.xCreate(pTokCtx, &azArg[1], nArg-1, &pTok->pTok);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(pTok);
|
||||
pTok = 0;
|
||||
}
|
||||
*ppOut = (Fts5Tokenizer*)pTok;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void f5tOrigintextDelete(Fts5Tokenizer *pTokenizer){
|
||||
OriginTextTokenizer *p = (OriginTextTokenizer*)pTokenizer;
|
||||
if( p->pTok ){
|
||||
p->tokapi.xDelete(p->pTok);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
typedef struct OriginTextCb OriginTextCb;
|
||||
struct OriginTextCb {
|
||||
void *pCtx;
|
||||
const char *pText;
|
||||
int nText;
|
||||
int (*xToken)(void *, int, const char *, int, int, int);
|
||||
|
||||
char *aBuf; /* Buffer to use */
|
||||
int nBuf; /* Allocated size of aBuf[] */
|
||||
};
|
||||
|
||||
static int xOriginToken(
|
||||
void *pCtx, /* Copy of 2nd argument to xTokenize() */
|
||||
int tflags, /* Mask of FTS5_TOKEN_* flags */
|
||||
const char *pToken, /* Pointer to buffer containing token */
|
||||
int nToken, /* Size of token in bytes */
|
||||
int iStart, /* Byte offset of token within input text */
|
||||
int iEnd /* Byte offset of end of token within input */
|
||||
){
|
||||
OriginTextCb *p = (OriginTextCb*)pCtx;
|
||||
int ret = 0;
|
||||
|
||||
if( nToken==(iEnd-iStart) && 0==memcmp(pToken, &p->pText[iStart], nToken) ){
|
||||
/* Token exactly matches document text. Pass it through as is. */
|
||||
ret = p->xToken(p->pCtx, tflags, pToken, nToken, iStart, iEnd);
|
||||
}else{
|
||||
int nReq = nToken + 1 + (iEnd-iStart);
|
||||
if( nReq>p->nBuf ){
|
||||
sqlite3_free(p->aBuf);
|
||||
p->aBuf = sqlite3_malloc(nReq*2);
|
||||
if( p->aBuf==0 ) return SQLITE_NOMEM;
|
||||
p->nBuf = nReq*2;
|
||||
}
|
||||
|
||||
memcpy(p->aBuf, pToken, nToken);
|
||||
p->aBuf[nToken] = '\0';
|
||||
memcpy(&p->aBuf[nToken+1], &p->pText[iStart], iEnd-iStart);
|
||||
ret = p->xToken(p->pCtx, tflags, p->aBuf, nReq, iStart, iEnd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int f5tOrigintextTokenize(
|
||||
Fts5Tokenizer *pTokenizer,
|
||||
void *pCtx,
|
||||
int flags, /* Mask of FTS5_TOKENIZE_* flags */
|
||||
const char *pText, int nText,
|
||||
int (*xToken)(void *, int, const char *, int, int, int)
|
||||
){
|
||||
OriginTextTokenizer *p = (OriginTextTokenizer*)pTokenizer;
|
||||
OriginTextCb cb;
|
||||
int ret;
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
cb.pCtx = pCtx;
|
||||
cb.pText = pText;
|
||||
cb.nText = nText;
|
||||
cb.xToken = xToken;
|
||||
|
||||
ret = p->tokapi.xTokenize(p->pTok,(void*)&cb,flags,pText,nText,xOriginToken);
|
||||
sqlite3_free(cb.aBuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_fts5_register_origintext DB
|
||||
**
|
||||
** Description...
|
||||
*/
|
||||
static int SQLITE_TCLAPI f5tRegisterOriginText(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db = 0;
|
||||
fts5_api *pApi = 0;
|
||||
int rc;
|
||||
fts5_tokenizer tok = {0, 0, 0};
|
||||
OriginTextCtx *pCtx = 0;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( f5tDbAndApi(interp, objv[1], &db, &pApi) ) return TCL_ERROR;
|
||||
|
||||
pCtx = (OriginTextCtx*)ckalloc(sizeof(OriginTextCtx));
|
||||
pCtx->db = db;
|
||||
pCtx->pApi = pApi;
|
||||
|
||||
tok.xCreate = f5tOrigintextCreate;
|
||||
tok.xDelete = f5tOrigintextDelete;
|
||||
tok.xTokenize = f5tOrigintextTokenize;
|
||||
rc = pApi->xCreateTokenizer(
|
||||
pApi, "origintext", (void*)pCtx, &tok, f5tOrigintextTokenizerDelete
|
||||
);
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Entry point.
|
||||
*/
|
||||
@@ -1133,7 +1338,8 @@ int Fts5tcl_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_fts5_may_be_corrupt", f5tMayBeCorrupt, 0 },
|
||||
{ "sqlite3_fts5_token_hash", f5tTokenHash, 0 },
|
||||
{ "sqlite3_fts5_register_matchinfo", f5tRegisterMatchinfo, 0 },
|
||||
{ "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 }
|
||||
{ "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 },
|
||||
{ "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 }
|
||||
};
|
||||
int i;
|
||||
F5tTokenizerContext *pContext;
|
||||
|
||||
@@ -629,7 +629,7 @@ static int fts5VocabFilterMethod(
|
||||
if( pEq ){
|
||||
zTerm = (const char *)sqlite3_value_text(pEq);
|
||||
nTerm = sqlite3_value_bytes(pEq);
|
||||
f = 0;
|
||||
f = FTS5INDEX_QUERY_NOTOKENDATA;
|
||||
}else{
|
||||
if( pGe ){
|
||||
zTerm = (const char *)sqlite3_value_text(pGe);
|
||||
|
||||
@@ -61,6 +61,12 @@ proc fts5_test_collist {cmd} {
|
||||
set res
|
||||
}
|
||||
|
||||
proc fts5_collist {cmd iPhrase} {
|
||||
set res [list]
|
||||
$cmd xPhraseColumnForeach $iPhrase c { lappend res $c }
|
||||
set res
|
||||
}
|
||||
|
||||
proc fts5_test_columnsize {cmd} {
|
||||
set res [list]
|
||||
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
|
||||
@@ -69,6 +75,10 @@ proc fts5_test_columnsize {cmd} {
|
||||
set res
|
||||
}
|
||||
|
||||
proc fts5_columntext {cmd iCol} {
|
||||
$cmd xColumnText $iCol
|
||||
}
|
||||
|
||||
proc fts5_test_columntext {cmd} {
|
||||
set res [list]
|
||||
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
|
||||
@@ -125,6 +135,13 @@ proc fts5_test_queryphrase {cmd} {
|
||||
set res
|
||||
}
|
||||
|
||||
proc fts5_queryphrase {cmd iPhrase} {
|
||||
set cnt [list]
|
||||
for {set j 0} {$j < [$cmd xColumnCount]} {incr j} { lappend cnt 0 }
|
||||
$cmd xQueryPhrase $iPhrase [list test_queryphrase_cb cnt]
|
||||
set cnt
|
||||
}
|
||||
|
||||
proc fts5_test_phrasecount {cmd} {
|
||||
$cmd xPhraseCount
|
||||
}
|
||||
@@ -154,6 +171,9 @@ proc fts5_aux_test_functions {db} {
|
||||
|
||||
fts5_test_queryphrase
|
||||
fts5_test_phrasecount
|
||||
fts5_columntext
|
||||
fts5_queryphrase
|
||||
fts5_collist
|
||||
} {
|
||||
sqlite3_fts5_create_function $db $f $f
|
||||
}
|
||||
@@ -438,6 +458,20 @@ proc detail_is_none {} { detail_check ; expr {$::detail == "none"} }
|
||||
proc detail_is_col {} { detail_check ; expr {$::detail == "col" } }
|
||||
proc detail_is_full {} { detail_check ; expr {$::detail == "full"} }
|
||||
|
||||
proc foreach_tokenizer_mode {prefix script} {
|
||||
set saved $::testprefix
|
||||
foreach {d mapping} {
|
||||
"" {}
|
||||
"-origintext" {, tokenize="origintext unicode61", tokendata=1}
|
||||
} {
|
||||
set s [string map [list %TOKENIZER% $mapping] $script]
|
||||
set ::testprefix "$prefix$d"
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
uplevel $s
|
||||
}
|
||||
set ::testprefix $saved
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Convert a poslist of the type returned by fts5_test_poslist() to a
|
||||
|
||||
+44
-24
@@ -22,6 +22,7 @@ ifcapable !fts5 {
|
||||
}
|
||||
|
||||
foreach_detail_mode $::testprefix {
|
||||
foreach_tokenizer_mode $::testprefix {
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
|
||||
@@ -44,7 +45,7 @@ do_execsql_test 1.1 {
|
||||
#
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
|
||||
}
|
||||
do_execsql_test 2.1 {
|
||||
INSERT INTO t1 VALUES('a b c', 'd e f');
|
||||
@@ -73,8 +74,9 @@ do_execsql_test 2.4 {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
|
||||
}
|
||||
foreach {i x y} {
|
||||
1 {g f d b f} {h h e i a}
|
||||
@@ -97,8 +99,9 @@ foreach {i x y} {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
}
|
||||
foreach {i x y} {
|
||||
@@ -121,8 +124,9 @@ foreach {i x y} {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
}
|
||||
foreach {i x y} {
|
||||
@@ -145,8 +149,9 @@ foreach {i x y} {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
}
|
||||
|
||||
@@ -181,6 +186,7 @@ do_execsql_test 6.6 {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
expr srand(0)
|
||||
do_execsql_test 7.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y,z);
|
||||
@@ -222,6 +228,7 @@ for {set i 1} {$i <= 10} {incr i} {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 8.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, prefix="1,2,3");
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
@@ -236,6 +243,7 @@ do_execsql_test 8.1 {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
|
||||
expr srand(0)
|
||||
|
||||
@@ -280,8 +288,9 @@ for {set i 1} {$i <= 10} {incr i} {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 10.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
|
||||
}
|
||||
set d10 {
|
||||
1 {g f d b f} {h h e i a}
|
||||
@@ -314,19 +323,19 @@ do_execsql_test 10.4.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_catchsql_test 11.1 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rank, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rank, detail=%DETAIL% %TOKENIZER%);
|
||||
} {1 {reserved fts5 column name: rank}}
|
||||
do_catchsql_test 11.2 {
|
||||
CREATE VIRTUAL TABLE rank USING fts5(a, b, c, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE rank USING fts5(a, b, c, detail=%DETAIL% %TOKENIZER%);
|
||||
} {1 {reserved fts5 table name: rank}}
|
||||
do_catchsql_test 11.3 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rowid, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rowid, detail=%DETAIL% %TOKENIZER%);
|
||||
} {1 {reserved fts5 column name: rowid}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 12.1 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(x,y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
|
||||
} {}
|
||||
|
||||
do_catchsql_test 12.2 {
|
||||
@@ -341,8 +350,9 @@ do_test 12.3 {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 13.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t1(rowid, x) VALUES(1, 'o n e'), (2, 't w o');
|
||||
} {}
|
||||
|
||||
@@ -365,8 +375,9 @@ do_execsql_test 13.6 {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 14.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
WITH d(x,y) AS (
|
||||
SELECT NULL, 'xyz xyz xyz xyz xyz xyz'
|
||||
@@ -449,8 +460,9 @@ do_catchsql_test 16.2 {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 17.1 {
|
||||
CREATE VIRTUAL TABLE b2 USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE b2 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO b2 VALUES('a');
|
||||
INSERT INTO b2 VALUES('b');
|
||||
INSERT INTO b2 VALUES('c');
|
||||
@@ -466,8 +478,9 @@ do_test 17.2 {
|
||||
|
||||
if {[string match n* %DETAIL%]==0} {
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 17.3 {
|
||||
CREATE VIRTUAL TABLE c2 USING fts5(x, y, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE c2 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO c2 VALUES('x x x', 'x x x');
|
||||
SELECT rowid FROM c2 WHERE c2 MATCH 'y:x';
|
||||
} {1}
|
||||
@@ -476,8 +489,9 @@ if {[string match n* %DETAIL%]==0} {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 17.1 {
|
||||
CREATE VIRTUAL TABLE uio USING fts5(ttt, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE uio USING fts5(ttt, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO uio VALUES(NULL);
|
||||
INSERT INTO uio SELECT NULL FROM uio;
|
||||
INSERT INTO uio SELECT NULL FROM uio;
|
||||
@@ -524,8 +538,8 @@ do_execsql_test 17.9 {
|
||||
#--------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 18.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(c, d, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL% %TOKENIZER%);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(c, d, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t1 VALUES('abc*', NULL);
|
||||
INSERT INTO t2 VALUES(1, 'abcdefg');
|
||||
}
|
||||
@@ -540,8 +554,9 @@ do_execsql_test 18.3 {
|
||||
# fts5 table in the temp schema.
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 19.0 {
|
||||
CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t1 VALUES('x y z');
|
||||
INSERT INTO t1 VALUES('w x 1');
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH 'x';
|
||||
@@ -551,8 +566,9 @@ do_execsql_test 19.0 {
|
||||
# Test that 6 and 7 byte varints can be read.
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 20.0 {
|
||||
CREATE VIRTUAL TABLE temp.tmp USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE temp.tmp USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
}
|
||||
set ::ids [list \
|
||||
0 [expr 1<<36] [expr 2<<36] [expr 1<<43] [expr 2<<43]
|
||||
@@ -570,7 +586,7 @@ do_test 20.1 {
|
||||
#
|
||||
do_execsql_test 21.0 {
|
||||
CREATE TEMP TABLE t8(a, b);
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
}
|
||||
|
||||
do_execsql_test 21.1 {
|
||||
@@ -581,7 +597,7 @@ do_execsql_test 21.1 {
|
||||
}
|
||||
|
||||
do_execsql_test 22.0 {
|
||||
CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t9(rowid, x) VALUES(2, 'bbb');
|
||||
BEGIN;
|
||||
INSERT INTO t9(rowid, x) VALUES(1, 'aaa');
|
||||
@@ -596,7 +612,7 @@ do_execsql_test 22.1 {
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 23.0 {
|
||||
CREATE VIRTUAL TABLE t10 USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t10 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
CREATE TABLE t11(x);
|
||||
}
|
||||
do_execsql_test 23.1 {
|
||||
@@ -608,7 +624,7 @@ do_execsql_test 23.2 {
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 24.0 {
|
||||
CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
INSERT INTO t12 VALUES('aaaa');
|
||||
}
|
||||
do_execsql_test 24.1 {
|
||||
@@ -618,6 +634,9 @@ do_execsql_test 24.1 {
|
||||
INSERT INTO t12 VALUES('aaaa');
|
||||
END;
|
||||
}
|
||||
execsql_pp {
|
||||
SELECT rowid, hex(block) FROM t12_data
|
||||
}
|
||||
do_execsql_test 24.2 {
|
||||
INSERT INTO t12(t12) VALUES('integrity-check');
|
||||
}
|
||||
@@ -627,7 +646,7 @@ do_execsql_test 24.3 {
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 25.0 {
|
||||
CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL%);
|
||||
CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
|
||||
}
|
||||
do_execsql_test 25.1 {
|
||||
BEGIN;
|
||||
@@ -638,6 +657,7 @@ SELECT * FROM t13('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
expand_all_sql db
|
||||
|
||||
@@ -334,4 +334,47 @@ do_execsql_test 11.2 {
|
||||
SELECT fts5_hitcount(x1) FROM x1('one') LIMIT 1;
|
||||
} {5}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that xColumnText returns SQLITE_RANGE when it should.
|
||||
#
|
||||
reset_db
|
||||
fts5_aux_test_functions db
|
||||
do_execsql_test 12.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
|
||||
INSERT INTO t1 VALUES('one', 'two', 'three');
|
||||
INSERT INTO t1 VALUES('one', 'one', 'one');
|
||||
INSERT INTO t1 VALUES('two', 'two', 'two');
|
||||
INSERT INTO t1 VALUES('three', 'three', 'three');
|
||||
}
|
||||
|
||||
do_catchsql_test 12.1.1 {
|
||||
SELECT fts5_columntext(t1, -1) FROM t1('two');
|
||||
} {1 SQLITE_RANGE}
|
||||
do_catchsql_test 12.1.2 {
|
||||
SELECT fts5_columntext(t1, 3) FROM t1('two');
|
||||
} {1 SQLITE_RANGE}
|
||||
do_catchsql_test 12.1.2 {
|
||||
SELECT fts5_columntext(t1, 1) FROM t1('one AND two');
|
||||
} {0 two}
|
||||
|
||||
do_catchsql_test 12.2.1 {
|
||||
SELECT fts5_queryphrase(t1, -1) FROM t1('one AND two');
|
||||
} {1 SQLITE_RANGE}
|
||||
do_catchsql_test 12.2.2 {
|
||||
SELECT fts5_queryphrase(t1, 2) FROM t1('one AND two');
|
||||
} {1 SQLITE_RANGE}
|
||||
do_catchsql_test 12.2.3 {
|
||||
SELECT fts5_queryphrase(t1, 1) FROM t1('one AND two');
|
||||
} {0 {{1 2 1}}}
|
||||
|
||||
do_catchsql_test 12.3.1 {
|
||||
SELECT fts5_collist(t1, -1) FROM t1('one AND two');
|
||||
} {1 SQLITE_RANGE}
|
||||
do_catchsql_test 12.3.2 {
|
||||
SELECT fts5_collist(t1, 2) FROM t1('one AND two');
|
||||
} {1 SQLITE_RANGE}
|
||||
do_catchsql_test 12.3.3 {
|
||||
SELECT fts5_collist(t1, 1) FROM t1('one AND two');
|
||||
} {0 1}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -293,4 +293,39 @@ do_catchsql_test 7.2.5 {
|
||||
SELECT * FROM t1('abc') ORDER BY rank;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Check that if the content table is a view, and that view contains an
|
||||
# error, a reasonable error message is returned if the user tries to
|
||||
# read from the view via the fts5 table.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.1 {
|
||||
CREATE VIEW a1 AS
|
||||
SELECT 1 AS r, text_value(1) AS t
|
||||
UNION ALL
|
||||
SELECT 2 AS r, text_value(2) AS t;
|
||||
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(t, content='a1', content_rowid='r');
|
||||
}
|
||||
|
||||
foreach {tn sql} {
|
||||
1 "SELECT * FROM t1"
|
||||
2 "INSERT INTO t1(t1) VALUES('rebuild')"
|
||||
3 "SELECT * FROM t1 WHERE rowid=1"
|
||||
} {
|
||||
do_catchsql_test 8.2.$tn $sql {1 {no such function: text_value}}
|
||||
}
|
||||
|
||||
proc text_value {i} {
|
||||
if {$i==1} { return "one" }
|
||||
if {$i==2} { return "two" }
|
||||
return "many"
|
||||
}
|
||||
db func text_value text_value
|
||||
|
||||
do_execsql_test 8.3.1 { SELECT * FROM t1 } {one two}
|
||||
do_execsql_test 8.3.2 { INSERT INTO t1(t1) VALUES('rebuild') }
|
||||
do_execsql_test 8.3.3 { SELECT * FROM t1 WHERE rowid=1 } {one}
|
||||
do_execsql_test 8.3.4 { SELECT rowid FROM t1('two') } {2}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -966,6 +966,262 @@ do_catchsql_test 6.2 {
|
||||
UPDATE t1 SET content=randomblob(500) WHERE t1;
|
||||
} {1 {constraint failed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 7.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 40960 pagesize 4096 filename crash-d8b4a99207c10b.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 0a .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 0d 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 0d 0b 62 00 0f 97 0f 40 ..........b....@
|
||||
| 112: 0e d5 0e 75 0e 18 0d c0 0d 66 0d 0f 0c a4 0c 44 ...u.....f.....D
|
||||
| 128: 0b ec 0b a7 0b 62 00 00 00 00 00 00 00 00 00 00 .....b..........
|
||||
| 2912: 00 00 43 0d 06 17 11 11 08 75 74 61 62 6c 65 74 ..C......utablet
|
||||
| 2928: 34 74 34 43 52 45 41 54 45 20 56 49 52 54 55 41 4t4CREATE VIRTUA
|
||||
| 2944: 4c 20 54 41 42 4c 45 20 74 34 20 55 53 49 4e 47 L TABLE t4 USING
|
||||
| 2960: 20 66 74 73 35 76 6f 63 61 62 28 27 74 32 27 2c fts5vocab('t2',
|
||||
| 2976: 20 27 72 6f 77 27 29 43 0c 06 17 11 11 08 75 74 'row')C......ut
|
||||
| 2992: 61 62 6c 65 74 33 74 33 43 52 45 41 54 45 20 56 ablet3t3CREATE V
|
||||
| 3008: 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 33 20 IRTUAL TABLE t3
|
||||
| 3024: 55 53 49 4e 47 20 66 74 73 35 76 6f 63 61 62 28 USING fts5vocab(
|
||||
| 3040: 27 74 31 27 2c 20 27 72 6f 77 27 29 56 0b 06 17 't1', 'row')V...
|
||||
| 3056: 1f 1f 01 7d 74 61 62 6c 65 74 32 5f 63 6f 6e 66 ....tablet2_conf
|
||||
| 3072: 69 67 74 32 5f 63 6f 6e 66 69 67 0a 43 52 45 41 igt2_config.CREA
|
||||
| 3088: 54 45 20 54 41 42 4c 45 20 27 74 32 5f 63 6f 6e TE TABLE 't2_con
|
||||
| 3104: 66 69 67 27 28 6b 20 50 52 49 4d 41 52 59 20 4b fig'(k PRIMARY K
|
||||
| 3120: 45 59 2c 20 76 29 20 57 49 54 48 4f 55 54 20 52 EY, v) WITHOUT R
|
||||
| 3136: 4f 57 49 44 5e 0a 07 17 21 21 01 81 07 74 61 62 OWID^...!!...tab
|
||||
| 3152: 6c 65 74 32 5f 63 6f 6e 74 65 6e 74 74 32 5f 63 let2_contentt2_c
|
||||
| 3168: 6f 6e 74 65 6e 74 09 43 52 45 41 54 45 20 54 41 ontent.CREATE TA
|
||||
| 3184: 42 4c 45 20 27 74 32 5f 63 6f 6e 74 65 6e 74 27 BLE 't2_content'
|
||||
| 3200: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
|
||||
| 3216: 41 52 59 20 4b 45 59 2c 20 63 30 2c 20 63 31 2c ARY KEY, c0, c1,
|
||||
| 3232: 20 63 32 29 69 09 07 17 19 19 01 81 2d 74 61 62 c2)i.......-tab
|
||||
| 3248: 6c 65 74 32 5f 69 64 78 74 32 5f 69 64 78 08 43 let2_idxt2_idx.C
|
||||
| 3264: 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 32 5f REATE TABLE 't2_
|
||||
| 3280: 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d idx'(segid, term
|
||||
| 3296: 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 , pgno, PRIMARY
|
||||
| 3312: 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29 KEY(segid, term)
|
||||
| 3328: 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55 ) WITHOUT ROWIDU
|
||||
| 3344: 08 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 32 5f ........tablet2_
|
||||
| 3360: 64 61 74 61 74 32 5f 64 61 74 61 07 43 52 45 41 datat2_data.CREA
|
||||
| 3376: 54 45 20 54 41 42 4c 45 20 27 74 32 5f 64 61 74 TE TABLE 't2_dat
|
||||
| 3392: 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 a'(id INTEGER PR
|
||||
| 3408: 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b IMARY KEY, block
|
||||
| 3424: 20 42 4c 4f 42 29 58 07 07 17 11 11 08 81 1d 74 BLOB)X........t
|
||||
| 3440: 61 62 6c 65 74 32 74 32 43 52 45 41 54 45 20 56 ablet2t2CREATE V
|
||||
| 3456: 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 32 20 IRTUAL TABLE t2
|
||||
| 3472: 55 53 49 4e 47 20 66 74 73 35 28 27 61 27 2c 5b USING fts5('a',[
|
||||
| 3488: 62 5d 2c 22 63 22 2c 64 65 74 61 69 6c 3d 6e 6f b],.c.,detail=no
|
||||
| 3504: 6e 65 2c 63 6f 6c 75 6d 6e 73 69 7a 65 3d 30 29 ne,columnsize=0)
|
||||
| 3520: 56 06 06 17 1f 1f 01 7d 74 61 62 6c 65 74 31 5f V.......tablet1_
|
||||
| 3536: 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 69 67 06 configt1_config.
|
||||
| 3552: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
|
||||
| 3568: 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 49 4d 41 _config'(k PRIMA
|
||||
| 3584: 52 59 20 4b 45 59 2c 20 76 29 20 57 49 54 48 4f RY KEY, v) WITHO
|
||||
| 3600: 55 54 20 52 4f 57 49 44 5b 05 07 17 21 21 01 81 UT ROWID[...!!..
|
||||
| 3616: 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 69 7a 65 .tablet1_docsize
|
||||
| 3632: 74 31 5f 64 6f 63 73 69 7a 65 05 43 52 45 41 54 t1_docsize.CREAT
|
||||
| 3648: 45 20 54 41 42 4c 45 20 27 74 31 5f 64 6f 63 73 E TABLE 't1_docs
|
||||
| 3664: 69 7a 65 27 28 69 64 20 49 4e 54 45 47 45 52 20 ize'(id INTEGER
|
||||
| 3680: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 7a 20 PRIMARY KEY, sz
|
||||
| 3696: 42 4c 4f 42 29 5e 04 07 17 21 21 01 81 07 74 61 BLOB)^...!!...ta
|
||||
| 3712: 62 6c 65 74 31 5f 63 6f 6e 74 65 6e 74 74 31 5f blet1_contentt1_
|
||||
| 3728: 63 6f 6e 74 65 6e 74 04 43 52 45 41 54 45 20 54 content.CREATE T
|
||||
| 3744: 41 42 4c 45 20 27 74 31 5f 63 6f 6e 74 65 6e 74 ABLE 't1_content
|
||||
| 3760: 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 '(id INTEGER PRI
|
||||
| 3776: 4d 41 52 59 20 4b 45 59 2c 20 63 30 2c 20 63 31 MARY KEY, c0, c1
|
||||
| 3792: 2c 20 63 32 29 69 03 07 17 19 19 01 81 2d 74 61 , c2)i.......-ta
|
||||
| 3808: 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 64 78 03 blet1_idxt1_idx.
|
||||
| 3824: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
|
||||
| 3840: 5f 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72 _idx'(segid, ter
|
||||
| 3856: 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 m, pgno, PRIMARY
|
||||
| 3872: 20 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d KEY(segid, term
|
||||
| 3888: 29 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 )) WITHOUT ROWID
|
||||
| 3904: 55 02 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 U........tablet1
|
||||
| 3920: 5f 64 61 74 61 74 31 5f 64 61 74 61 02 43 52 45 _datat1_data.CRE
|
||||
| 3936: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 61 ATE TABLE 't1_da
|
||||
| 3952: 74 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 ta'(id INTEGER P
|
||||
| 3968: 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 RIMARY KEY, bloc
|
||||
| 3984: 6b 20 42 4c 4f 42 29 67 01 07 17 11 11 08 81 3b k BLOB)g.......;
|
||||
| 4000: 74 61 62 6c 65 74 31 74 31 43 52 45 41 54 45 20 tablet1t1CREATE
|
||||
| 4016: 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 31 VIRTUAL TABLE t1
|
||||
| 4032: 20 55 53 49 4e 47 20 66 74 73 35 28 61 2c 62 20 USING fts5(a,b
|
||||
| 4048: 75 6e 69 6e 64 65 78 65 64 2c 63 2c 74 6f 6b 65 unindexed,c,toke
|
||||
| 4064: 6e 69 7a 65 3d 22 70 6f 72 74 65 72 20 61 73 63 nize=.porter asc
|
||||
| 4080: 69 69 22 2c 74 6f 6b 65 6e 64 61 74 61 3d 31 29 ii.,tokendata=1)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 0f 68 00 05 0f 13 00 0f e6 0f 13 0f a8 0f 7c ..h............|
|
||||
| 16: 0f 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .*..............
|
||||
| 3856: 00 00 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 .......0........
|
||||
| 3872: 03 01 01 01 02 01 01 03 01 01 37 8c 80 80 80 80 ..........7.....
|
||||
| 3888: 01 03 00 74 00 00 00 2e 02 30 61 03 02 02 01 01 ...t.....0a.....
|
||||
| 3904: 62 03 02 03 01 01 63 03 02 04 01 01 67 03 06 01 b.....c.....g...
|
||||
| 3920: 02 02 01 01 68 03 06 01 02 03 01 01 69 03 06 01 ....h.......i...
|
||||
| 3936: 02 04 04 06 06 06 08 08 0f ef 00 14 2a 00 00 00 ............*...
|
||||
| 3952: 00 01 02 02 00 02 01 01 01 02 01 01 25 88 80 80 ............%...
|
||||
| 3968: 80 80 01 03 00 50 00 00 00 1f 02 30 67 02 08 02 .....P.....0g...
|
||||
| 3984: 01 02 02 01 01 68 02 08 03 01 02 03 01 01 69 02 .....h........i.
|
||||
| 4000: 08 04 01 02 04 04 09 09 37 84 80 80 80 7f f1 03 ........7.......
|
||||
| 4016: 00 74 00 00 00 2e 02 30 61 01 02 02 01 01 62 01 .t.....0a.....b.
|
||||
| 4032: 02 03 01 01 63 01 02 04 01 01 67 01 06 01 02 02 ....c.....g.....
|
||||
| 4048: 01 01 68 01 06 01 02 03 01 01 69 01 06 01 02 04 ..h.......i.....
|
||||
| 4064: 04 06 06 06 08 08 07 01 03 00 14 03 09 00 09 00 ................
|
||||
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
|
||||
| page 3 offset 8192
|
||||
| 0: 0a 00 00 00 03 0f ec 00 0f fa 0f f3 0f ec 00 00 ................
|
||||
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c ................
|
||||
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 03 0f be 00 0f ea 0f d4 0f be 00 00 ................
|
||||
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 03 ................
|
||||
| 4032: 05 00 17 17 17 61 20 62 20 63 67 20 68 20 69 67 .....a b cg h ig
|
||||
| 4048: 20 68 20 69 14 02 05 00 17 17 17 67 20 68 20 69 h i.......g h i
|
||||
| 4064: 61 20 62 20 63 67 20 68 20 69 14 01 05 00 17 17 a b cg h i......
|
||||
| 4080: 17 61 20 62 20 63 64 20 65 20 66 67 20 68 20 69 .a b cd e fg h i
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 03 0f e8 00 0f f8 0f f0 0f e8 00 00 ................
|
||||
| 4064: 00 00 00 00 00 00 00 00 06 03 03 00 12 03 00 03 ................
|
||||
| 4080: 06 02 03 00 12 03 00 03 06 01 03 00 12 03 00 03 ................
|
||||
| page 6 offset 20480
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| page 7 offset 24576
|
||||
| 0: 0d 00 00 00 03 0f 9e 00 0f e6 0f ef 0f 9e 00 00 ................
|
||||
| 3984: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 84 ..............A.
|
||||
| 4000: 80 80 80 80 01 04 00 81 06 00 00 00 34 02 30 61 ............4.0a
|
||||
| 4016: 01 01 01 01 01 62 01 01 01 01 01 63 01 01 01 01 .....b.....c....
|
||||
| 4032: 01 64 01 01 01 65 01 01 01 66 01 01 01 67 01 01 .d...e...f...g..
|
||||
| 4048: 01 01 01 68 01 01 01 01 01 69 01 01 01 04 06 06 ...h.....i......
|
||||
| 4064: 06 04 04 04 06 06 07 01 03 00 14 03 09 09 09 0f ................
|
||||
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
|
||||
| page 8 offset 28672
|
||||
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
|
||||
| page 9 offset 32768
|
||||
| 0: 0d 00 00 00 03 0f be 00 0f ea 0f d4 0f be 00 00 ................
|
||||
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 03 ................
|
||||
| 4032: 05 00 17 17 17 61 20 62 20 63 67 20 68 20 69 67 .....a b cg h ig
|
||||
| 4048: 20 68 20 69 14 02 05 00 17 17 17 67 20 68 20 69 h i.......g h i
|
||||
| 4064: 61 20 62 20 63 67 20 68 20 69 14 01 05 00 17 17 a b cg h i......
|
||||
| 4080: 17 61 20 62 20 63 64 20 65 20 66 67 20 68 20 69 .a b cd e fg h i
|
||||
| page 10 offset 36864
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| end crash-d8b4a99207c10b.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 7.1 {
|
||||
SELECT snippet(t1, -1, '.', '..', '[', ']'),
|
||||
highlight(t1, 2, '[', ']')
|
||||
FROM t1('g + h')
|
||||
WHERE rank MATCH 'bm25(1.0, 1.0)' ORDER BY rank;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 8.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 20480 pagesize 4096 filename crash-d57c01958e48ab.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 05 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 05 0e 10 00 0f 97 0f 40 ...............@
|
||||
| 112: 0e d5 0e 68 0e 10 01 00 00 00 00 00 00 00 00 00 ...h............
|
||||
| 3600: 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 74 31 5f V.......tablet1_
|
||||
| 3616: 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 69 67 05 configt1_config.
|
||||
| 3632: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
|
||||
| 3648: 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 49 4d 41 _config'(k PRIMA
|
||||
| 3664: 52 59 20 4b 45 59 2c 20 76 29 20 57 49 54 48 4f RY KEY, v) WITHO
|
||||
| 3680: 55 54 20 52 4f 57 49 44 6b 04 07 17 21 21 01 81 UT ROWIDk...!!..
|
||||
| 3696: 21 74 61 62 6c 65 74 31 5f 64 6f 63 73 69 7a 65 !tablet1_docsize
|
||||
| 3712: 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 45 41 54 t1_docsize.CREAT
|
||||
| 3728: 45 20 54 41 42 4c 45 20 27 74 31 5f 64 6f 63 73 E TABLE 't1_docs
|
||||
| 3744: 69 7a 65 27 28 69 64 20 49 4e 54 45 47 45 52 20 ize'(id INTEGER
|
||||
| 3760: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 7a 20 PRIMARY KEY, sz
|
||||
| 3776: 42 4c 4f 42 2c 20 6f 72 69 67 69 6e 20 49 4e 54 BLOB, origin INT
|
||||
| 3792: 45 47 45 52 29 69 03 07 17 19 19 01 81 2d 74 61 EGER)i.......-ta
|
||||
| 3808: 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 64 78 03 blet1_idxt1_idx.
|
||||
| 3824: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
|
||||
| 3840: 5f 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72 _idx'(segid, ter
|
||||
| 3856: 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 m, pgno, PRIMARY
|
||||
| 3872: 20 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d KEY(segid, term
|
||||
| 3888: 29 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 )) WITHOUT ROWID
|
||||
| 3904: 55 02 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 U........tablet1
|
||||
| 3920: 5f 64 61 74 61 74 31 5f 64 61 74 61 02 43 52 45 _datat1_data.CRE
|
||||
| 3936: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 61 ATE TABLE 't1_da
|
||||
| 3952: 74 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 ta'(id INTEGER P
|
||||
| 3968: 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 RIMARY KEY, bloc
|
||||
| 3984: 6b 20 42 4c 4f 42 29 67 01 07 17 11 11 08 81 3b k BLOB)g.......;
|
||||
| 4000: 74 61 62 6c 65 74 31 74 31 43 52 45 41 54 45 20 tablet1t1CREATE
|
||||
| 4016: 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 31 VIRTUAL TABLE t1
|
||||
| 4032: 20 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 USING fts5(a, b
|
||||
| 4048: 2c 20 63 6f 6e 74 65 6e 74 3d 27 27 2c 20 63 6f , content='', co
|
||||
| 4064: 6e 74 65 6e 74 6c 65 73 73 5f 64 65 6c 65 74 65 ntentless_delete
|
||||
| 4080: 3d 31 2c 20 74 6f 6b 65 6e 64 61 74 61 3d 31 29 =1, tokendata=1)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 0f eb 00 03 0e 17 00 0f e2 0e 17 0e 31 00 00 .............1..
|
||||
| 16: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3600: 00 00 00 00 00 00 00 18 0a 03 00 36 00 00 00 00 ...........6....
|
||||
| 3616: ff 00 00 01 01 01 01 00 01 01 01 01 01 01 00 00 ................
|
||||
| 3632: 07 83 29 84 80 80 80 80 01 04 00 86 56 00 00 01 ..).........V...
|
||||
| 3648: 96 04 30 61 61 61 01 02 02 01 04 02 04 01 08 02 ..0aaa..........
|
||||
| 3664: 04 04 04 01 10 02 04 04 04 04 04 04 04 01 20 02 .............. .
|
||||
| 3680: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 01 ................
|
||||
| 3696: 40 02 04 04 04 04 04 04 04 04 04 04 04 04 04 04 @...............
|
||||
| 3712: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 ................
|
||||
| 3728: 04 01 81 00 02 04 04 04 04 04 04 04 04 04 04 04 ................
|
||||
| 3744: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 ................
|
||||
| 3760: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 ................
|
||||
| 3776: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 ................
|
||||
| 3792: 04 04 04 04 02 02 62 63 01 06 01 01 02 01 03 62 ......bc.......b
|
||||
| 3808: 62 62 02 02 03 01 04 03 06 01 08 03 06 06 06 01 bb..............
|
||||
| 3824: 10 03 06 06 06 06 06 06 06 01 20 03 06 06 06 06 .......... .....
|
||||
| 3840: 06 06 06 06 06 06 06 06 06 06 06 01 40 03 06 06 ............@...
|
||||
| 3856: 06 06 06 06 06 06 06 06 06 06 06 06 06 06 06 06 ................
|
||||
| 3872: 06 06 06 06 06 06 06 06 06 06 16 06 06 02 02 63 ...............c
|
||||
| 3888: 64 02 06 01 01 02 01 03 63 63 63 03 02 05 01 04 d.......ccc.....
|
||||
| 3904: 05 0a 01 08 05 0a 0a 0a 01 10 05 0a 0a 0a 0a 0a ................
|
||||
| 3920: 0a 0a 01 20 05 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ... ............
|
||||
| 3936: 0a 0a 0a 0a 02 02 64 65 03 06 01 01 02 01 03 64 ......de.......d
|
||||
| 3952: 64 64 04 02 09 01 04 09 12 01 08 09 12 12 12 01 dd..............
|
||||
| 3968: 10 09 12 12 12 12 12 12 12 02 02 65 66 04 06 01 ...........ef...
|
||||
| 3984: 01 02 01 03 65 65 65 05 02 11 01 04 11 22 01 08 ....eee.........
|
||||
| 4000: 11 22 22 22 02 02 66 67 05 06 01 01 02 01 03 66 ......fg.......f
|
||||
| 4016: 56 66 06 02 21 01 04 21 42 02 02 67 68 06 06 01 Vf..!..!B..gh...
|
||||
| 4032: 01 02 cb 03 67 67 67 07 02 41 02 02 68 69 07 06 ....ggg..A..hi..
|
||||
| 4048: 01 01 02 04 81 13 09 50 09 2e 09 1c 09 12 09 0c .......P........
|
||||
| 4064: 09 08 07 01 03 00 14 07 81 77 07 00 00 00 15 22 .........w......
|
||||
| 4080: 00 00 00 00 ff 00 00 01 00 00 00 00 00 00 05 0c ................
|
||||
| page 3 offset 8192
|
||||
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 07 0f c8 00 0f f8 0f f0 0f e8 0f e0 ................
|
||||
| 16: 0f d8 0f d0 0f c8 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4032: 00 00 00 00 00 00 00 00 06 07 04 00 10 09 7f 01 ................
|
||||
| 4048: 06 06 04 00 10 09 3f 01 06 05 04 00 10 09 1f 01 ......?.........
|
||||
| 4064: 06 04 04 00 10 09 0f 01 06 03 04 00 10 09 07 01 ................
|
||||
| 4080: 06 02 04 00 10 09 03 01 06 01 04 00 10 09 01 01 ................
|
||||
| page 5 offset 16384
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| end crash-d57c01958e48ab.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 8.1 {
|
||||
SELECT rowid FROM t1('a* NOT ý') ;
|
||||
} {0 {1 2 3 4 5 6 7}}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
# 2010 June 15
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix fts5faultG
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set ::testprefix fts5faultH
|
||||
|
||||
sqlite3_fts5_register_origintext db
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(
|
||||
x, tokenize="origintext unicode61", tokendata=1
|
||||
);
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('oNe tWo thRee');
|
||||
INSERT INTO t1 VALUES('One Two Three');
|
||||
INSERT INTO t1 VALUES('onE twO threE');
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('one two three');
|
||||
INSERT INTO t1 VALUES('one two three');
|
||||
INSERT INTO t1 VALUES('one two three');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_faultsim_test 1 -faults oom* -prep {
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT rowid FROM t1('three');
|
||||
}
|
||||
} -test {
|
||||
faultsim_integrity_check
|
||||
faultsim_test_result {0 {1 2 3 4 5 6}}
|
||||
}
|
||||
|
||||
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(
|
||||
x, tokenize="origintext unicode61", tokendata=1
|
||||
);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, x) VALUES(10, 'aaa bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(12, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(13, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(14, 'bbb BBB bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(15, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(16, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(17, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(18, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(19, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(20, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(21, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(22, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(23, 'bbb bbb bbb');
|
||||
INSERT INTO t1(rowid, x) VALUES(24, 'aaa bbb BBB');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_faultsim_test 2 -faults oom* -prep {
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT rowid FROM t1('BBB AND AAA');
|
||||
}
|
||||
} -test {
|
||||
faultsim_integrity_check
|
||||
faultsim_test_result {0 {10 24}}
|
||||
}
|
||||
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(
|
||||
x, tokenize="origintext unicode61", tokendata=1
|
||||
);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
|
||||
INSERT INTO t1(rowid, x) VALUES(9, 'bbb Bbb BBB');
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, x) VALUES(10, 'aaa bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(11, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(12, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(13, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(14, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(15, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(16, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(17, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(18, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(19, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(20, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(21, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(22, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(23, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(24, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(25, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(26, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(27, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(28, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(29, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(30, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(31, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(32, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(33, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(34, 'bbb Bbb BBB');
|
||||
INSERT INTO t1(rowid, x) VALUES(35, 'aaa bbb BBB');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_faultsim_test 3 -faults oom* -prep {
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT rowid FROM t1('BBB AND AAA');
|
||||
}
|
||||
} -test {
|
||||
faultsim_integrity_check
|
||||
faultsim_test_result {0 {10 35}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -91,7 +91,6 @@ do_execsql_test 2.2.1 {
|
||||
INSERT INTO vt0(c0) VALUES ('xyz');
|
||||
}
|
||||
|
||||
breakpoint
|
||||
do_execsql_test 2.2.2 {
|
||||
ALTER TABLE t0 RENAME TO t1;
|
||||
}
|
||||
@@ -500,6 +499,41 @@ do_execsql_test 17.5 {
|
||||
SELECT c0 FROM t0 WHERE c0 GLOB '*faul*';
|
||||
} {assertionfaultproblem}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 18.0 {
|
||||
BEGIN;
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(text);
|
||||
ALTER TABLE t1 RENAME TO t2;
|
||||
}
|
||||
|
||||
do_execsql_test 18.1 {
|
||||
DROP TABLE t2;
|
||||
}
|
||||
|
||||
do_execsql_test 18.2 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 19.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(text);
|
||||
CREATE TABLE t2(text);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('one');
|
||||
INSERT INTO t1 VALUES('two');
|
||||
INSERT INTO t1 VALUES('three');
|
||||
INSERT INTO t1 VALUES('one');
|
||||
INSERT INTO t1 VALUES('two');
|
||||
INSERT INTO t1 VALUES('three');
|
||||
SAVEPOINT one;
|
||||
INSERT INTO t2 VALUES('one');
|
||||
INSERT INTO t2 VALUES('two');
|
||||
INSERT INTO t2 VALUES('three');
|
||||
ROLLBACK TO one;
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
# 2014 Jan 08
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests focused on phrase queries.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5origintext
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
foreach_detail_mode $testprefix {
|
||||
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize="origintext unicode61", detail=%DETAIL%
|
||||
);
|
||||
CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
INSERT INTO ft VALUES('Hello world');
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO ft(ft) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
proc b {x} { string map [list "\0" "."] $x }
|
||||
db func b b
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
select b(term) from vocab;
|
||||
} {
|
||||
hello.Hello
|
||||
world
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT rowid FROM ft('Hello');
|
||||
} {1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
# Return a random integer between 0 and n-1.
|
||||
#
|
||||
proc random {n} {
|
||||
expr {abs(int(rand()*$n))}
|
||||
}
|
||||
|
||||
proc select_one {list} {
|
||||
set n [llength $list]
|
||||
lindex $list [random $n]
|
||||
}
|
||||
|
||||
proc term {} {
|
||||
set first_letter {
|
||||
a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
}
|
||||
|
||||
set term [select_one $first_letter]
|
||||
append term [random 100]
|
||||
}
|
||||
|
||||
proc document {} {
|
||||
set nTerm [expr [random 5] + 5]
|
||||
set doc ""
|
||||
for {set ii 0} {$ii < $nTerm} {incr ii} {
|
||||
lappend doc [term]
|
||||
}
|
||||
set doc
|
||||
}
|
||||
db func document document
|
||||
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize="origintext unicode61", detail=%DETAIL%
|
||||
);
|
||||
INSERT INTO ft(ft, rank) VALUES('pgsz', 128);
|
||||
CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
|
||||
}
|
||||
|
||||
do_test 2.1 {
|
||||
for {set ii 0} {$ii < 500} {incr ii} {
|
||||
execsql { INSERT INTO ft VALUES( document() ) }
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
INSERT INTO ft(ft) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
INSERT INTO ft(ft, rank) VALUES('merge', 16);
|
||||
}
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
INSERT INTO ft(ft) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize="origintext unicode61", detail=%DETAIL%
|
||||
);
|
||||
CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
|
||||
|
||||
INSERT INTO ft(rowid, x) VALUES(1, 'hello');
|
||||
INSERT INTO ft(rowid, x) VALUES(2, 'Hello');
|
||||
INSERT INTO ft(rowid, x) VALUES(3, 'HELLO');
|
||||
}
|
||||
|
||||
#proc b {x} { string map [list "\0" "."] $x }
|
||||
#db func b b
|
||||
#execsql_pp { SELECT b(term) FROM vocab }
|
||||
|
||||
do_execsql_test 3.1.1 { SELECT rowid FROM ft('hello') } 1
|
||||
do_execsql_test 3.1.2 { SELECT rowid FROM ft('Hello') } 2
|
||||
do_execsql_test 3.1.3 { SELECT rowid FROM ft('HELLO') } 3
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
CREATE VIRTUAL TABLE ft2 USING fts5(x,
|
||||
tokenize="origintext unicode61",
|
||||
tokendata=1,
|
||||
detail=%DETAIL%
|
||||
);
|
||||
CREATE VIRTUAL TABLE vocab2 USING fts5vocab(ft2, instance);
|
||||
|
||||
INSERT INTO ft2(rowid, x) VALUES(1, 'hello');
|
||||
INSERT INTO ft2(rowid, x) VALUES(2, 'Hello');
|
||||
INSERT INTO ft2(rowid, x) VALUES(3, 'HELLO');
|
||||
|
||||
INSERT INTO ft2(rowid, x) VALUES(10, 'helloooo');
|
||||
}
|
||||
|
||||
#proc b {x} { string map [list "\0" "."] $x }
|
||||
#db func b b
|
||||
#execsql_pp { SELECT b(term) FROM vocab }
|
||||
|
||||
do_execsql_test 3.3.1 { SELECT rowid FROM ft2('hello') } {1 2 3}
|
||||
do_execsql_test 3.3.2 { SELECT rowid FROM ft2('Hello') } {1 2 3}
|
||||
do_execsql_test 3.3.3 { SELECT rowid FROM ft2('HELLO') } {1 2 3}
|
||||
|
||||
do_execsql_test 3.3.4 { SELECT rowid FROM ft2('hello*') } {1 2 3 10}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
proc querytoken {cmd iPhrase iToken} {
|
||||
set txt [$cmd xQueryToken $iPhrase $iToken]
|
||||
string map [list "\0" "."] $txt
|
||||
}
|
||||
sqlite3_fts5_create_function db querytoken querytoken
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize='origintext unicode61', tokendata=1, detail=%DETAIL%
|
||||
);
|
||||
INSERT INTO ft VALUES('one two three four');
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
SELECT rowid, querytoken(ft, 0, 0) FROM ft('TwO')
|
||||
} {1 two.TwO}
|
||||
do_execsql_test 4.2 {
|
||||
SELECT rowid, querytoken(ft, 0, 0) FROM ft('one TWO ThreE')
|
||||
} {1 one}
|
||||
do_execsql_test 4.3 {
|
||||
SELECT rowid, querytoken(ft, 1, 0) FROM ft('one TWO ThreE')
|
||||
} {1 two.TWO}
|
||||
|
||||
if {"%DETAIL%"=="full"} {
|
||||
# Phrase queries are only supported for detail=full.
|
||||
#
|
||||
do_execsql_test 4.4 {
|
||||
SELECT rowid, querytoken(ft, 0, 2) FROM ft('"one TWO ThreE"')
|
||||
} {1 three.ThreE}
|
||||
do_catchsql_test 4.5 {
|
||||
SELECT rowid, querytoken(ft, 0, 3) FROM ft('"one TWO ThreE"')
|
||||
} {1 SQLITE_RANGE}
|
||||
do_catchsql_test 4.6 {
|
||||
SELECT rowid, querytoken(ft, 1, 0) FROM ft('"one TWO ThreE"')
|
||||
} {1 SQLITE_RANGE}
|
||||
do_catchsql_test 4.7 {
|
||||
SELECT rowid, querytoken(ft, -1, 0) FROM ft('"one TWO ThreE"')
|
||||
} {1 SQLITE_RANGE}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
proc insttoken {cmd iIdx iToken} {
|
||||
set txt [$cmd xInstToken $iIdx $iToken]
|
||||
string map [list "\0" "."] $txt
|
||||
}
|
||||
sqlite3_fts5_create_function db insttoken insttoken
|
||||
fts5_aux_test_functions db
|
||||
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize='origintext unicode61', tokendata=1, detail=%DETAIL%
|
||||
);
|
||||
INSERT INTO ft VALUES('one ONE One oNe oNE one');
|
||||
}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
SELECT insttoken(ft, 0, 0),
|
||||
insttoken(ft, 1, 0),
|
||||
insttoken(ft, 2, 0),
|
||||
insttoken(ft, 3, 0),
|
||||
insttoken(ft, 4, 0),
|
||||
insttoken(ft, 5, 0)
|
||||
FROM ft('one');
|
||||
} {
|
||||
one one.ONE one.One one.oNe one.oNE one
|
||||
}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
SELECT insttoken(ft, 1, 0) FROM ft('one');
|
||||
} {
|
||||
one.ONE
|
||||
}
|
||||
|
||||
do_execsql_test 5.3 {
|
||||
SELECT fts5_test_poslist(ft) FROM ft('one');
|
||||
} {
|
||||
{0.0.0 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the xInstToken() API with:
|
||||
#
|
||||
# * a non tokendata=1 table.
|
||||
# * prefix queries.
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, y, tokenize='origintext unicode61', detail=%DETAIL%
|
||||
);
|
||||
|
||||
INSERT INTO ft VALUES('One Two', 'Three two');
|
||||
INSERT INTO ft VALUES('three Three', 'one One');
|
||||
}
|
||||
proc tokens {cmd} {
|
||||
set ret [list]
|
||||
for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
|
||||
set txt [$cmd xInstToken $iTok 0]
|
||||
set txt [string map [list "\0" "."] $txt]
|
||||
lappend ret $txt
|
||||
}
|
||||
set ret
|
||||
}
|
||||
sqlite3_fts5_create_function db tokens tokens
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
SELECT rowid, tokens(ft) FROM ft('One');
|
||||
} {1 one.One 2 one.One}
|
||||
|
||||
do_execsql_test 6.2 {
|
||||
SELECT rowid, tokens(ft) FROM ft('on*');
|
||||
} {1 {{}} 2 {{} {}}}
|
||||
|
||||
do_execsql_test 6.3 {
|
||||
SELECT rowid, tokens(ft) FROM ft('Three*');
|
||||
} {1 {{}} 2 {{}}}
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
# 2014 Jan 08
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests focused on phrase queries.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5origintext2
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize="origintext unicode61", tokendata=1
|
||||
);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft VALUES('Hello');
|
||||
INSERT INTO ft VALUES('hello');
|
||||
INSERT INTO ft VALUES('HELLO');
|
||||
INSERT INTO ft VALUES('today');
|
||||
INSERT INTO ft VALUES('today');
|
||||
INSERT INTO ft VALUES('today');
|
||||
INSERT INTO ft VALUES('World');
|
||||
INSERT INTO ft VALUES('world');
|
||||
INSERT INTO ft VALUES('WORLD');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 { SELECT rowid FROM ft('hello'); } {1 2 3}
|
||||
do_execsql_test 1.3 { SELECT rowid FROM ft('today'); } {4 5 6}
|
||||
do_execsql_test 1.4 { SELECT rowid FROM ft('world'); } {7 8 9}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
SELECT count(*) FROM ft_data
|
||||
} 3
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
DELETE FROM ft;
|
||||
INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
|
||||
BEGIN;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO ft SELECT 'Hello Hello Hello Hello Hello Hello Hello' FROM s;
|
||||
INSERT INTO ft VALUES ('hELLO hELLO hELLO');
|
||||
INSERT INTO ft VALUES('today today today today today today today');
|
||||
INSERT INTO ft VALUES('today today today today today today today');
|
||||
INSERT INTO ft VALUES('today today today today today today today');
|
||||
INSERT INTO ft VALUES('today today today today today today today');
|
||||
INSERT INTO ft VALUES('today today today today today today today');
|
||||
INSERT INTO ft VALUES('today today today today today today today');
|
||||
INSERT INTO ft VALUES('World World World World World World World');
|
||||
INSERT INTO ft VALUES('world world world world world world world');
|
||||
INSERT INTO ft VALUES('WORLD WORLD WORLD WORLD WORLD WORLD WORLD');
|
||||
INSERT INTO ft VALUES('World World World World World World World');
|
||||
INSERT INTO ft VALUES('world world world world world world world');
|
||||
INSERT INTO ft VALUES('WORLD WORLD WORLD WORLD WORLD WORLD WORLD');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 1.7 {
|
||||
SELECT count(*) FROM ft_data;
|
||||
} 23
|
||||
|
||||
do_execsql_test 1.8 { SELECT rowid FROM ft('hello') WHERE rowid>100; } {101}
|
||||
|
||||
do_execsql_test 1.9 {
|
||||
DELETE FROM ft;
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
SELECT count(*) FROM ft_data;
|
||||
} {2}
|
||||
do_execsql_test 1.10 {
|
||||
BEGIN;
|
||||
INSERT INTO ft VALUES('Hello');
|
||||
INSERT INTO ft VALUES('hello');
|
||||
INSERT INTO ft VALUES('HELLO');
|
||||
INSERT INTO ft VALUES('today');
|
||||
INSERT INTO ft VALUES('today');
|
||||
INSERT INTO ft VALUES('today');
|
||||
INSERT INTO ft VALUES('World');
|
||||
INSERT INTO ft VALUES('world');
|
||||
INSERT INTO ft VALUES('WORLD');
|
||||
}
|
||||
|
||||
do_execsql_test 1.11 { SELECT rowid FROM ft('hello'); } {1 2 3}
|
||||
do_execsql_test 1.12 { SELECT rowid FROM ft('today'); } {4 5 6}
|
||||
do_execsql_test 1.13 { SELECT rowid FROM ft('world'); } {7 8 9}
|
||||
do_execsql_test 1.14 { SELECT rowid FROM ft('hello') ORDER BY rank; } {1 2 3}
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
reset_db
|
||||
sqlite3_fts5_register_origintext db
|
||||
proc tokens {cmd} {
|
||||
set ret [list]
|
||||
for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
|
||||
set txt [$cmd xInstToken $iTok 0]
|
||||
set txt [string map [list "\0" "."] $txt]
|
||||
lappend ret $txt
|
||||
}
|
||||
set ret
|
||||
}
|
||||
sqlite3_fts5_create_function db tokens tokens
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(
|
||||
v, tokenize="origintext unicode61", tokendata=1, detail=none
|
||||
);
|
||||
|
||||
INSERT INTO x1 VALUES('xxx Xxx XXX yyy YYY yyy');
|
||||
INSERT INTO x1 VALUES('xxx yyy xxx yyy yyy yyy');
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT tokens(x1) FROM x1('xxx');
|
||||
} {
|
||||
{xxx xxx.Xxx xxx.XXX} {xxx xxx}
|
||||
}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
UPDATE x1_content SET c0 = 'xxx xxX xxx yyy yyy yyy' WHERE id=1;
|
||||
}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT tokens(x1) FROM x1('xxx');
|
||||
} {
|
||||
{xxx {} xxx} {xxx xxx}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# 2023 November 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests focused on phrase queries.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5origintext3
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
foreach_detail_mode $testprefix {
|
||||
reset_db
|
||||
|
||||
sqlite3_fts5_register_origintext db
|
||||
fts5_aux_test_functions db
|
||||
proc insttoken {cmd iIdx iToken} {
|
||||
set txt [$cmd xInstToken $iIdx $iToken]
|
||||
string map [list "\0" "."] $txt
|
||||
}
|
||||
sqlite3_fts5_create_function db insttoken insttoken
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
|
||||
);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
INSERT INTO ft VALUES('Hello world HELLO WORLD hello');
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT fts5_test_poslist(ft) FROM ft('hello');
|
||||
} {{0.0.0 0.0.2 0.0.4}}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT
|
||||
insttoken(ft, 0, 0),
|
||||
insttoken(ft, 1, 0),
|
||||
insttoken(ft, 2, 0)
|
||||
FROM ft('hello');
|
||||
} {hello.Hello hello.HELLO hello}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT
|
||||
insttoken(ft, 0, 0),
|
||||
insttoken(ft, 1, 0),
|
||||
insttoken(ft, 2, 0)
|
||||
FROM ft('hello') ORDER BY rank;
|
||||
} {hello.Hello hello.HELLO hello}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
CREATE VIRTUAL TABLE ft2 USING fts5(
|
||||
x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
|
||||
);
|
||||
INSERT INTO ft2(rowid, x) VALUES(1, 'ONE one two three ONE');
|
||||
INSERT INTO ft2(rowid, x) VALUES(2, 'TWO one two three TWO');
|
||||
INSERT INTO ft2(rowid, x) VALUES(3, 'THREE one two three THREE');
|
||||
}
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
SELECT insttoken(ft2, 0, 0), rowid FROM ft2('three') ORDER BY rank;
|
||||
} {three.THREE 3 three 1 three 2}
|
||||
|
||||
do_execsql_test 1.7 {
|
||||
INSERT INTO ft2(rowid, x) VALUES(10, 'aaa bbb BBB');
|
||||
INSERT INTO ft2(rowid, x) VALUES(12, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(13, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(14, 'bbb BBB bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(15, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(16, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(17, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(18, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(19, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(20, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(21, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(22, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(23, 'bbb bbb bbb');
|
||||
INSERT INTO ft2(rowid, x) VALUES(24, 'aaa bbb BBB');
|
||||
}
|
||||
|
||||
do_execsql_test 1.8 { SELECT rowid FROM ft2('aaa AND bbb'); } {10 24}
|
||||
do_execsql_test 1.9 { SELECT rowid FROM ft2('bbb AND aaa'); } {10 24}
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# 2023 November 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests focused on phrase queries.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5origintext4
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# The tests below verify that a doclist-index is used to limit the number
|
||||
# of pages loaded into the cache. It does this by querying sqlite3_db_status()
|
||||
# for the amount of memory used by the pager cache.
|
||||
#
|
||||
# memsubsys1 effectively limits the page-cache to 24 pages. Which masks
|
||||
# the effect tested by the tests in this file. And "mmap" prevents the
|
||||
# cache from being used, also preventing these tests from working.
|
||||
#
|
||||
if {[permutation]=="memsubsys1" || [permutation]=="mmap"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
sqlite3_fts5_register_origintext db
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA page_size = 4096;
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize="origintext unicode61", tokendata=1
|
||||
);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft SELECT 'the first thing';
|
||||
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<90000
|
||||
)
|
||||
INSERT INTO ft SELECT 'The second thing' FROM s;
|
||||
|
||||
INSERT INTO ft SELECT 'the first thing';
|
||||
COMMIT;
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
}
|
||||
|
||||
foreach {tn sql expr} {
|
||||
1 { SELECT rowid FROM ft('the') } {$mem > 250000}
|
||||
2 { SELECT rowid FROM ft('first') } {$mem < 50000}
|
||||
3 { SELECT rowid FROM ft('the first') } {$mem < 50000}
|
||||
} {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
sqlite3_fts5_register_origintext db
|
||||
|
||||
execsql $sql
|
||||
do_test 1.2.$tn {
|
||||
set mem [lindex [sqlite3_db_status db CACHE_USED 0] 1]
|
||||
expr $expr
|
||||
} 1
|
||||
}
|
||||
|
||||
proc b {x} { string map [list "\0" "."] $x }
|
||||
db func b b
|
||||
# execsql_pp { SELECT segid, b(term), pgno from ft_idx }
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
# 2023 Dec 04
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests for tables that use both tokendata=1 and contentless_delete=1.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5origintext
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Return a random integer between 0 and n-1.
|
||||
#
|
||||
proc random {n} { expr {abs(int(rand()*$n))} }
|
||||
|
||||
# Select an element of the list passed as the only argument at random and
|
||||
# return it.
|
||||
#
|
||||
proc select_one {list} {
|
||||
set n [llength $list]
|
||||
lindex $list [random $n]
|
||||
}
|
||||
|
||||
# Given a term that consists entirely of alphabet characters, return all
|
||||
# permutations of the term using upper and lower case characters. e.g.
|
||||
#
|
||||
# "abc" -> {CBA cBA CbA cbA CBa cBa Cba cba}
|
||||
#
|
||||
proc casify {term {lRet {{}}}} {
|
||||
if {$term==""} { return $lRet }
|
||||
set t [string range $term 1 end]
|
||||
set f1 [string toupper [string range $term 0 0]]
|
||||
set f2 [string tolower [string range $term 0 0]]
|
||||
set ret [list]
|
||||
foreach x $lRet {
|
||||
lappend ret "$x$f1"
|
||||
lappend ret "$x$f2"
|
||||
}
|
||||
return [casify $t $ret]
|
||||
}
|
||||
|
||||
proc vocab {} {
|
||||
list abc def ghi jkl mno pqr stu vwx yza
|
||||
}
|
||||
|
||||
# Return a random 3 letter term.
|
||||
#
|
||||
proc term {} {
|
||||
if {[info exists ::expanded_vocab]==0} {
|
||||
foreach v [vocab] { lappend ::expanded_vocab {*}[casify $v] }
|
||||
}
|
||||
|
||||
select_one $::expanded_vocab
|
||||
}
|
||||
|
||||
# Return a document - between 3 and 10 terms.
|
||||
#
|
||||
proc document {} {
|
||||
set nTerm [expr [random 3] + 7]
|
||||
set doc ""
|
||||
for {set ii 0} {$ii < $nTerm} {incr ii} {
|
||||
lappend doc [term]
|
||||
}
|
||||
set doc
|
||||
}
|
||||
db func document document
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
expr srand(6)
|
||||
|
||||
set NDOC 200
|
||||
set NLOOP 50
|
||||
|
||||
sqlite3_fts5_register_origintext db
|
||||
|
||||
proc tokens {cmd} {
|
||||
set ret [list]
|
||||
for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
|
||||
set txt [$cmd xInstToken $iTok 0]
|
||||
set txt [string map [list "\0" "."] $txt]
|
||||
lappend ret $txt
|
||||
}
|
||||
set ret
|
||||
}
|
||||
sqlite3_fts5_create_function db tokens tokens
|
||||
|
||||
proc rankfunc {cmd} {
|
||||
$cmd xRowid
|
||||
}
|
||||
sqlite3_fts5_create_function db rankfunc rankfunc
|
||||
|
||||
proc ctrl_tokens {term args} {
|
||||
set ret [list]
|
||||
set term [string tolower $term]
|
||||
foreach doc $args {
|
||||
foreach a $doc {
|
||||
if {[string tolower $a]==$term} {
|
||||
if {$a==$term} {
|
||||
lappend ret $a
|
||||
} else {
|
||||
lappend ret [string tolower $a].$a
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db func ctrl_tokens ctrl_tokens
|
||||
|
||||
proc do_all_vocab_test {tn} {
|
||||
foreach ::v [concat [vocab] nnn] {
|
||||
set answer [execsql {
|
||||
SELECT id, ctrl_tokens($::v, x) FROM ctrl WHERE x LIKE '%' || $::v || '%'
|
||||
}]
|
||||
do_execsql_test $tn.$::v.1 {
|
||||
SELECT rowid, tokens(ft) FROM ft($::v)
|
||||
} $answer
|
||||
do_execsql_test $tn.$::v.2 {
|
||||
SELECT rowid, tokens(ft) FROM ft($::v) ORDER BY rank
|
||||
} $answer
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(
|
||||
x, tokenize="origintext unicode61", content=, contentless_delete=1,
|
||||
tokendata=1
|
||||
);
|
||||
|
||||
CREATE TABLE ctrl(id INTEGER PRIMARY KEY, x TEXT);
|
||||
INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
|
||||
INSERT INTO ft(ft, rank) VALUES('rank', 'rankfunc()');
|
||||
}
|
||||
do_test 1.1 {
|
||||
for {set ii 0} {$ii < $NDOC} {incr ii} {
|
||||
set doc [document]
|
||||
execsql {
|
||||
INSERT INTO ft(rowid, x) VALUES($ii, $doc);
|
||||
INSERT INTO ctrl(id, x) VALUES($ii, $doc);
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
#execsql_pp { SELECT * FROM ctrl }
|
||||
#execsql_pp { SELECT * FROM ft }
|
||||
#fts5_aux_test_functions db
|
||||
#execsql_pp { SELECT rowid, tokens(ft), fts5_test_poslist(ft) FROM ft('ghi'); }
|
||||
|
||||
do_all_vocab_test 1.2
|
||||
|
||||
for {set ii 0} {$ii < $NLOOP} {incr ii} {
|
||||
set lRowid [execsql { SELECT id FROM ctrl WHERE random() % 2 }]
|
||||
foreach r $lRowid {
|
||||
execsql { DELETE FROM ft WHERE rowid = $r }
|
||||
execsql { DELETE FROM ctrl WHERE rowid = $r }
|
||||
|
||||
set doc [document]
|
||||
execsql { INSERT INTO ft(rowid, x) VALUES($r, $doc) }
|
||||
execsql { INSERT INTO ctrl(id, x) VALUES($r, $doc) }
|
||||
}
|
||||
do_all_vocab_test 1.3.$ii
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft2 USING fts5(
|
||||
x, y, tokenize="origintext unicode61", content=, contentless_delete=1,
|
||||
tokendata=1
|
||||
);
|
||||
|
||||
CREATE TABLE ctrl2(id INTEGER PRIMARY KEY, x TEXT, y TEXT);
|
||||
INSERT INTO ft2(ft2, rank) VALUES('pgsz', 64);
|
||||
INSERT INTO ft2(ft2, rank) VALUES('rank', 'rankfunc()');
|
||||
}
|
||||
do_test 2.1 {
|
||||
for {set ii 0} {$ii < $NDOC} {incr ii} {
|
||||
set doc1 [document]
|
||||
set doc2 [document]
|
||||
execsql {
|
||||
INSERT INTO ft2(rowid, x, y) VALUES($ii, $doc, $doc2);
|
||||
INSERT INTO ctrl2(id, x, y) VALUES($ii, $doc, $doc2);
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
proc do_all_vocab_test2 {tn} {
|
||||
foreach ::v [vocab] {
|
||||
set answer [execsql {
|
||||
SELECT id, ctrl_tokens($::v, x, y) FROM ctrl2
|
||||
WHERE x LIKE '%' || $::v || '%' OR y LIKE '%' || $::v || '%';
|
||||
}]
|
||||
do_execsql_test $tn.$::v.1 {
|
||||
SELECT rowid, tokens(ft2) FROM ft2($::v)
|
||||
} $answer
|
||||
do_execsql_test $tn.$::v.2 {
|
||||
SELECT rowid, tokens(ft2) FROM ft2($::v) ORDER BY rank
|
||||
} $answer
|
||||
}
|
||||
}
|
||||
|
||||
do_all_vocab_test2 2.2
|
||||
|
||||
for {set ii 0} {$ii < $NLOOP} {incr ii} {
|
||||
set lRowid [execsql { SELECT id FROM ctrl2 WHERE random() % 2 }]
|
||||
foreach r $lRowid {
|
||||
execsql { DELETE FROM ft2 WHERE rowid = $r }
|
||||
execsql { DELETE FROM ctrl2 WHERE rowid = $r }
|
||||
|
||||
set doc1 [document]
|
||||
set doc2 [document]
|
||||
execsql { INSERT INTO ft2(rowid, x, y) VALUES($r, $doc, $doc1) }
|
||||
execsql { INSERT INTO ctrl2(id, x, y) VALUES($r, $doc, $doc2) }
|
||||
}
|
||||
do_all_vocab_test 2.3.$ii
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
unset -nocomplain ::expanded_vocab
|
||||
proc vocab {} {
|
||||
list abcde fghij klmno
|
||||
}
|
||||
|
||||
proc do_all_vocab_test3 {tn} {
|
||||
foreach ::v [concat [vocab] nnn] {
|
||||
set answer [execsql {
|
||||
SELECT rowid, ctrl_tokens($::v, w) FROM ctrl3 WHERE w LIKE '%' || $::v || '%'
|
||||
}]
|
||||
do_execsql_test $tn.$::v.1 {
|
||||
SELECT rowid, tokens(ft3) FROM ft3($::v)
|
||||
} $answer
|
||||
do_execsql_test $tn.$::v.2 {
|
||||
SELECT rowid, tokens(ft3) FROM ft3($::v) ORDER BY rank
|
||||
} $answer
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE ft3 USING fts5(
|
||||
w, tokenize="origintext unicode61", content=, contentless_delete=1,
|
||||
tokendata=1
|
||||
);
|
||||
INSERT INTO ft3(ft3, rank) VALUES('rank', 'rankfunc()');
|
||||
CREATE TABLE ctrl3(w);
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<2
|
||||
)
|
||||
INSERT INTO ctrl3 SELECT document() FROM s;
|
||||
INSERT INTO ft3(rowid, w) SELECT rowid, w FROM ctrl3;
|
||||
}
|
||||
|
||||
do_all_vocab_test3 3.2
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -86,71 +86,76 @@ do_execsql_test 2.8 {
|
||||
# Tests with large/small rowid values.
|
||||
#
|
||||
|
||||
reset_db
|
||||
|
||||
expr srand(0)
|
||||
|
||||
set vocab {
|
||||
Popper Poppins Popsicle Porfirio Porrima Porsche
|
||||
Porter Portia Portland Portsmouth Portugal Portuguese
|
||||
Poseidon Post PostgreSQL Potemkin Potomac Potsdam
|
||||
Pottawatomie Potter Potts Pound Poussin Powell
|
||||
PowerPC PowerPoint Powers Powhatan Poznan Prada
|
||||
Prado Praetorian Prague Praia Prakrit Pratchett
|
||||
Pratt Pravda Praxiteles Preakness Precambrian Preminger
|
||||
Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
|
||||
}
|
||||
proc newdoc {} {
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
|
||||
foreach {tn cfg} {
|
||||
1 ""
|
||||
2 "INSERT INTO fff(fff, rank) VALUES('secure-delete', 1)"
|
||||
} {
|
||||
reset_db
|
||||
|
||||
expr srand(0)
|
||||
|
||||
set vocab {
|
||||
Popper Poppins Popsicle Porfirio Porrima Porsche
|
||||
Porter Portia Portland Portsmouth Portugal Portuguese
|
||||
Poseidon Post PostgreSQL Potemkin Potomac Potsdam
|
||||
Pottawatomie Potter Potts Pound Poussin Powell
|
||||
PowerPC PowerPoint Powers Powhatan Poznan Prada
|
||||
Prado Praetorian Prague Praia Prakrit Pratchett
|
||||
Pratt Pravda Praxiteles Preakness Precambrian Preminger
|
||||
Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db func newdoc newdoc
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE fff USING fts5(y);
|
||||
INSERT INTO fff(fff, rank) VALUES('pgsz', 64);
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
INSERT INTO fff(fff, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
proc lshuffle {in} {
|
||||
set out [list]
|
||||
while {[llength $in]>0} {
|
||||
set idx [expr int(abs(rand()) * [llength $in])]
|
||||
lappend out [lindex $in $idx]
|
||||
set in [lreplace $in $idx $idx]
|
||||
}
|
||||
set out
|
||||
}
|
||||
|
||||
#dump fff
|
||||
|
||||
set iTest 1
|
||||
foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
|
||||
#if {$iTest==1} { dump fff }
|
||||
#if {$iTest==1} { breakpoint }
|
||||
do_execsql_test 3.1.$iTest.$ii {
|
||||
DELETE FROM fff WHERE rowid=$ii;
|
||||
}
|
||||
#if {$iTest==1} { dump fff }
|
||||
if {($iTest % 20)==0} {
|
||||
do_execsql_test 3.1.$iTest.$ii.ic {
|
||||
INSERT INTO fff(fff) VALUES('integrity-check');
|
||||
proc newdoc {} {
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db func newdoc newdoc
|
||||
|
||||
do_execsql_test 3.$tn.0 {
|
||||
CREATE VIRTUAL TABLE fff USING fts5(y);
|
||||
INSERT INTO fff(fff, rank) VALUES('pgsz', 64);
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
}
|
||||
|
||||
execsql $cfg
|
||||
|
||||
proc lshuffle {in} {
|
||||
set out [list]
|
||||
while {[llength $in]>0} {
|
||||
set idx [expr int(abs(rand()) * [llength $in])]
|
||||
lappend out [lindex $in $idx]
|
||||
set in [lreplace $in $idx $idx]
|
||||
}
|
||||
set out
|
||||
}
|
||||
|
||||
#dump fff
|
||||
|
||||
set iTest 1
|
||||
foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
|
||||
#if {$iTest==1} { dump fff }
|
||||
#if {$iTest==1} { breakpoint }
|
||||
do_execsql_test 3.$tn.1.$iTest.$ii {
|
||||
DELETE FROM fff WHERE rowid=$ii;
|
||||
}
|
||||
#if {$iTest==1} { dump fff }
|
||||
if {($iTest % 20)==0} {
|
||||
do_execsql_test 3.$tn.1.$iTest.$ii.ic {
|
||||
INSERT INTO fff(fff) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
#if {$iTest==1} { break }
|
||||
incr iTest
|
||||
}
|
||||
#if {$iTest==1} { break }
|
||||
incr iTest
|
||||
}
|
||||
|
||||
#execsql_pp { SELECT rowid FROM fff('post') ORDER BY rowid ASC }
|
||||
|
||||
@@ -343,7 +343,9 @@ do_execsql_test 17.0 {
|
||||
INSERT INTO t2 VALUES('a aa aaa', 'b bb bbb');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 17.1 { SELECT * FROM t2('y:a*') WHERE rowid BETWEEN 10 AND 20 }
|
||||
do_execsql_test 17.1 {
|
||||
SELECT * FROM t2('y:a*') WHERE rowid BETWEEN 10 AND 20
|
||||
}
|
||||
do_execsql_test 17.2 {
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES('a aa aaa', 'b bb bbb');
|
||||
|
||||
@@ -42,7 +42,7 @@ proc fts5_test_bothlist {cmd} {
|
||||
}
|
||||
sqlite3_fts5_create_function db fts5_test_bothlist fts5_test_bothlist
|
||||
|
||||
proc fts5_rowid {cmd} { expr [$cmd xColumnText -1] }
|
||||
proc fts5_rowid {cmd} { expr [$cmd xRowid] }
|
||||
sqlite3_fts5_create_function db fts5_rowid fts5_rowid
|
||||
|
||||
do_execsql_test 1.$tok.0.1 "
|
||||
|
||||
@@ -280,6 +280,30 @@ do_catchsql_test 5.2 {
|
||||
INSERT INTO t1 SELECT randomblob(3000) FROM v1
|
||||
} {1 {query aborted}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
sqlite3_fts5_may_be_corrupt 1
|
||||
|
||||
do_execsql_test 6.0 {
|
||||
BEGIN TRANSACTION;
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a,b unindexed,c,tokenize="porter ascii",tokendata=1);
|
||||
REPLACE INTO t1_data VALUES(1,X'03090009');
|
||||
REPLACE INTO t1_data VALUES(10,X'000000000103030003010101020101030101');
|
||||
REPLACE INTO t1_data VALUES(137438953473,X'0000002e023061010202010162010203010163010204010167010601020201016801060102030101690106010204040606060808');
|
||||
REPLACE INTO t1_data VALUES(274877906945,X'0000001f013067020802010202010168020803010203010169020804010204040909');
|
||||
REPLACE INTO t1_data VALUES(412316860417,X'0000002e023061030202010162030203010163030204010167030601020201016803060102030101690306010204040606060808');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
CREATE VIRTUAL TABLE t3 USING fts5vocab('t1', 'row');
|
||||
}
|
||||
|
||||
do_catchsql_test 6.2 {
|
||||
SELECT * FROM t3;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -107,6 +107,12 @@
|
||||
# undef SQLITE_OMIT_UTF16 1
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_S... */
|
||||
#ifndef SQLITE_STRICT_SUBTYPE
|
||||
# define SQLITE_STRICT_SUBTYPE 1
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_T... */
|
||||
#ifndef SQLITE_TEMP_STORE
|
||||
|
||||
@@ -256,7 +256,7 @@ public final class CApi {
|
||||
sqlite3_bind_nio_buffer().
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_bind_blob(
|
||||
/*public*/ static int sqlite3_bind_blob(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data,
|
||||
int begin, int n
|
||||
){
|
||||
@@ -269,7 +269,7 @@ public final class CApi {
|
||||
final two arguments.
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_bind_blob(
|
||||
/*public*/ static int sqlite3_bind_blob(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data
|
||||
){
|
||||
return sqlite3_bind_nio_buffer(stmt, ndx, data, 0, -1);
|
||||
@@ -346,7 +346,7 @@ public final class CApi {
|
||||
@see https://docs.oracle.com/javase/8/docs/api/java/nio/Buffer.html
|
||||
*/
|
||||
@Experimental
|
||||
public static native int sqlite3_bind_nio_buffer(
|
||||
/*public*/ static native int sqlite3_bind_nio_buffer(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data,
|
||||
int beginPos, int howMany
|
||||
);
|
||||
@@ -356,7 +356,7 @@ public final class CApi {
|
||||
contents, up to its limit() (as opposed to its capacity()).
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_bind_nio_buffer(
|
||||
/*public*/ static int sqlite3_bind_nio_buffer(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data
|
||||
){
|
||||
return sqlite3_bind_nio_buffer(stmt, ndx, data, 0, -1);
|
||||
@@ -600,7 +600,7 @@ public final class CApi {
|
||||
sqlite3_blob_read() (0 on success).
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_blob_read_nio_buffer(
|
||||
/*public*/ static int sqlite3_blob_read_nio_buffer(
|
||||
@NotNull sqlite3_blob src, int srcOffset,
|
||||
@NotNull java.nio.ByteBuffer tgt, int tgtOffset, int howMany
|
||||
){
|
||||
@@ -624,7 +624,7 @@ public final class CApi {
|
||||
for any reason.
|
||||
*/
|
||||
@Experimental
|
||||
public static java.nio.ByteBuffer sqlite3_blob_read_nio_buffer(
|
||||
/*public*/ static java.nio.ByteBuffer sqlite3_blob_read_nio_buffer(
|
||||
@NotNull sqlite3_blob src, int srcOffset, int howMany
|
||||
){
|
||||
if( !JNI_SUPPORTS_NIO || src==null ) return null;
|
||||
@@ -645,7 +645,7 @@ public final class CApi {
|
||||
Overload alias for sqlite3_blob_read_nio_buffer().
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_blob_read(
|
||||
/*public*/ static int sqlite3_blob_read(
|
||||
@NotNull sqlite3_blob src, int srcOffset,
|
||||
@NotNull java.nio.ByteBuffer tgt,
|
||||
int tgtOffset, int howMany
|
||||
@@ -668,7 +668,7 @@ public final class CApi {
|
||||
the result of the underlying call to sqlite3_blob_read().
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_blob_read(
|
||||
/*public*/ static int sqlite3_blob_read(
|
||||
@NotNull sqlite3_blob src,
|
||||
@NotNull java.nio.ByteBuffer tgt
|
||||
){
|
||||
@@ -727,7 +727,7 @@ public final class CApi {
|
||||
returns the result of the underlying call to sqlite3_blob_read().
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_blob_write_nio_buffer(
|
||||
/*public*/ static int sqlite3_blob_write_nio_buffer(
|
||||
@NotNull sqlite3_blob tgt, int tgtOffset,
|
||||
@NotNull java.nio.ByteBuffer src,
|
||||
int srcOffset, int howMany
|
||||
@@ -756,7 +756,7 @@ public final class CApi {
|
||||
of b.
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_blob_write(
|
||||
/*public*/ static int sqlite3_blob_write(
|
||||
@NotNull sqlite3_blob tgt, int tgtOffset,
|
||||
@NotNull java.nio.ByteBuffer src
|
||||
){
|
||||
@@ -770,7 +770,7 @@ public final class CApi {
|
||||
of tgt.
|
||||
*/
|
||||
@Experimental
|
||||
public static int sqlite3_blob_write(
|
||||
/*public*/ static int sqlite3_blob_write(
|
||||
@NotNull sqlite3_blob tgt,
|
||||
@NotNull java.nio.ByteBuffer src
|
||||
){
|
||||
@@ -926,7 +926,7 @@ public final class CApi {
|
||||
would return null for the same inputs.
|
||||
*/
|
||||
@Experimental
|
||||
public static native java.nio.ByteBuffer sqlite3_column_nio_buffer(
|
||||
/*public*/ static native java.nio.ByteBuffer sqlite3_column_nio_buffer(
|
||||
@NotNull sqlite3_stmt stmt, int ndx
|
||||
);
|
||||
|
||||
@@ -1848,7 +1848,7 @@ public final class CApi {
|
||||
then this function behaves like sqlite3_result_error_toobig().
|
||||
*/
|
||||
@Experimental
|
||||
public static native void sqlite3_result_nio_buffer(
|
||||
/*public*/ static native void sqlite3_result_nio_buffer(
|
||||
@NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob,
|
||||
int begin, int n
|
||||
);
|
||||
@@ -1858,7 +1858,7 @@ public final class CApi {
|
||||
as the result blob content.
|
||||
*/
|
||||
@Experimental
|
||||
public static void sqlite3_result_nio_buffer(
|
||||
/*public*/ static void sqlite3_result_nio_buffer(
|
||||
@NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob
|
||||
){
|
||||
sqlite3_result_nio_buffer(cx, blob, 0, -1);
|
||||
@@ -1963,7 +1963,7 @@ public final class CApi {
|
||||
sqlite3_result_nio_buffer().
|
||||
*/
|
||||
@Experimental
|
||||
public static void sqlite3_result_blob(
|
||||
/*public*/ static void sqlite3_result_blob(
|
||||
@NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob,
|
||||
int begin, int n
|
||||
){
|
||||
@@ -1975,7 +1975,7 @@ public final class CApi {
|
||||
sqlite3_result_nio_buffer().
|
||||
*/
|
||||
@Experimental
|
||||
public static void sqlite3_result_blob(
|
||||
/*public*/ static void sqlite3_result_blob(
|
||||
@NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob
|
||||
){
|
||||
sqlite3_result_nio_buffer(cx, blob);
|
||||
@@ -2387,7 +2387,7 @@ public final class CApi {
|
||||
would return null for the same input.
|
||||
*/
|
||||
@Experimental
|
||||
public static native java.nio.ByteBuffer sqlite3_value_nio_buffer(
|
||||
/*public*/ static native java.nio.ByteBuffer sqlite3_value_nio_buffer(
|
||||
@NotNull sqlite3_value v
|
||||
);
|
||||
|
||||
|
||||
@@ -625,10 +625,20 @@ public class TesterFts5 {
|
||||
"SELECT fts5_columntext(ft, 1) FROM ft('x') ORDER BY rowid",
|
||||
"[x, x, x y z, x z, x y z, x]"
|
||||
);
|
||||
do_execsql_test(db,
|
||||
"SELECT fts5_columntext(ft, 2) FROM ft('x') ORDER BY rowid",
|
||||
"[null, null, null, null, null, null]"
|
||||
);
|
||||
boolean threw = false;
|
||||
try{
|
||||
/* columntext() used to return NULLs when given an out-of bounds column
|
||||
but now results in a range error. */
|
||||
do_execsql_test(db,
|
||||
"SELECT fts5_columntext(ft, 2) FROM ft('x') ORDER BY rowid",
|
||||
"[null, null, null, null, null, null]"
|
||||
);
|
||||
}catch(Exception e){
|
||||
threw = true;
|
||||
affirm( e.getMessage().matches(".*column index out of range") );
|
||||
}
|
||||
affirm( threw );
|
||||
threw = false;
|
||||
|
||||
/* Test fts5_columntotalsize() */
|
||||
do_execsql_test(db,
|
||||
|
||||
+59
-21
@@ -26,9 +26,14 @@
|
||||
**
|
||||
** .load ./randomjson
|
||||
** SELECT random_json(1);
|
||||
** SELECT random_json5(1);
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#ifdef SQLITE_STATIC_RANDOMJSON
|
||||
# include "sqlite3.h"
|
||||
#else
|
||||
# include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -51,17 +56,18 @@ static unsigned int prngInt(Prng *p){
|
||||
return p->x ^ p->y;
|
||||
}
|
||||
|
||||
static const char *azJsonAtoms[] = {
|
||||
/* JSON /* JSON-5 */
|
||||
static char *azJsonAtoms[] = {
|
||||
/* JSON JSON-5 */
|
||||
"0", "0",
|
||||
"1", "1",
|
||||
"-1", "-1",
|
||||
"2", "+2",
|
||||
"3", "3",
|
||||
"2.5", "2.5",
|
||||
"3DDDD", "3DDDD",
|
||||
"2.5DD", "2.5DD",
|
||||
"0.75", ".75",
|
||||
"-4.0e2", "-4.e2",
|
||||
"5.0e-3", "+5e-3",
|
||||
"6.DDe+0DD", "6.DDe+0DD",
|
||||
"0", "0x0",
|
||||
"512", "0x200",
|
||||
"256", "+0x100",
|
||||
@@ -73,12 +79,14 @@ static const char *azJsonAtoms[] = {
|
||||
"-9.0e999", "-Infinity",
|
||||
"9.0e999", "+Infinity",
|
||||
"null", "NaN",
|
||||
"-0.0005123", "-0.0005123",
|
||||
"-0.0005DD", "-0.0005DD",
|
||||
"4.35e-3", "+4.35e-3",
|
||||
"\"gem\\\"hay\"", "\"gem\\\"hay\"",
|
||||
"\"icy'joy\"", "'icy\\'joy\'",
|
||||
"\"keylog\"", "\"key\\\nlog\"",
|
||||
"\"mix\\\\\\tnet\"", "\"mix\\\\\\tnet\"",
|
||||
"\"oat\\r\\n\"", "\"oat\\r\\n\"",
|
||||
"\"\\fpan\\b\"", "\"\\fpan\\b\"",
|
||||
"{}", "{}",
|
||||
"[]", "[]",
|
||||
"[]", "[/*empty*/]",
|
||||
@@ -89,19 +97,20 @@ static const char *azJsonAtoms[] = {
|
||||
"\"day\"", "\"day\"",
|
||||
"\"end\"", "'end'",
|
||||
"\"fly\"", "\"fly\"",
|
||||
"\"\\u00XX\\u00XX\"", "\"\\xXX\\xXX\"",
|
||||
"\"y\\uXXXXz\"", "\"y\\uXXXXz\"",
|
||||
"\"\"", "\"\"",
|
||||
};
|
||||
static const char *azJsonTemplate[] = {
|
||||
static char *azJsonTemplate[] = {
|
||||
/* JSON JSON-5 */
|
||||
"{\"a\":%,\"b\":%,\"c\":%}", "{a:%,b:%,c:%}",
|
||||
"{\"a\":%,\"b\":%,\"cDD\":%}", "{a:%,b:%,cDD:%}",
|
||||
"{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"e\":%}", "{a:%,b:%,c:%,d:%,e:%}",
|
||||
"{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}", "{a:%,b:%,c:%,d:%,\"\":%}",
|
||||
"{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}", "{a:%,b:%,c:%,d:%,'':%}",
|
||||
"{\"d\":%}", "{d:%}",
|
||||
"{\"eeee\":%, \"ffff\":%}", "{eeee:% /*and*/, ffff:%}",
|
||||
"{\"$g\":%,\"_h_\":%}", "{$g:%,_h_:%,}",
|
||||
"{\"$g\":%,\"_h_\":%,\"a b c d\":%}", "{$g:%,_h_:%,\"a b c d\":%}",
|
||||
"{\"x\":%,\n \"y\":%}", "{\"x\":%,\n \"y\":%}",
|
||||
"{\"a b c d\":%,\"e\":%,\"f\":%,\"x\":%,\"y\":%}",
|
||||
"{\"a b c d\":%,e:%,f:%,x:%,y:%}",
|
||||
"{\"\\u00XX\":%,\"\\uXXXX\":%}", "{\"\\xXX\":%,\"\\uXXXX\":%}",
|
||||
"{\"Z\":%}", "{Z:%,}",
|
||||
"[%]", "[%,]",
|
||||
"[%,%]", "[%,%]",
|
||||
@@ -122,15 +131,13 @@ static void jsonExpand(
|
||||
unsigned int r /* Growth probability 0..1000. 0 means no growth */
|
||||
){
|
||||
unsigned int i, j, k;
|
||||
const char *z;
|
||||
char *z;
|
||||
char *zX;
|
||||
size_t n;
|
||||
char zBuf[200];
|
||||
|
||||
j = 0;
|
||||
if( zSrc==0 ){
|
||||
k = prngInt(p)%(count(azJsonTemplate)/2);
|
||||
k = k*2 + eType;
|
||||
zSrc = azJsonTemplate[k];
|
||||
}
|
||||
if( zSrc==0 ) zSrc = "%";
|
||||
if( strlen(zSrc)>=STRSZ/10 ) r = 0;
|
||||
for(i=0; zSrc[i]; i++){
|
||||
if( zSrc[i]!='%' ){
|
||||
@@ -149,9 +156,36 @@ static void jsonExpand(
|
||||
z = azJsonTemplate[k];
|
||||
}
|
||||
n = strlen(z);
|
||||
if( (zX = strstr(z,"XX"))!=0 ){
|
||||
unsigned int y = prngInt(p);
|
||||
if( (y&0xff)==((y>>8)&0xff) ) y += 0x100;
|
||||
while( (y&0xff)==((y>>16)&0xff) || ((y>>8)&0xff)==((y>>16)&0xff) ){
|
||||
y += 0x10000;
|
||||
}
|
||||
memcpy(zBuf, z, n+1);
|
||||
z = zBuf;
|
||||
zX = strstr(z,"XX");
|
||||
while( zX!=0 ){
|
||||
zX[0] = "0123456789abcdef"[y%16]; y /= 16;
|
||||
zX[1] = "0123456789abcdef"[y%16]; y /= 16;
|
||||
zX = strstr(zX, "XX");
|
||||
}
|
||||
}else if( (zX = strstr(z,"DD"))!=0 ){
|
||||
unsigned int y = prngInt(p);
|
||||
memcpy(zBuf, z, n+1);
|
||||
z = zBuf;
|
||||
zX = strstr(z,"DD");
|
||||
while( zX!=0 ){
|
||||
zX[0] = "0123456789"[y%10]; y /= 10;
|
||||
zX[1] = "0123456789"[y%10]; y /= 10;
|
||||
zX = strstr(zX, "DD");
|
||||
}
|
||||
}
|
||||
assert( strstr(z, "XX")==0 );
|
||||
assert( strstr(z, "DD")==0 );
|
||||
if( j+n<STRSZ ){
|
||||
memcpy(&zDest[j], z, n);
|
||||
j += n;
|
||||
j += (int)n;
|
||||
}
|
||||
}
|
||||
zDest[STRSZ-1] = 0;
|
||||
@@ -178,7 +212,7 @@ static void randJsonFunc(
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_randomjson_init(
|
||||
sqlite3 *db,
|
||||
@@ -188,7 +222,11 @@ int sqlite3_randomjson_init(
|
||||
static int cOne = 1;
|
||||
static int cZero = 0;
|
||||
int rc = SQLITE_OK;
|
||||
#ifdef SQLITE_STATIC_RANDOMJSON
|
||||
(void)pApi; /* Unused parameter */
|
||||
#else
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#endif
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "random_json", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
|
||||
+16
-2
@@ -350,6 +350,20 @@ totype_atof_calc:
|
||||
return z>=zEnd && nDigits>0 && eValid && nonNum==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a floating point value to an integer. Or, if this cannot be
|
||||
** done in a way that avoids 'outside the range of representable values'
|
||||
** warnings from UBSAN, return 0.
|
||||
**
|
||||
** This function is a modified copy of internal SQLite function
|
||||
** sqlite3RealToI64().
|
||||
*/
|
||||
static sqlite3_int64 totypeDoubleToInt(double r){
|
||||
if( r<-9223372036854774784.0 ) return 0;
|
||||
if( r>+9223372036854774784.0 ) return 0;
|
||||
return (sqlite3_int64)r;
|
||||
}
|
||||
|
||||
/*
|
||||
** tointeger(X): If X is any value (integer, double, blob, or string) that
|
||||
** can be losslessly converted into an integer, then make the conversion and
|
||||
@@ -365,7 +379,7 @@ static void tointegerFunc(
|
||||
switch( sqlite3_value_type(argv[0]) ){
|
||||
case SQLITE_FLOAT: {
|
||||
double rVal = sqlite3_value_double(argv[0]);
|
||||
sqlite3_int64 iVal = (sqlite3_int64)rVal;
|
||||
sqlite3_int64 iVal = totypeDoubleToInt(rVal);
|
||||
if( rVal==(double)iVal ){
|
||||
sqlite3_result_int64(context, iVal);
|
||||
}
|
||||
@@ -440,7 +454,7 @@ static void torealFunc(
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_int64 iVal = sqlite3_value_int64(argv[0]);
|
||||
double rVal = (double)iVal;
|
||||
if( iVal==(sqlite3_int64)rVal ){
|
||||
if( iVal==totypeDoubleToInt(rVal) ){
|
||||
sqlite3_result_double(context, rVal);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -582,6 +582,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
|
||||
bNextPage = 1;
|
||||
}else{
|
||||
iOff += dbdataGetVarintU32(&pCsr->aPage[iOff], &nPayload);
|
||||
if( nPayload>0x7fffff00 ) nPayload &= 0x3fff;
|
||||
}
|
||||
|
||||
/* If this is a leaf intkey cell, load the rowid */
|
||||
|
||||
+10
-11
@@ -717,7 +717,7 @@ static int nodeAcquire(
|
||||
** increase its reference count and return it.
|
||||
*/
|
||||
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
|
||||
if( pParent && pParent!=pNode->pParent ){
|
||||
if( pParent && ALWAYS(pParent!=pNode->pParent) ){
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
@@ -3452,7 +3452,7 @@ static int rtreeSqlInit(
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
if( pRtree->nAux ){
|
||||
if( pRtree->nAux && rc!=SQLITE_NOMEM ){
|
||||
pRtree->zReadAuxSql = sqlite3_mprintf(
|
||||
"SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
|
||||
zDb, zPrefix);
|
||||
@@ -4141,15 +4141,13 @@ static int rtreeCheckTable(
|
||||
check.zTab = zTab;
|
||||
|
||||
/* Find the number of auxiliary columns */
|
||||
if( check.rc==SQLITE_OK ){
|
||||
pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
|
||||
if( pStmt ){
|
||||
nAux = sqlite3_column_count(pStmt) - 2;
|
||||
sqlite3_finalize(pStmt);
|
||||
}else
|
||||
if( check.rc!=SQLITE_NOMEM ){
|
||||
check.rc = SQLITE_OK;
|
||||
}
|
||||
pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
|
||||
if( pStmt ){
|
||||
nAux = sqlite3_column_count(pStmt) - 2;
|
||||
sqlite3_finalize(pStmt);
|
||||
}else
|
||||
if( check.rc!=SQLITE_NOMEM ){
|
||||
check.rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Find number of dimensions in the rtree table. */
|
||||
@@ -4204,6 +4202,7 @@ static int rtreeIntegrity(
|
||||
if( rc==SQLITE_OK && *pzErr ){
|
||||
*pzErr = sqlite3_mprintf("In RTree %s.%s:\n%z",
|
||||
pRtree->zDb, pRtree->zName, *pzErr);
|
||||
if( (*pzErr)==0 ) rc = SQLITE_NOMEM;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+141
-46
@@ -42,7 +42,10 @@
|
||||
# 1) Consolidate the code generation for sqlite3*.*js into a script
|
||||
# which generates the makefile code, rather than using $(call) and
|
||||
# $(eval), or at least centralize the setup of the numerous vars
|
||||
# related to each build variant $(JS_BUILD_MODES).
|
||||
# related to each build variant $(JS_BUILD_MODES). (Update: an
|
||||
# external script was attempted but generating properly-escaped
|
||||
# makefile code from within a shell script is even less legible
|
||||
# than the $(eval) indirection going on in this file.)
|
||||
#
|
||||
default: all
|
||||
#default: quick
|
||||
@@ -51,9 +54,39 @@ MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
CLEAN_FILES :=
|
||||
DISTCLEAN_FILES := ./--dummy--
|
||||
release: oz
|
||||
# JS_BUILD_MODES exists solely to reduce repetition in documentation
|
||||
# below.
|
||||
|
||||
########################################################################
|
||||
# JS_BUILD_NAMES exists for documentation purposes only. It enumerates
|
||||
# the core build styles:
|
||||
#
|
||||
# - sqlite3 = canonical library build
|
||||
#
|
||||
# - sqlite3-wasmfs = WASMFS-capable library build
|
||||
#
|
||||
JS_BUILD_NAMES := sqlite3 sqlite3-wasmfs
|
||||
|
||||
########################################################################
|
||||
# JS_BUILD_MODES exists for documentation purposes only. It enumerates
|
||||
# the various "flavors" of build, each of which requires slight
|
||||
# customization of the output:
|
||||
#
|
||||
# - vanilla = plain-vanilla JS for use in browsers. This is the
|
||||
# canonical build mode.
|
||||
#
|
||||
# - esm = ES6 module, a.k.a. ESM, for use in browsers.
|
||||
#
|
||||
# - bundler-friendly = esm slightly tweaked for "bundler"
|
||||
# tools. Bundlers are invariably based on node.js, so these builds
|
||||
# are intended to be read at build-time by node.js but with a final
|
||||
# target of browsers.
|
||||
#
|
||||
# - node = for use by node.js for node.js, as opposed to by node.js on
|
||||
# behalf o browser-side code (use bundler-friendly for that). Note
|
||||
# that persistent storage (OPFS) is not available in these builds.
|
||||
#
|
||||
JS_BUILD_MODES := vanilla esm bunder-friendly node
|
||||
|
||||
########################################################################
|
||||
# Emscripten SDK home dir and related binaries...
|
||||
EMSDK_HOME ?= $(word 1,$(wildcard $(HOME)/emsdk $(HOME)/src/emsdk))
|
||||
emcc.bin ?= $(word 1,$(wildcard $(EMSDK_HOME)/upstream/emscripten/emcc) $(shell which emcc))
|
||||
@@ -93,11 +126,14 @@ else
|
||||
maybe-wasm-strip = $(wasm-strip)
|
||||
endif
|
||||
|
||||
########################################################################
|
||||
# dir.top = the top dir of the canonical build tree, where
|
||||
# sqlite3.[ch] live.
|
||||
dir.top := ../..
|
||||
# Reminder: some Emscripten flags require absolute paths but we want
|
||||
# relative paths for most stuff simply to reduce noise. The
|
||||
# $(abspath...) GNU make function can transform relative paths to
|
||||
# absolute.
|
||||
# Maintenance reminder: some Emscripten flags require absolute paths
|
||||
# but we want relative paths for most stuff simply to reduce
|
||||
# noise. The $(abspath...) GNU make function can transform relative
|
||||
# paths to absolute.
|
||||
dir.wasm := $(patsubst %/,%,$(dir $(MAKEFILE)))
|
||||
dir.api := api
|
||||
dir.jacc := jaccwabyt
|
||||
@@ -143,12 +179,14 @@ endif
|
||||
# Set up sqlite3.c and sqlite3.h...
|
||||
#
|
||||
# To build with SEE (https://sqlite.org/see), either put sqlite3-see.c
|
||||
# in the top of this build tree or pass
|
||||
# sqlite3.c=PATH_TO_sqlite3-see.c to the build. Note that only
|
||||
# encryption modules with no 3rd-party dependencies will currently
|
||||
# work here: AES256-OFB, AES128-OFB, and AES128-CCM. Not
|
||||
# coincidentally, those 3 modules are included in the sqlite3-see.c
|
||||
# bundle.
|
||||
# in $(dir.top) or pass sqlite3.c=PATH_TO_sqlite3-see.c to the $(MAKE)
|
||||
# invocation. Note that only encryption modules with no 3rd-party
|
||||
# dependencies will currently work here: AES256-OFB, AES128-OFB, and
|
||||
# AES128-CCM. Not coincidentally, those 3 modules are included in the
|
||||
# sqlite3-see.c bundle. Note, however, that distributing an SEE build
|
||||
# of the WASM on a public site is in violation of the SEE license
|
||||
# because it effectively provides a usable copy of the SEE build to
|
||||
# all visitors.
|
||||
#
|
||||
# A custom sqlite3.c must not have any spaces in its name.
|
||||
# $(sqlite3.canonical.c) must point to the sqlite3.c in
|
||||
@@ -193,6 +231,10 @@ SQLITE_OPT = \
|
||||
# can be used to find errant uses of sqlite3_js_vfs_create_file()
|
||||
# in client code.
|
||||
|
||||
########################################################################@
|
||||
# It's important that sqlite3.h 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.
|
||||
.NOTPARALLEL: $(sqlite3.h)
|
||||
$(sqlite3.h):
|
||||
$(MAKE) -C $(dir.top) sqlite3.c
|
||||
@@ -242,6 +284,7 @@ ifneq (,$(sqlite3_wasm_extra_init.c))
|
||||
cflags.wasm_extra_init := -DSQLITE_WASM_EXTRA_INIT
|
||||
endif
|
||||
|
||||
#########################################################################
|
||||
# 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
|
||||
@@ -251,11 +294,12 @@ 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
|
||||
|
||||
#########################################################################
|
||||
# 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
|
||||
# blocks, which contain the license header and version info.
|
||||
# block(s), which contain the license header and version info.
|
||||
bin.stripccomments := $(dir.tool)/stripccomments
|
||||
$(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
|
||||
$(CC) -o $@ $<
|
||||
@@ -287,6 +331,9 @@ DISTCLEAN_FILES += $(bin.stripccomments)
|
||||
# c-pp.c was written specifically for the sqlite project's JavaScript
|
||||
# builds but is maintained as a standalone project:
|
||||
# https://fossil.wanderinghorse.net/r/c-pp
|
||||
#
|
||||
# Note that the SQLITE_... build flags used here have NO EFFECT on the
|
||||
# JS/WASM build. They are solely for use with $(bin.c-pp) itself.
|
||||
bin.c-pp := ./c-pp
|
||||
$(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
|
||||
$(CC) -O0 -o $@ c-pp.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top) \
|
||||
@@ -347,6 +394,7 @@ emcc_opt_full := $(emcc_opt) -g3
|
||||
# -Oz when small deliverable size is a priority.
|
||||
########################################################################
|
||||
|
||||
########################################################################
|
||||
# EXPORTED_FUNCTIONS.* = files for use with Emscripten's
|
||||
# -sEXPORTED_FUNCTION flag.
|
||||
EXPORTED_FUNCTIONS.api.main := $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api)
|
||||
@@ -358,6 +406,7 @@ EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api
|
||||
$(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE)
|
||||
cat $(EXPORTED_FUNCTIONS.api.in) > $@
|
||||
|
||||
########################################################################
|
||||
# sqlite3-license-version.js = generated JS file with the license
|
||||
# header and version info.
|
||||
sqlite3-license-version.js := $(dir.tmp)/sqlite3-license-version.js
|
||||
@@ -370,20 +419,37 @@ sqlite3-api-build-version.js := $(dir.tmp)/sqlite3-api-build-version.js
|
||||
# sqlite3-api.jses = the list of JS files which make up
|
||||
# $(sqlite3-api.js.in), in the order they need to be assembled.
|
||||
sqlite3-api.jses := $(sqlite3-license-version.js)
|
||||
# sqlite3-api-prologue.js: initial boostrapping bits:
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-prologue.js
|
||||
# whwhasm.js and jaccwabyt.js: Low-level utils, mostly replacing
|
||||
# Emscripten glue:
|
||||
sqlite3-api.jses += $(dir.common)/whwasmutil.js
|
||||
sqlite3-api.jses += $(dir.jacc)/jaccwabyt.js
|
||||
# sqlite3-api-glue.js Glues the previous part together:
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-glue.js
|
||||
# $(sqlite3-api-build-version.js) = library version info
|
||||
sqlite3-api.jses += $(sqlite3-api-build-version.js)
|
||||
# sqlite3-api-oo1.js = the oo1 API:
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.js
|
||||
# sqlite3-api-worker.js = the Worker1 API:
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-v-helper.js
|
||||
# sqlite3-vfs-helper = helper APIs for VFSes:
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.c-pp.js
|
||||
# sqlite3-vtab-helper = helper APIs for VTABLEs:
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vtab-helper.c-pp.js
|
||||
# sqlite3-vfs-opfs.c-pp.js = the first OPFS VFS:
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
|
||||
# sqlite3-vfs-opfs-sahpool.c-pp.js = the second OPFS VFS:
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
|
||||
# sqlite3-api-cleanup.js = "finalizes" the build and cleans up
|
||||
# any extraneous global symbols which are needed temporarily
|
||||
# by the previous files.
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
|
||||
|
||||
########################################################################
|
||||
# SOAP.js is an external API file which is part of our distribution
|
||||
# but not part of the sqlite3-api.js amalgamation.
|
||||
# but not part of the sqlite3-api.js amalgamation. It's a component of
|
||||
# the first OPFS VFS and necessarily an external file.
|
||||
SOAP.js := $(dir.api)/sqlite3-opfs-async-proxy.js
|
||||
SOAP.js.bld := $(dir.dout)/$(notdir $(SOAP.js))
|
||||
sqlite3-api.ext.jses += $(SOAP.js.bld)
|
||||
@@ -438,7 +504,9 @@ endif
|
||||
# emcc flags for .c/.o.
|
||||
emcc.cflags :=
|
||||
emcc.cflags += -std=c99 -fPIC
|
||||
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c).
|
||||
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c), primarily
|
||||
# for variadic macros and snprintf() to implement
|
||||
# sqlite3_wasm_enum_json().
|
||||
emcc.cflags += -I. -I$(dir.top)
|
||||
########################################################################
|
||||
# emcc flags specific to building .js/.wasm files...
|
||||
@@ -459,14 +527,16 @@ emcc.jsflags += -sIMPORTED_MEMORY
|
||||
emcc.jsflags += -sSTRICT_JS=0
|
||||
# STRICT_JS disabled due to:
|
||||
# https://github.com/emscripten-core/emscripten/issues/18610
|
||||
# TL;DR: does not work with MODULARIZE or EXPORT_ES6 as of version 3.1.31.
|
||||
# TL;DR: does not work with MODULARIZE or EXPORT_ES6 as of version
|
||||
# 3.1.31. The fix for that in newer emcc's is to throw a built-time
|
||||
# error if STRICT_JS is used together with those options.
|
||||
|
||||
# -sENVIRONMENT values for the various build modes:
|
||||
emcc.environment.vanilla := web,worker
|
||||
emcc.environment.bundler-friendly := $(emcc.environment.vanilla)
|
||||
emcc.environment.esm := $(emcc.environment.vanilla)
|
||||
emcc.environment.node := node
|
||||
# Note that adding "node" to the list for the other builds causes
|
||||
# Note that adding ",node" to the list for the other builds causes
|
||||
# Emscripten to generate code which confuses node: it cannot reliably
|
||||
# determine whether the build is for a browser or for node.
|
||||
|
||||
@@ -518,13 +588,14 @@ emcc.jsflags += -sSTACK_SIZE=512KB
|
||||
# extern-post-js.js. However... using a temporary symbol name here
|
||||
# and then adding sqlite3InitModule() ourselves results in 2 global
|
||||
# symbols: we cannot "delete" the Emscripten-defined
|
||||
# $(sqlite3.js.init-func) because it's declared with "var".
|
||||
# $(sqlite3.js.init-func) from vanilla builds (as opposed to ESM
|
||||
# builds) because it's declared with "var".
|
||||
sqlite3.js.init-func := sqlite3InitModule
|
||||
emcc.jsflags += -sEXPORT_NAME=$(sqlite3.js.init-func)
|
||||
emcc.jsflags += -sGLOBAL_BASE=4096 # HYPOTHETICALLY keep func table indexes from overlapping w/ heap addr.
|
||||
#emcc.jsflags += -sSTRICT # fails due to missing __syscall_...()
|
||||
#emcc.jsflags += -sALLOW_UNIMPLEMENTED_SYSCALLS
|
||||
#emcc.jsflags += -sFILESYSTEM=0 # only for experimentation. sqlite3 needs the FS API
|
||||
#emcc.jsflags += -sFILESYSTEM=0 # only for experimentation. fiddle needs the FS API
|
||||
#emcc.jsflags += -sABORTING_MALLOC # only for experimentation
|
||||
emcc.jsflags += -sALLOW_TABLE_GROWTH
|
||||
# ^^^^ -sALLOW_TABLE_GROWTH is required for installing new SQL UDFs
|
||||
@@ -568,15 +639,25 @@ emcc.jsflags += -sLLD_REPORT_UNDEFINED
|
||||
# -g3 debugging info, _huge_.
|
||||
########################################################################
|
||||
|
||||
########################################################################
|
||||
# $(sqlite3-api-build-version.js) injects the build version info into
|
||||
# the bundle in JSON form.
|
||||
$(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE)
|
||||
@echo "Making $@..."
|
||||
@{ \
|
||||
echo 'globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \
|
||||
echo -n ' sqlite3.version = '; \
|
||||
$(bin.version-info) --json; \
|
||||
echo ';'; \
|
||||
echo '});'; \
|
||||
echo 'globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \
|
||||
echo -n ' sqlite3.version = '; \
|
||||
$(bin.version-info) --json; \
|
||||
echo ';'; \
|
||||
echo '});'; \
|
||||
} > $@
|
||||
|
||||
########################################################################
|
||||
# $(sqlite3-license-version.js) contains the license header and
|
||||
# in-comment build version info.
|
||||
#
|
||||
# Maintenance reminder: there are awk binaries out there which do not
|
||||
# support -e SCRIPT.
|
||||
$(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js) \
|
||||
$(MAKEFILE)
|
||||
@echo "Making $@..."; { \
|
||||
@@ -584,8 +665,8 @@ $(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js)
|
||||
echo '/*'; \
|
||||
echo '** This code was built from sqlite3 version...'; \
|
||||
echo "**"; \
|
||||
awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \
|
||||
-e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
awk '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
awk '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
echo "**"; \
|
||||
echo "** Using the Emscripten SDK version $(emcc.version)."; \
|
||||
echo '*/'; \
|
||||
@@ -594,7 +675,11 @@ $(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js)
|
||||
########################################################################
|
||||
# --post-js and --pre-js are emcc flags we use to append/prepend JS to
|
||||
# the generated emscripten module file. These rules set up the core
|
||||
# pre/post files for use by the various builds.
|
||||
# pre/post files for use by the various builds. --pre-js is used to
|
||||
# inject code which needs to run as part of the pre-WASM-load phase.
|
||||
# --post-js injects code which runs after the WASM module is loaded
|
||||
# and includes the entirety of the library plus some
|
||||
# Emscripten-specific post-bootstrapping code.
|
||||
pre-js.js.in := $(dir.api)/pre-js.c-pp.js
|
||||
post-js.js.in := $(dir.tmp)/post-js.c-pp.js
|
||||
post-jses.js := \
|
||||
@@ -612,18 +697,26 @@ $(post-js.js.in): $(post-jses.js) $(MAKEFILE)
|
||||
|
||||
########################################################################
|
||||
# call-make-pre-post is a $(call)able which creates rules for
|
||||
# pre-js-$(1)-$(2).js. $1 = the base name of the JS file on whose
|
||||
# behalf this pre-js is for (one of: sqlite3, sqlite3-wasmfs). $2 is
|
||||
# pre-js.$(1)-$(2).js. $1 = the base name of the JS file on whose
|
||||
# behalf this pre-js is for (one of: $(JS_BUILD_NAMES)). $2 is
|
||||
# the build mode: one of $(JS_BUILD_MODES). This sets up
|
||||
# --[extern-][pre/post]-js flags in $(pre-post-$(1)-$(2).flags) and
|
||||
# dependencies in $(pre-post-$(1)-$(2).deps). The resulting files get
|
||||
# filtered using $(C-PP.FILTER). Any flags necessary for such
|
||||
# filtering need to be set in $(c-pp.D.$(1)-$(2)) before $(call)ing
|
||||
# this.
|
||||
#
|
||||
# Maintenance note: a shell script was written to generate these rules
|
||||
# with the hope that it would make them more legible and maintainable,
|
||||
# but embedding makefile code in another language makes it even less
|
||||
# legible than having the level of $(eval) indirection which we have
|
||||
# here.
|
||||
define call-make-pre-post
|
||||
pre-post-$(1)-$(2).flags ?=
|
||||
pre-js.js.$(1)-$(2) := $$(dir.tmp)/pre-js.$(1)-$(2).intermediary.js
|
||||
$$(eval $$(call C-PP.FILTER,$$(pre-js.js.in),$$(pre-js.js.$(1)-$(2)),$$(c-pp.D.$(1)-$(2))))
|
||||
pre-js.js.$(1)-$(2).intermediary := $$(dir.tmp)/pre-js.$(1)-$(2).intermediary.js
|
||||
pre-js.js.$(1)-$(2) := $$(dir.tmp)/pre-js.$(1)-$(2).js
|
||||
#$$(error $$(pre-js.js.$(1)-$(2).intermediary) $$(pre-js.js.$(1)-$(2)))
|
||||
$$(eval $$(call C-PP.FILTER,$$(pre-js.js.in),$$(pre-js.js.$(1)-$(2).intermediary),$$(c-pp.D.$(1)-$(2))))
|
||||
post-js.js.$(1)-$(2) := $$(dir.tmp)/post-js.$(1)-$(2).js
|
||||
$$(eval $$(call C-PP.FILTER,$$(post-js.js.in),$$(post-js.js.$(1)-$(2)),$$(c-pp.D.$(1)-$(2))))
|
||||
extern-post-js.js.$(1)-$(2) := $$(dir.tmp)/extern-post-js.$(1)-$(2).js
|
||||
@@ -634,8 +727,8 @@ pre-post-common.flags.$(1)-$(2) := \
|
||||
--extern-post-js=$$(extern-post-js.js.$(1)-$(2))
|
||||
pre-post-jses.$(1)-$(2).deps := $$(pre-post-jses.deps.common) \
|
||||
$$(post-js.js.$(1)-$(2)) $$(extern-post-js.js.$(1)-$(2))
|
||||
$$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(1)-$(2)) $$(MAKEFILE)
|
||||
cp $$(pre-js.js.$(1)-$(2)) $$@
|
||||
$$(pre-js.js.$(1)-$(2)): $$(pre-js.js.$(1)-$(2).intermediary) $$(MAKEFILE)
|
||||
cp $$(pre-js.js.$(1)-$(2).intermediary) $$@
|
||||
@if [ sqlite3-wasmfs = $(1) ]; then \
|
||||
echo "delete Module[xNameOfInstantiateWasm] /*for WASMFS build*/;"; \
|
||||
elif [ sqlite3 != $(1) ]; then \
|
||||
@@ -643,10 +736,10 @@ $$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(1)-$(2)) $$(MAKEFILE)
|
||||
fi >> $$@
|
||||
pre-post-$(1)-$(2).deps := \
|
||||
$$(pre-post-jses.$(1)-$(2).deps) \
|
||||
$$(dir.tmp)/pre-js-$(1)-$(2).js
|
||||
$$(dir.tmp)/pre-js.$(1)-$(2).js
|
||||
pre-post-$(1)-$(2).flags += \
|
||||
$$(pre-post-common.flags.$(1)-$(2)) \
|
||||
--pre-js=$$(dir.tmp)/pre-js-$(1)-$(2).js
|
||||
--pre-js=$$(dir.tmp)/pre-js.$(1)-$(2).js
|
||||
endef
|
||||
# /post-js and pre-js
|
||||
########################################################################
|
||||
@@ -683,8 +776,8 @@ sqlite3-wasmfs.cfiles := $(sqlite3-wasm.cfiles)
|
||||
# Upstream RFE:
|
||||
# https://github.com/emscripten-core/emscripten/issues/18237
|
||||
#
|
||||
# Maintenance reminder: Mac sed works differently than GNU sed, so
|
||||
# don't use sed for this.
|
||||
# Maintenance reminder: Mac sed works differently than GNU sed, so we
|
||||
# use awk instead of sed for this.
|
||||
define SQLITE3.xJS.ESM-EXPORT-DEFAULT
|
||||
if [ x1 = x$(1) ]; then \
|
||||
echo "Fragile workaround for emscripten/issues/18237. See SQLITE3.xJS.RECIPE."; \
|
||||
@@ -700,6 +793,7 @@ if [ x1 = x$(1) ]; then \
|
||||
fi
|
||||
endef
|
||||
|
||||
########################################################################
|
||||
# extern-post-js* and extern-pre-js* are files for use with
|
||||
# Emscripten's --extern-pre-js and --extern-post-js flags.
|
||||
extern-pre-js.js := $(dir.api)/extern-pre-js.js
|
||||
@@ -711,11 +805,12 @@ pre-post-common.flags := \
|
||||
# pre-post-jses.deps.* = a list of dependencies for the
|
||||
# --[extern-][pre/post]-js files.
|
||||
pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)
|
||||
|
||||
########################################################################
|
||||
# SETUP_LIB_BUILD_MODE is a $(call)'able which sets up numerous pieces
|
||||
# for one of the build modes.
|
||||
#
|
||||
# $1 = one of: sqlite3, sqlite3-wasmfs
|
||||
# $1 = one of: $(JS_BUILD_NAMES)
|
||||
# $2 = build mode name: one of $(JS_BUILD_MODES)
|
||||
# $3 = 1 for ESM build mode, else 0
|
||||
# $4 = resulting sqlite-api JS/MJS file
|
||||
@@ -726,7 +821,8 @@ pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)
|
||||
# Maintenance reminder: be careful not to introduce spaces around args
|
||||
# ($1, $2), otherwise string concatenation will malfunction.
|
||||
#
|
||||
# emcc.environment.$(2) must be set to a value for the -sENVIRONMENT flag.
|
||||
# emcc.environment.$(2) must be set to a value for emcc's
|
||||
# -sENVIRONMENT flag.
|
||||
#
|
||||
# $(cflags.$(1)) and $(cflags.$(1).$(2)) may be defined to append
|
||||
# CFLAGS to a given build mode.
|
||||
@@ -781,8 +877,7 @@ sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs
|
||||
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,vanilla,0,\
|
||||
$(sqlite3-api.js), $(sqlite3.js)))
|
||||
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,esm,1,\
|
||||
$(sqlite3-api.mjs), $(sqlite3.mjs), \
|
||||
-Dtarget=es6-module, -sEXPORT_ES6 -sUSE_ES6_IMPORT_META))
|
||||
$(sqlite3-api.mjs), $(sqlite3.mjs), -Dtarget=es6-module))
|
||||
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,bundler-friendly,1,\
|
||||
$(sqlite3-api-bundler-friendly.mjs),$(sqlite3-bundler-friendly.mjs),\
|
||||
$(c-pp.D.sqlite3-esm) -Dtarget=es6-bundler-friendly))
|
||||
@@ -798,7 +893,7 @@ $(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,node,1,\
|
||||
# -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 references
|
||||
# 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.
|
||||
#
|
||||
@@ -854,7 +949,7 @@ dir.sql := sql
|
||||
speedtest1 := ../../speedtest1
|
||||
speedtest1.c := ../../test/speedtest1.c
|
||||
speedtest1.sql := $(dir.sql)/speedtest1.sql
|
||||
speedtest1.cliflags := --size 25 --big-transactions
|
||||
speedtest1.cliflags := --size 10 --big-transactions
|
||||
$(speedtest1):
|
||||
$(MAKE) -C ../.. speedtest1
|
||||
$(speedtest1.sql): $(speedtest1) $(MAKEFILE)
|
||||
@@ -1087,4 +1182,4 @@ endif
|
||||
|
||||
# Run local web server for the test/demo pages.
|
||||
httpd:
|
||||
althttpd -max-age 1 -enable-sab -page index.html
|
||||
althttpd -max-age 1 -enable-sab 1 -page index.html
|
||||
|
||||
@@ -78,10 +78,12 @@ browser client:
|
||||
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-v-helper.js`**\
|
||||
Installs `sqlite3.vfs` and `sqlite3.vtab`, namespaces which contain
|
||||
helpers for use by downstream code which creates `sqlite3_vfs`
|
||||
and `sqlite3_module` implementations.
|
||||
- **`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`**\
|
||||
Installs the `sqlite3.vtab` namespace, which contain helpers for use
|
||||
by downstream code which creates `sqlite3_module` implementations.
|
||||
- **`sqlite3-vfs-opfs.c-pp.js`**\
|
||||
is an sqlite3 VFS implementation which supports the Origin-Private
|
||||
FileSystem (OPFS) as a storage layer to provide persistent storage
|
||||
|
||||
@@ -19,8 +19,10 @@ Module.postRun.push(function(Module/*the Emscripten-style module object*/){
|
||||
- sqlite3-api-glue.js => glues previous parts together
|
||||
- sqlite3-api-oo.js => SQLite3 OO API #1
|
||||
- sqlite3-api-worker1.js => Worker-based API
|
||||
- sqlite3-vfs-helper.js => Internal-use utilities for...
|
||||
- sqlite3-vfs-opfs.js => OPFS VFS
|
||||
- sqlite3-vfs-helper.c-pp.js => Utilities for VFS impls
|
||||
- sqlite3-vtab-helper.c-pp.js => Utilities for virtual table impls
|
||||
- sqlite3-vfs-opfs.c-pp.js => OPFS VFS
|
||||
- sqlite3-vfs-opfs-sahpool.c-pp.js => OPFS SAHPool VFS
|
||||
- sqlite3-api-cleanup.js => final API cleanup
|
||||
- post-js-footer.js => closes this postRun() function
|
||||
*/
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
previous steps of the sqlite3-api.js bootstrapping process:
|
||||
sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It
|
||||
initializes the main API pieces so that the downstream components
|
||||
(e.g. sqlite3-api-oo1.js) have all that they need.
|
||||
(e.g. sqlite3-api-oo1.js) have all of the infrastructure that they
|
||||
need.
|
||||
*/
|
||||
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
'use strict';
|
||||
@@ -329,6 +330,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
|
||||
if(wasm.exports.sqlite3_activate_see instanceof Function){
|
||||
/**
|
||||
This code is capable of using an SEE build but note that an SEE
|
||||
WASM build is generally incompatible with SEE's license
|
||||
conditions. It is permitted for use internally in organizations
|
||||
which have licensed SEE, but not for public sites because
|
||||
exposing an SEE build of sqlite3.wasm effectively provides all
|
||||
clients with a working copy of the commercial SEE code.
|
||||
*/
|
||||
wasm.bindingSignatures.push(
|
||||
["sqlite3_key", "int", "sqlite3*", "string", "int"],
|
||||
["sqlite3_key_v2","int","sqlite3*","string","*","int"],
|
||||
@@ -341,6 +350,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
Functions which require BigInt (int64) support are separated from
|
||||
the others because we need to conditionally bind them or apply
|
||||
dummy impls, depending on the capabilities of the environment.
|
||||
(That said: we never actually build without BigInt support,
|
||||
and such builds are untested.)
|
||||
|
||||
Note that not all of these functions directly require int64
|
||||
but are only for use with APIs which require int64. For example,
|
||||
@@ -359,7 +370,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
/* Careful! Short version: de/serialize() are problematic because they
|
||||
might use a different allocator than the user for managing the
|
||||
deserialized block. de/serialize() are ONLY safe to use with
|
||||
sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */,
|
||||
sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. Because
|
||||
of this, the canonical builds of sqlite3.wasm/js guarantee that
|
||||
sqlite3.wasm.alloc() and friends use those allocators. Custom builds
|
||||
may not guarantee that, however. */,
|
||||
["sqlite3_drop_modules", "int", ["sqlite3*", "**"]],
|
||||
["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]],
|
||||
["sqlite3_malloc64", "*","i64"],
|
||||
@@ -422,8 +436,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
// Add session/changeset APIs...
|
||||
if(wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add){
|
||||
/* ACHTUNG: 2022-12-23: the session/changeset API bindings are
|
||||
COMPLETELY UNTESTED. */
|
||||
/**
|
||||
FuncPtrAdapter options for session-related callbacks with the
|
||||
native signature "i(ps)". This proxy converts the 2nd argument
|
||||
@@ -601,16 +613,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
/**
|
||||
Functions which are intended solely for API-internal use by the
|
||||
WASM components, not client code. These get installed into
|
||||
sqlite3.wasm. Some of them get exposed to clients via variants
|
||||
named sqlite3_js_...().
|
||||
sqlite3.util. Some of them get exposed to clients via variants
|
||||
in sqlite3_js_...().
|
||||
|
||||
2024-01-11: these were renamed, with two underscores in the
|
||||
prefix, to ensure that clients do not accidentally depend on
|
||||
them. They have always been documented as internal-use-only, so
|
||||
no clients "should" be depending on the old names.
|
||||
*/
|
||||
wasm.bindingSignatures.wasm = [
|
||||
["sqlite3_wasm_db_reset", "int", "sqlite3*"],
|
||||
["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
|
||||
["sqlite3_wasm_vfs_create_file", "int",
|
||||
wasm.bindingSignatures.wasmInternal = [
|
||||
["sqlite3__wasm_db_reset", "int", "sqlite3*"],
|
||||
["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
|
||||
["sqlite3__wasm_vfs_create_file", "int",
|
||||
"sqlite3_vfs*","string","*", "int"],
|
||||
["sqlite3_wasm_posix_create_file", "int", "string","*", "int"],
|
||||
["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
|
||||
["sqlite3__wasm_posix_create_file", "int", "string","*", "int"],
|
||||
["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -652,7 +669,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
Use case: sqlite3_bind_pointer() and sqlite3_result_pointer()
|
||||
call for "a static string and preferably a string
|
||||
literal". This converter is used to ensure that the string
|
||||
literal." This converter is used to ensure that the string
|
||||
value seen by those functions is long-lived and behaves as they
|
||||
need it to.
|
||||
*/
|
||||
@@ -674,14 +691,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
`sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
|
||||
*/
|
||||
const __xArgPtr = wasm.xWrap.argAdapter('*');
|
||||
const nilType = function(){}/*a class no value can ever be an instance of*/;
|
||||
const nilType = function(){
|
||||
/*a class which no value can ever be an instance of*/
|
||||
};
|
||||
wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)
|
||||
('sqlite3_context*', __xArgPtr)
|
||||
('sqlite3_value*', __xArgPtr)
|
||||
('void*', __xArgPtr)
|
||||
('sqlite3_changegroup*', __xArgPtr)
|
||||
('sqlite3_changeset_iter*', __xArgPtr)
|
||||
//('sqlite3_rebaser*', __xArgPtr)
|
||||
('sqlite3_session*', __xArgPtr)
|
||||
('sqlite3_stmt*', (v)=>
|
||||
__xArgPtr((v instanceof (sqlite3?.oo1?.Stmt || nilType))
|
||||
@@ -742,8 +760,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
for(const e of wasm.bindingSignatures){
|
||||
capi[e[0]] = wasm.xWrap.apply(null, e);
|
||||
}
|
||||
for(const e of wasm.bindingSignatures.wasm){
|
||||
wasm[e[0]] = wasm.xWrap.apply(null, e);
|
||||
for(const e of wasm.bindingSignatures.wasmInternal){
|
||||
util[e[0]] = wasm.xWrap.apply(null, e);
|
||||
}
|
||||
|
||||
/* For C API functions which cannot work properly unless
|
||||
@@ -765,9 +783,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
implicitly making it part of the public interface. */
|
||||
delete wasm.bindingSignatures;
|
||||
|
||||
if(wasm.exports.sqlite3_wasm_db_error){
|
||||
if(wasm.exports.sqlite3__wasm_db_error){
|
||||
const __db_err = wasm.xWrap(
|
||||
'sqlite3_wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
|
||||
'sqlite3__wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
|
||||
);
|
||||
/**
|
||||
Sets the given db's error state. Accepts:
|
||||
@@ -785,7 +803,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
Returns the resulting code. Pass (pDb,0,0) to clear the error
|
||||
state.
|
||||
*/
|
||||
util.sqlite3_wasm_db_error = function(pDb, resultCode, message){
|
||||
util.sqlite3__wasm_db_error = function(pDb, resultCode, message){
|
||||
if(resultCode instanceof sqlite3.WasmAllocError){
|
||||
resultCode = capi.SQLITE_NOMEM;
|
||||
message = 0 /*avoid allocating message string*/;
|
||||
@@ -796,17 +814,17 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
return pDb ? __db_err(pDb, resultCode, message) : resultCode;
|
||||
};
|
||||
}else{
|
||||
util.sqlite3_wasm_db_error = function(pDb,errCode,msg){
|
||||
console.warn("sqlite3_wasm_db_error() is not exported.",arguments);
|
||||
util.sqlite3__wasm_db_error = function(pDb,errCode,msg){
|
||||
console.warn("sqlite3__wasm_db_error() is not exported.",arguments);
|
||||
return errCode;
|
||||
};
|
||||
}
|
||||
}/*xWrap() bindings*/
|
||||
|
||||
{/* Import C-level constants and structs... */
|
||||
const cJson = wasm.xCall('sqlite3_wasm_enum_json');
|
||||
const cJson = wasm.xCall('sqlite3__wasm_enum_json');
|
||||
if(!cJson){
|
||||
toss("Maintenance required: increase sqlite3_wasm_enum_json()'s",
|
||||
toss("Maintenance required: increase sqlite3__wasm_enum_json()'s",
|
||||
"static buffer size!");
|
||||
}
|
||||
//console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
|
||||
@@ -877,7 +895,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
delete capi[k];
|
||||
}
|
||||
capi.sqlite3_vtab_config = wasm.xWrap(
|
||||
'sqlite3_wasm_vtab_config','int',[
|
||||
'sqlite3__wasm_vtab_config','int',[
|
||||
'sqlite3*', 'int', 'int']
|
||||
);
|
||||
}/* end vtab-related setup */
|
||||
@@ -889,7 +907,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
consistency with non-special-case wrappings.
|
||||
*/
|
||||
const __dbArgcMismatch = (pDb,f,n)=>{
|
||||
return util.sqlite3_wasm_db_error(pDb, capi.SQLITE_MISUSE,
|
||||
return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE,
|
||||
f+"() requires "+n+" argument"+
|
||||
(1===n?"":'s')+".");
|
||||
};
|
||||
@@ -898,7 +916,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
argument and require SQLITE_UTF8. Sets the db error code to
|
||||
SQLITE_FORMAT and returns that code. */
|
||||
const __errEncoding = (pDb)=>{
|
||||
return util.sqlite3_wasm_db_error(
|
||||
return util.sqlite3__wasm_db_error(
|
||||
pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding."
|
||||
);
|
||||
};
|
||||
@@ -1128,7 +1146,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
return rc;
|
||||
}catch(e){
|
||||
return util.sqlite3_wasm_db_error(pDb, e);
|
||||
return util.sqlite3__wasm_db_error(pDb, e);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1254,7 +1272,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
return rc;
|
||||
}catch(e){
|
||||
console.error("sqlite3_create_function_v2() setup threw:",e);
|
||||
return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
|
||||
return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1299,7 +1317,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
return rc;
|
||||
}catch(e){
|
||||
console.error("sqlite3_create_window_function() setup threw:",e);
|
||||
return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
|
||||
return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
|
||||
}
|
||||
};
|
||||
/**
|
||||
@@ -1394,7 +1412,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null);
|
||||
case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail);
|
||||
default:
|
||||
return util.sqlite3_wasm_db_error(
|
||||
return util.sqlite3__wasm_db_error(
|
||||
pDb, capi.SQLITE_MISUSE,
|
||||
"Invalid SQL argument type for sqlite3_prepare_v2/v3()."
|
||||
);
|
||||
@@ -1438,7 +1456,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}else if('string'===typeof text){
|
||||
[p, n] = wasm.allocCString(text);
|
||||
}else{
|
||||
return util.sqlite3_wasm_db_error(
|
||||
return util.sqlite3__wasm_db_error(
|
||||
capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
|
||||
"Invalid 3rd argument type for sqlite3_bind_text()."
|
||||
);
|
||||
@@ -1446,7 +1464,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
|
||||
}catch(e){
|
||||
wasm.dealloc(p);
|
||||
return util.sqlite3_wasm_db_error(
|
||||
return util.sqlite3__wasm_db_error(
|
||||
capi.sqlite3_db_handle(pStmt), e
|
||||
);
|
||||
}
|
||||
@@ -1472,7 +1490,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}else if('string'===typeof pMem){
|
||||
[p, n] = wasm.allocCString(pMem);
|
||||
}else{
|
||||
return util.sqlite3_wasm_db_error(
|
||||
return util.sqlite3__wasm_db_error(
|
||||
capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
|
||||
"Invalid 3rd argument type for sqlite3_bind_blob()."
|
||||
);
|
||||
@@ -1480,7 +1498,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
|
||||
}catch(e){
|
||||
wasm.dealloc(p);
|
||||
return util.sqlite3_wasm_db_error(
|
||||
return util.sqlite3__wasm_db_error(
|
||||
capi.sqlite3_db_handle(pStmt), e
|
||||
);
|
||||
}
|
||||
@@ -1504,11 +1522,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
case capi.SQLITE_CONFIG_SORTERREF_SIZE: // 28 /* int nByte */
|
||||
case capi.SQLITE_CONFIG_STMTJRNL_SPILL: // 26 /* int nByte */
|
||||
case capi.SQLITE_CONFIG_URI:// 17 /* int */
|
||||
return wasm.exports.sqlite3_wasm_config_i(op, args[0]);
|
||||
return wasm.exports.sqlite3__wasm_config_i(op, args[0]);
|
||||
case capi.SQLITE_CONFIG_LOOKASIDE: // 13 /* int int */
|
||||
return wasm.exports.sqlite3_wasm_config_ii(op, args[0], args[1]);
|
||||
return wasm.exports.sqlite3__wasm_config_ii(op, args[0], args[1]);
|
||||
case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: // 29 /* sqlite3_int64 */
|
||||
return wasm.exports.sqlite3_wasm_config_j(op, args[0]);
|
||||
return wasm.exports.sqlite3__wasm_config_j(op, args[0]);
|
||||
case capi.SQLITE_CONFIG_GETMALLOC: // 5 /* sqlite3_mem_methods* */
|
||||
case capi.SQLITE_CONFIG_GETMUTEX: // 11 /* sqlite3_mutex_methods* */
|
||||
case capi.SQLITE_CONFIG_GETPCACHE2: // 19 /* sqlite3_pcache_methods2* */
|
||||
@@ -1574,11 +1592,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
if( pKvvfs ){/* kvvfs-specific glue */
|
||||
if(util.isUIThread()){
|
||||
const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
|
||||
wasm.exports.sqlite3_wasm_kvvfs_methods()
|
||||
wasm.exports.sqlite3__wasm_kvvfs_methods()
|
||||
);
|
||||
delete capi.sqlite3_kvvfs_methods;
|
||||
|
||||
const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
|
||||
const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack,
|
||||
pstack = wasm.pstack;
|
||||
|
||||
const kvvfsStorage = (zClass)=>
|
||||
@@ -1587,7 +1605,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
/**
|
||||
Implementations for members of the object referred to by
|
||||
sqlite3_wasm_kvvfs_methods(). We swap out the native
|
||||
sqlite3__wasm_kvvfs_methods(). We swap out the native
|
||||
implementations with these, which use localStorage or
|
||||
sessionStorage for their backing store.
|
||||
*/
|
||||
@@ -1667,5 +1685,181 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
}/*pKvvfs*/
|
||||
|
||||
/* Warn if client-level code makes use of FuncPtrAdapter. */
|
||||
wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
|
||||
|
||||
const StructBinder = sqlite3.StructBinder
|
||||
/* we require a local alias b/c StructBinder is removed from the sqlite3
|
||||
object during the final steps of the API cleanup. */;
|
||||
/**
|
||||
Installs a StructBinder-bound function pointer member of the
|
||||
given name and function in the given StructBinder.StructType
|
||||
target object.
|
||||
|
||||
It creates a WASM proxy for the given function and arranges for
|
||||
that proxy to be cleaned up when tgt.dispose() is called. Throws
|
||||
on the slightest hint of error, e.g. tgt is-not-a StructType,
|
||||
name does not map to a struct-bound member, etc.
|
||||
|
||||
As a special case, if the given function is a pointer, then
|
||||
`wasm.functionEntry()` is used to validate that it is a known
|
||||
function. If so, it is used as-is with no extra level of proxying
|
||||
or cleanup, else an exception is thrown. It is legal to pass a
|
||||
value of 0, indicating a NULL pointer, with the caveat that 0
|
||||
_is_ a legal function pointer in WASM but it will not be accepted
|
||||
as such _here_. (Justification: the function at address zero must
|
||||
be one which initially came from the WASM module, not a method we
|
||||
want to bind to a virtual table or VFS.)
|
||||
|
||||
This function returns a proxy for itself which is bound to tgt
|
||||
and takes 2 args (name,func). That function returns the same
|
||||
thing as this one, permitting calls to be chained.
|
||||
|
||||
If called with only 1 arg, it has no side effects but returns a
|
||||
func with the same signature as described above.
|
||||
|
||||
ACHTUNG: because we cannot generically know how to transform JS
|
||||
exceptions into result codes, the installed functions do no
|
||||
automatic catching of exceptions. It is critical, to avoid
|
||||
undefined behavior in the C layer, that methods mapped via
|
||||
this function do not throw. The exception, as it were, to that
|
||||
rule is...
|
||||
|
||||
If applyArgcCheck is true then each JS function (as opposed to
|
||||
function pointers) gets wrapped in a proxy which asserts that it
|
||||
is passed the expected number of arguments, throwing if the
|
||||
argument count does not match expectations. That is only intended
|
||||
for dev-time usage for sanity checking, and may leave the C
|
||||
environment in an undefined state.
|
||||
*/
|
||||
const installMethod = function callee(
|
||||
tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
|
||||
){
|
||||
if(!(tgt instanceof StructBinder.StructType)){
|
||||
toss("Usage error: target object is-not-a StructType.");
|
||||
}else if(!(func instanceof Function) && !wasm.isPtr(func)){
|
||||
toss("Usage errror: expecting a Function or WASM pointer to one.");
|
||||
}
|
||||
if(1===arguments.length){
|
||||
return (n,f)=>callee(tgt, n, f, applyArgcCheck);
|
||||
}
|
||||
if(!callee.argcProxy){
|
||||
callee.argcProxy = function(tgt, funcName, func,sig){
|
||||
return function(...args){
|
||||
if(func.length!==arguments.length){
|
||||
toss("Argument mismatch for",
|
||||
tgt.structInfo.name+"::"+funcName
|
||||
+": Native signature is:",sig);
|
||||
}
|
||||
return func.apply(this, args);
|
||||
}
|
||||
};
|
||||
/* An ondispose() callback for use with
|
||||
StructBinder-created types. */
|
||||
callee.removeFuncList = function(){
|
||||
if(this.ondispose.__removeFuncList){
|
||||
this.ondispose.__removeFuncList.forEach(
|
||||
(v,ndx)=>{
|
||||
if('number'===typeof v){
|
||||
try{wasm.uninstallFunction(v)}
|
||||
catch(e){/*ignore*/}
|
||||
}
|
||||
/* else it's a descriptive label for the next number in
|
||||
the list. */
|
||||
}
|
||||
);
|
||||
delete this.ondispose.__removeFuncList;
|
||||
}
|
||||
};
|
||||
}/*static init*/
|
||||
const sigN = tgt.memberSignature(name);
|
||||
if(sigN.length<2){
|
||||
toss("Member",name,"does not have a function pointer signature:",sigN);
|
||||
}
|
||||
const memKey = tgt.memberKey(name);
|
||||
const fProxy = (applyArgcCheck && !wasm.isPtr(func))
|
||||
/** This middle-man proxy is only for use during development, to
|
||||
confirm that we always pass the proper number of
|
||||
arguments. We know that the C-level code will always use the
|
||||
correct argument count. */
|
||||
? callee.argcProxy(tgt, memKey, func, sigN)
|
||||
: func;
|
||||
if(wasm.isPtr(fProxy)){
|
||||
if(fProxy && !wasm.functionEntry(fProxy)){
|
||||
toss("Pointer",fProxy,"is not a WASM function table entry.");
|
||||
}
|
||||
tgt[memKey] = fProxy;
|
||||
}else{
|
||||
const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
|
||||
tgt[memKey] = pFunc;
|
||||
if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
|
||||
tgt.addOnDispose('ondispose.__removeFuncList handler',
|
||||
callee.removeFuncList);
|
||||
tgt.ondispose.__removeFuncList = [];
|
||||
}
|
||||
tgt.ondispose.__removeFuncList.push(memKey, pFunc);
|
||||
}
|
||||
return (n,f)=>callee(tgt, n, f, applyArgcCheck);
|
||||
}/*installMethod*/;
|
||||
installMethod.installMethodArgcCheck = false;
|
||||
|
||||
/**
|
||||
Installs methods into the given StructBinder.StructType-type
|
||||
instance. Each entry in the given methods object must map to a
|
||||
known member of the given StructType, else an exception will be
|
||||
triggered. See installMethod() for more details, including the
|
||||
semantics of the 3rd argument.
|
||||
|
||||
As an exception to the above, if any two or more methods in the
|
||||
2nd argument are the exact same function, installMethod() is
|
||||
_not_ called for the 2nd and subsequent instances, and instead
|
||||
those instances get assigned the same method pointer which is
|
||||
created for the first instance. This optimization is primarily to
|
||||
accommodate special handling of sqlite3_module::xConnect and
|
||||
xCreate methods.
|
||||
|
||||
On success, returns its first argument. Throws on error.
|
||||
*/
|
||||
const installMethods = function(
|
||||
structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
|
||||
){
|
||||
const seen = new Map /* map of <Function, memberName> */;
|
||||
for(const k of Object.keys(methods)){
|
||||
const m = methods[k];
|
||||
const prior = seen.get(m);
|
||||
if(prior){
|
||||
const mkey = structInstance.memberKey(k);
|
||||
structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
|
||||
}else{
|
||||
installMethod(structInstance, k, m, applyArgcCheck);
|
||||
seen.set(m, k);
|
||||
}
|
||||
}
|
||||
return structInstance;
|
||||
};
|
||||
|
||||
/**
|
||||
Equivalent to calling installMethod(this,...arguments) with a
|
||||
first argument of this object. If called with 1 or 2 arguments
|
||||
and the first is an object, it's instead equivalent to calling
|
||||
installMethods(this,...arguments).
|
||||
*/
|
||||
StructBinder.StructType.prototype.installMethod = function callee(
|
||||
name, func, applyArgcCheck = installMethod.installMethodArgcCheck
|
||||
){
|
||||
return (arguments.length < 3 && name && 'object'===typeof name)
|
||||
? installMethods(this, ...arguments)
|
||||
: installMethod(this, ...arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
Equivalent to calling installMethods() with a first argument
|
||||
of this object.
|
||||
*/
|
||||
StructBinder.StructType.prototype.installMethods = function(
|
||||
methods, applyArgcCheck = installMethod.installMethodArgcCheck
|
||||
){
|
||||
return installMethods(this, methods, applyArgcCheck);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//#ifnot omit-oo1
|
||||
/*
|
||||
2022-07-22
|
||||
|
||||
@@ -1940,4 +1941,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}/*main-window-only bits*/
|
||||
|
||||
});
|
||||
|
||||
//#else
|
||||
/* Built with the omit-oo1 flag. */
|
||||
//#endif ifnot omit-oo1
|
||||
|
||||
@@ -1061,7 +1061,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
are undefined if the passed-in value did not come from
|
||||
this.pointer.
|
||||
*/
|
||||
restore: wasm.exports.sqlite3_wasm_pstack_restore,
|
||||
restore: wasm.exports.sqlite3__wasm_pstack_restore,
|
||||
/**
|
||||
Attempts to allocate the given number of bytes from the
|
||||
pstack. On success, it zeroes out a block of memory of the
|
||||
@@ -1083,7 +1083,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
if('string'===typeof n && !(n = wasm.sizeofIR(n))){
|
||||
WasmAllocError.toss("Invalid value for pstack.alloc(",arguments[0],")");
|
||||
}
|
||||
return wasm.exports.sqlite3_wasm_pstack_alloc(n)
|
||||
return wasm.exports.sqlite3__wasm_pstack_alloc(n)
|
||||
|| WasmAllocError.toss("Could not allocate",n,
|
||||
"bytes from the pstack.");
|
||||
},
|
||||
@@ -1163,10 +1163,10 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
*/
|
||||
pointer: {
|
||||
configurable: false, iterable: true, writeable: false,
|
||||
get: wasm.exports.sqlite3_wasm_pstack_ptr
|
||||
get: wasm.exports.sqlite3__wasm_pstack_ptr
|
||||
//Whether or not a setter as an alternative to restore() is
|
||||
//clearer or would just lead to confusion is unclear.
|
||||
//set: wasm.exports.sqlite3_wasm_pstack_restore
|
||||
//set: wasm.exports.sqlite3__wasm_pstack_restore
|
||||
},
|
||||
/**
|
||||
sqlite3.wasm.pstack.quota to the total number of bytes
|
||||
@@ -1175,7 +1175,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
*/
|
||||
quota: {
|
||||
configurable: false, iterable: true, writeable: false,
|
||||
get: wasm.exports.sqlite3_wasm_pstack_quota
|
||||
get: wasm.exports.sqlite3__wasm_pstack_quota
|
||||
},
|
||||
/**
|
||||
sqlite3.wasm.pstack.remaining resolves to the amount of space
|
||||
@@ -1183,7 +1183,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
*/
|
||||
remaining: {
|
||||
configurable: false, iterable: true, writeable: false,
|
||||
get: wasm.exports.sqlite3_wasm_pstack_remaining
|
||||
get: wasm.exports.sqlite3__wasm_pstack_remaining
|
||||
}
|
||||
})/*wasm.pstack properties*/;
|
||||
|
||||
@@ -1256,14 +1256,14 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
}
|
||||
try{
|
||||
if(pdir && 0===wasm.xCallWrapped(
|
||||
'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
|
||||
'sqlite3__wasm_init_wasmfs', 'i32', ['string'], pdir
|
||||
)){
|
||||
return __wasmfsOpfsDir = pdir;
|
||||
}else{
|
||||
return __wasmfsOpfsDir = "";
|
||||
}
|
||||
}catch(e){
|
||||
// sqlite3_wasm_init_wasmfs() is not available
|
||||
// sqlite3__wasm_init_wasmfs() is not available
|
||||
return __wasmfsOpfsDir = "";
|
||||
}
|
||||
};
|
||||
@@ -1365,7 +1365,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
const zSchema = schema
|
||||
? (wasm.isPtr(schema) ? schema : wasm.scopedAllocCString(''+schema))
|
||||
: 0;
|
||||
let rc = wasm.exports.sqlite3_wasm_db_serialize(
|
||||
let rc = wasm.exports.sqlite3__wasm_db_serialize(
|
||||
pDb, zSchema, ppOut, pSize, 0
|
||||
);
|
||||
if(rc){
|
||||
@@ -1391,7 +1391,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
or not provided, then "main" is assumed.
|
||||
*/
|
||||
capi.sqlite3_js_db_vfs =
|
||||
(dbPointer, dbName=0)=>wasm.sqlite3_wasm_db_vfs(dbPointer, dbName);
|
||||
(dbPointer, dbName=0)=>util.sqlite3__wasm_db_vfs(dbPointer, dbName);
|
||||
|
||||
/**
|
||||
A thin wrapper around capi.sqlite3_aggregate_context() which
|
||||
@@ -1449,7 +1449,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
if(!util.isInt32(dataLen) || dataLen<0){
|
||||
SQLite3Error.toss("Invalid 3rd argument for sqlite3_js_posix_create_file().");
|
||||
}
|
||||
const rc = wasm.sqlite3_wasm_posix_create_file(filename, pData, dataLen);
|
||||
const rc = util.sqlite3__wasm_posix_create_file(filename, pData, dataLen);
|
||||
if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
|
||||
capi.sqlite3_js_rc_str(rc));
|
||||
}finally{
|
||||
@@ -1551,7 +1551,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
SQLite3Error.toss("Invalid 4th argument for sqlite3_js_vfs_create_file().");
|
||||
}
|
||||
try{
|
||||
const rc = wasm.sqlite3_wasm_vfs_create_file(vfs, filename, pData, dataLen);
|
||||
const rc = util.sqlite3__wasm_vfs_create_file(vfs, filename, pData, dataLen);
|
||||
if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
|
||||
capi.sqlite3_js_rc_str(rc));
|
||||
}finally{
|
||||
@@ -1672,12 +1672,12 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
*/
|
||||
capi.sqlite3_db_config = function(pDb, op, ...args){
|
||||
if(!this.s){
|
||||
this.s = wasm.xWrap('sqlite3_wasm_db_config_s','int',
|
||||
this.s = wasm.xWrap('sqlite3__wasm_db_config_s','int',
|
||||
['sqlite3*', 'int', 'string:static']
|
||||
/* MAINDBNAME requires a static string */);
|
||||
this.pii = wasm.xWrap('sqlite3_wasm_db_config_pii', 'int',
|
||||
this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int',
|
||||
['sqlite3*', 'int', '*','int', 'int']);
|
||||
this.ip = wasm.xWrap('sqlite3_wasm_db_config_ip','int',
|
||||
this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip','int',
|
||||
['sqlite3*', 'int', 'int','*']);
|
||||
}
|
||||
switch(op){
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//#ifnot omit-oo1
|
||||
/**
|
||||
2022-07-22
|
||||
|
||||
@@ -358,6 +359,7 @@
|
||||
|
||||
*/
|
||||
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
const util = sqlite3.util;
|
||||
sqlite3.initWorker1API = function(){
|
||||
'use strict';
|
||||
const toss = (...args)=>{throw new Error(args.join(' '))};
|
||||
@@ -408,12 +410,12 @@ sqlite3.initWorker1API = function(){
|
||||
if(db){
|
||||
delete this.dbs[getDbId(db)];
|
||||
const filename = db.filename;
|
||||
const pVfs = sqlite3.wasm.sqlite3_wasm_db_vfs(db.pointer, 0);
|
||||
const pVfs = util.sqlite3__wasm_db_vfs(db.pointer, 0);
|
||||
db.close();
|
||||
const ddNdx = this.dbList.indexOf(db);
|
||||
if(ddNdx>=0) this.dbList.splice(ddNdx, 1);
|
||||
if(alsoUnlink && filename && pVfs){
|
||||
sqlite3.wasm.sqlite3_wasm_vfs_unlink(pVfs, filename);
|
||||
util.sqlite3__wasm_vfs_unlink(pVfs, filename);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -494,12 +496,12 @@ sqlite3.initWorker1API = function(){
|
||||
}
|
||||
if(pVfs){
|
||||
/* 2022-11-02: this feature is as-yet untested except that
|
||||
sqlite3_wasm_vfs_create_file() has been tested from the
|
||||
sqlite3__wasm_vfs_create_file() has been tested from the
|
||||
browser dev console. */
|
||||
let pMem;
|
||||
try{
|
||||
pMem = sqlite3.wasm.allocFromTypedArray(byteArray);
|
||||
const rc = sqlite3.wasm.sqlite3_wasm_vfs_create_file(
|
||||
const rc = util.sqlite3__wasm_vfs_create_file(
|
||||
pVfs, oargs.filename, pMem, byteArray.byteLength
|
||||
);
|
||||
if(rc) sqlite3.SQLite3Error.toss(rc);
|
||||
@@ -689,3 +691,6 @@ sqlite3.initWorker1API = function(){
|
||||
globalThis.postMessage({type:'sqlite3-api',result:'worker1-ready'});
|
||||
}.bind({sqlite3});
|
||||
});
|
||||
//#else
|
||||
/* Built with the omit-oo1 flag. */
|
||||
//#endif ifnot omit-oo1
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
** 2022-11-30
|
||||
**
|
||||
** 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 installs sqlite3.vfs, a namespace of helpers for use in
|
||||
the creation of JavaScript implementations of sqlite3_vfs.
|
||||
*/
|
||||
'use strict';
|
||||
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
|
||||
const vfs = Object.create(null);
|
||||
sqlite3.vfs = vfs;
|
||||
|
||||
/**
|
||||
Uses sqlite3_vfs_register() to register this
|
||||
sqlite3.capi.sqlite3_vfs instance. This object must have already
|
||||
been filled out properly. If the first argument is truthy, the
|
||||
VFS is registered as the default VFS, else it is not.
|
||||
|
||||
On success, returns this object. Throws on error.
|
||||
*/
|
||||
capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
|
||||
if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
|
||||
toss("Expecting a sqlite3_vfs-type argument.");
|
||||
}
|
||||
const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
|
||||
if(rc){
|
||||
toss("sqlite3_vfs_register(",this,") failed with rc",rc);
|
||||
}
|
||||
if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
|
||||
toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
|
||||
this);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
A wrapper for
|
||||
sqlite3.StructBinder.StructType.prototype.installMethods() or
|
||||
registerVfs() to reduce installation of a VFS and/or its I/O
|
||||
methods to a single call.
|
||||
|
||||
Accepts an object which contains the properties "io" and/or
|
||||
"vfs", each of which is itself an object with following properties:
|
||||
|
||||
- `struct`: an sqlite3.StructBinder.StructType-type struct. This
|
||||
must be a populated (except for the methods) object of type
|
||||
sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the
|
||||
"vfs" entry).
|
||||
|
||||
- `methods`: an object mapping sqlite3_io_methods method names
|
||||
(e.g. 'xClose') to JS implementations of those methods. The JS
|
||||
implementations must be call-compatible with their native
|
||||
counterparts.
|
||||
|
||||
For each of those object, this function passes its (`struct`,
|
||||
`methods`, (optional) `applyArgcCheck`) properties to
|
||||
installMethods().
|
||||
|
||||
If the `vfs` entry is set then:
|
||||
|
||||
- Its `struct` property's registerVfs() is called. The
|
||||
`vfs` entry may optionally have an `asDefault` property, which
|
||||
gets passed as the argument to registerVfs().
|
||||
|
||||
- If `struct.$zName` is falsy and the entry has a string-type
|
||||
`name` property, `struct.$zName` is set to the C-string form of
|
||||
that `name` value before registerVfs() is called. That string
|
||||
gets added to the on-dispose state of the struct.
|
||||
|
||||
On success returns this object. Throws on error.
|
||||
*/
|
||||
vfs.installVfs = function(opt){
|
||||
let count = 0;
|
||||
const propList = ['io','vfs'];
|
||||
for(const key of propList){
|
||||
const o = opt[key];
|
||||
if(o){
|
||||
++count;
|
||||
o.struct.installMethods(o.methods, !!o.applyArgcCheck);
|
||||
if('vfs'===key){
|
||||
if(!o.struct.$zName && 'string'===typeof o.name){
|
||||
o.struct.addOnDispose(
|
||||
o.struct.$zName = wasm.allocCString(o.name)
|
||||
);
|
||||
}
|
||||
o.struct.registerVfs(!!o.asDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!count) toss("Misuse: installVfs() options object requires at least",
|
||||
"one of:", propList);
|
||||
return this;
|
||||
};
|
||||
}/*sqlite3ApiBootstrap.initializers.push()*/);
|
||||
@@ -245,7 +245,8 @@ const installOpfsVfs = function callee(options){
|
||||
opfsIoMethods.$iVersion = 1;
|
||||
opfsVfs.$iVersion = 2/*yes, two*/;
|
||||
opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
|
||||
opfsVfs.$mxPathname = 1024/*sure, why not?*/;
|
||||
opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit
|
||||
is undocumented/unspecified. */;
|
||||
opfsVfs.$zName = wasm.allocCString("opfs");
|
||||
// All C-side memory of opfsVfs is zeroed out, but just to be explicit:
|
||||
opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null;
|
||||
@@ -993,27 +994,6 @@ const installOpfsVfs = function callee(options){
|
||||
*/
|
||||
opfsUtil.randomFilename = randomFilename;
|
||||
|
||||
/**
|
||||
Re-registers the OPFS VFS. This is intended only for odd use
|
||||
cases which have to call sqlite3_shutdown() as part of their
|
||||
initialization process, which will unregister the VFS
|
||||
registered by installOpfsVfs(). If passed a truthy value, the
|
||||
OPFS VFS is registered as the default VFS, else it is not made
|
||||
the default. Returns the result of the the
|
||||
sqlite3_vfs_register() call.
|
||||
|
||||
Design note: the problem of having to re-register things after
|
||||
a shutdown/initialize pair is more general. How to best plug
|
||||
that in to the library is unclear. In particular, we cannot
|
||||
hook in to any C-side calls to sqlite3_initialize(), so we
|
||||
cannot add an after-initialize callback mechanism.
|
||||
*/
|
||||
opfsUtil.registerVfs = (asDefault=false)=>{
|
||||
return wasm.exports.sqlite3_vfs_register(
|
||||
opfsVfs.pointer, asDefault ? 1 : 0
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
Returns a promise which resolves to an object which represents
|
||||
all files and directories in the OPFS tree. The top-most object
|
||||
|
||||
@@ -10,19 +10,13 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
This file installs sqlite3.vfs, and object which exists to assist
|
||||
in the creation of JavaScript implementations of sqlite3_vfs, along
|
||||
with its virtual table counterpart, sqlite3.vtab.
|
||||
This file installs sqlite3.vtab, a namespace of helpers for use in
|
||||
the creation of JavaScript implementations virtual tables.
|
||||
*/
|
||||
'use strict';
|
||||
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
|
||||
const vfs = Object.create(null), vtab = Object.create(null);
|
||||
|
||||
const StructBinder = sqlite3.StructBinder
|
||||
/* we require a local alias b/c StructBinder is removed from the sqlite3
|
||||
object during the final steps of the API cleanup. */;
|
||||
sqlite3.vfs = vfs;
|
||||
const vtab = Object.create(null);
|
||||
sqlite3.vtab = vtab;
|
||||
|
||||
const sii = capi.sqlite3_index_info;
|
||||
@@ -72,257 +66,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr);
|
||||
};
|
||||
|
||||
/**
|
||||
Installs a StructBinder-bound function pointer member of the
|
||||
given name and function in the given StructType target object.
|
||||
|
||||
It creates a WASM proxy for the given function and arranges for
|
||||
that proxy to be cleaned up when tgt.dispose() is called. Throws
|
||||
on the slightest hint of error, e.g. tgt is-not-a StructType,
|
||||
name does not map to a struct-bound member, etc.
|
||||
|
||||
As a special case, if the given function is a pointer, then
|
||||
`wasm.functionEntry()` is used to validate that it is a known
|
||||
function. If so, it is used as-is with no extra level of proxying
|
||||
or cleanup, else an exception is thrown. It is legal to pass a
|
||||
value of 0, indicating a NULL pointer, with the caveat that 0
|
||||
_is_ a legal function pointer in WASM but it will not be accepted
|
||||
as such _here_. (Justification: the function at address zero must
|
||||
be one which initially came from the WASM module, not a method we
|
||||
want to bind to a virtual table or VFS.)
|
||||
|
||||
This function returns a proxy for itself which is bound to tgt
|
||||
and takes 2 args (name,func). That function returns the same
|
||||
thing as this one, permitting calls to be chained.
|
||||
|
||||
If called with only 1 arg, it has no side effects but returns a
|
||||
func with the same signature as described above.
|
||||
|
||||
ACHTUNG: because we cannot generically know how to transform JS
|
||||
exceptions into result codes, the installed functions do no
|
||||
automatic catching of exceptions. It is critical, to avoid
|
||||
undefined behavior in the C layer, that methods mapped via
|
||||
this function do not throw. The exception, as it were, to that
|
||||
rule is...
|
||||
|
||||
If applyArgcCheck is true then each JS function (as opposed to
|
||||
function pointers) gets wrapped in a proxy which asserts that it
|
||||
is passed the expected number of arguments, throwing if the
|
||||
argument count does not match expectations. That is only intended
|
||||
for dev-time usage for sanity checking, and will leave the C
|
||||
environment in an undefined state.
|
||||
*/
|
||||
const installMethod = function callee(
|
||||
tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
|
||||
){
|
||||
if(!(tgt instanceof StructBinder.StructType)){
|
||||
toss("Usage error: target object is-not-a StructType.");
|
||||
}else if(!(func instanceof Function) && !wasm.isPtr(func)){
|
||||
toss("Usage errror: expecting a Function or WASM pointer to one.");
|
||||
}
|
||||
if(1===arguments.length){
|
||||
return (n,f)=>callee(tgt, n, f, applyArgcCheck);
|
||||
}
|
||||
if(!callee.argcProxy){
|
||||
callee.argcProxy = function(tgt, funcName, func,sig){
|
||||
return function(...args){
|
||||
if(func.length!==arguments.length){
|
||||
toss("Argument mismatch for",
|
||||
tgt.structInfo.name+"::"+funcName
|
||||
+": Native signature is:",sig);
|
||||
}
|
||||
return func.apply(this, args);
|
||||
}
|
||||
};
|
||||
/* An ondispose() callback for use with
|
||||
StructBinder-created types. */
|
||||
callee.removeFuncList = function(){
|
||||
if(this.ondispose.__removeFuncList){
|
||||
this.ondispose.__removeFuncList.forEach(
|
||||
(v,ndx)=>{
|
||||
if('number'===typeof v){
|
||||
try{wasm.uninstallFunction(v)}
|
||||
catch(e){/*ignore*/}
|
||||
}
|
||||
/* else it's a descriptive label for the next number in
|
||||
the list. */
|
||||
}
|
||||
);
|
||||
delete this.ondispose.__removeFuncList;
|
||||
}
|
||||
};
|
||||
}/*static init*/
|
||||
const sigN = tgt.memberSignature(name);
|
||||
if(sigN.length<2){
|
||||
toss("Member",name,"does not have a function pointer signature:",sigN);
|
||||
}
|
||||
const memKey = tgt.memberKey(name);
|
||||
const fProxy = (applyArgcCheck && !wasm.isPtr(func))
|
||||
/** This middle-man proxy is only for use during development, to
|
||||
confirm that we always pass the proper number of
|
||||
arguments. We know that the C-level code will always use the
|
||||
correct argument count. */
|
||||
? callee.argcProxy(tgt, memKey, func, sigN)
|
||||
: func;
|
||||
if(wasm.isPtr(fProxy)){
|
||||
if(fProxy && !wasm.functionEntry(fProxy)){
|
||||
toss("Pointer",fProxy,"is not a WASM function table entry.");
|
||||
}
|
||||
tgt[memKey] = fProxy;
|
||||
}else{
|
||||
const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
|
||||
tgt[memKey] = pFunc;
|
||||
if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
|
||||
tgt.addOnDispose('ondispose.__removeFuncList handler',
|
||||
callee.removeFuncList);
|
||||
tgt.ondispose.__removeFuncList = [];
|
||||
}
|
||||
tgt.ondispose.__removeFuncList.push(memKey, pFunc);
|
||||
}
|
||||
return (n,f)=>callee(tgt, n, f, applyArgcCheck);
|
||||
}/*installMethod*/;
|
||||
installMethod.installMethodArgcCheck = false;
|
||||
|
||||
/**
|
||||
Installs methods into the given StructType-type instance. Each
|
||||
entry in the given methods object must map to a known member of
|
||||
the given StructType, else an exception will be triggered. See
|
||||
installMethod() for more details, including the semantics of the
|
||||
3rd argument.
|
||||
|
||||
As an exception to the above, if any two or more methods in the
|
||||
2nd argument are the exact same function, installMethod() is
|
||||
_not_ called for the 2nd and subsequent instances, and instead
|
||||
those instances get assigned the same method pointer which is
|
||||
created for the first instance. This optimization is primarily to
|
||||
accommodate special handling of sqlite3_module::xConnect and
|
||||
xCreate methods.
|
||||
|
||||
On success, returns its first argument. Throws on error.
|
||||
*/
|
||||
const installMethods = function(
|
||||
structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
|
||||
){
|
||||
const seen = new Map /* map of <Function, memberName> */;
|
||||
for(const k of Object.keys(methods)){
|
||||
const m = methods[k];
|
||||
const prior = seen.get(m);
|
||||
if(prior){
|
||||
const mkey = structInstance.memberKey(k);
|
||||
structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
|
||||
}else{
|
||||
installMethod(structInstance, k, m, applyArgcCheck);
|
||||
seen.set(m, k);
|
||||
}
|
||||
}
|
||||
return structInstance;
|
||||
};
|
||||
|
||||
/**
|
||||
Equivalent to calling installMethod(this,...arguments) with a
|
||||
first argument of this object. If called with 1 or 2 arguments
|
||||
and the first is an object, it's instead equivalent to calling
|
||||
installMethods(this,...arguments).
|
||||
*/
|
||||
StructBinder.StructType.prototype.installMethod = function callee(
|
||||
name, func, applyArgcCheck = installMethod.installMethodArgcCheck
|
||||
){
|
||||
return (arguments.length < 3 && name && 'object'===typeof name)
|
||||
? installMethods(this, ...arguments)
|
||||
: installMethod(this, ...arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
Equivalent to calling installMethods() with a first argument
|
||||
of this object.
|
||||
*/
|
||||
StructBinder.StructType.prototype.installMethods = function(
|
||||
methods, applyArgcCheck = installMethod.installMethodArgcCheck
|
||||
){
|
||||
return installMethods(this, methods, applyArgcCheck);
|
||||
};
|
||||
|
||||
/**
|
||||
Uses sqlite3_vfs_register() to register this
|
||||
sqlite3.capi.sqlite3_vfs. This object must have already been
|
||||
filled out properly. If the first argument is truthy, the VFS is
|
||||
registered as the default VFS, else it is not.
|
||||
|
||||
On success, returns this object. Throws on error.
|
||||
*/
|
||||
capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
|
||||
if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
|
||||
toss("Expecting a sqlite3_vfs-type argument.");
|
||||
}
|
||||
const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
|
||||
if(rc){
|
||||
toss("sqlite3_vfs_register(",this,") failed with rc",rc);
|
||||
}
|
||||
if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
|
||||
toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
|
||||
this);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
A wrapper for installMethods() or registerVfs() to reduce
|
||||
installation of a VFS and/or its I/O methods to a single
|
||||
call.
|
||||
|
||||
Accepts an object which contains the properties "io" and/or
|
||||
"vfs", each of which is itself an object with following properties:
|
||||
|
||||
- `struct`: an sqlite3.StructType-type struct. This must be a
|
||||
populated (except for the methods) object of type
|
||||
sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the
|
||||
"vfs" entry).
|
||||
|
||||
- `methods`: an object mapping sqlite3_io_methods method names
|
||||
(e.g. 'xClose') to JS implementations of those methods. The JS
|
||||
implementations must be call-compatible with their native
|
||||
counterparts.
|
||||
|
||||
For each of those object, this function passes its (`struct`,
|
||||
`methods`, (optional) `applyArgcCheck`) properties to
|
||||
installMethods().
|
||||
|
||||
If the `vfs` entry is set then:
|
||||
|
||||
- Its `struct` property's registerVfs() is called. The
|
||||
`vfs` entry may optionally have an `asDefault` property, which
|
||||
gets passed as the argument to registerVfs().
|
||||
|
||||
- If `struct.$zName` is falsy and the entry has a string-type
|
||||
`name` property, `struct.$zName` is set to the C-string form of
|
||||
that `name` value before registerVfs() is called. That string
|
||||
gets added to the on-dispose state of the struct.
|
||||
|
||||
On success returns this object. Throws on error.
|
||||
*/
|
||||
vfs.installVfs = function(opt){
|
||||
let count = 0;
|
||||
const propList = ['io','vfs'];
|
||||
for(const key of propList){
|
||||
const o = opt[key];
|
||||
if(o){
|
||||
++count;
|
||||
installMethods(o.struct, o.methods, !!o.applyArgcCheck);
|
||||
if('vfs'===key){
|
||||
if(!o.struct.$zName && 'string'===typeof o.name){
|
||||
o.struct.addOnDispose(
|
||||
o.struct.$zName = wasm.allocCString(o.name)
|
||||
);
|
||||
}
|
||||
o.struct.registerVfs(!!o.asDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!count) toss("Misuse: installVfs() options object requires at least",
|
||||
"one of:", propList);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
Internal factory function for xVtab and xCursor impls.
|
||||
*/
|
||||
@@ -456,30 +199,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
*/
|
||||
vtab.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);
|
||||
|
||||
/**
|
||||
Given an error object, this function returns
|
||||
sqlite3.capi.SQLITE_NOMEM if (e instanceof
|
||||
sqlite3.WasmAllocError), else it returns its
|
||||
second argument. Its intended usage is in the methods
|
||||
of a sqlite3_vfs or sqlite3_module:
|
||||
|
||||
```
|
||||
try{
|
||||
let rc = ...
|
||||
return rc;
|
||||
}catch(e){
|
||||
return sqlite3.vtab.exceptionToRc(e, sqlite3.capi.SQLITE_XYZ);
|
||||
// where SQLITE_XYZ is some call-appropriate result code.
|
||||
}
|
||||
```
|
||||
*/
|
||||
/**vfs.exceptionToRc = vtab.exceptionToRc =
|
||||
(e, defaultRc=capi.SQLITE_ERROR)=>(
|
||||
(e instanceof sqlite3.WasmAllocError)
|
||||
? capi.SQLITE_NOMEM
|
||||
: defaultRc
|
||||
);*/
|
||||
|
||||
/**
|
||||
Given an sqlite3_module method name and error object, this
|
||||
function returns sqlite3.capi.SQLITE_NOMEM if (e instanceof
|
||||
@@ -525,20 +244,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
};
|
||||
vtab.xError.errorReporter = 1 ? console.error.bind(console) : false;
|
||||
|
||||
/**
|
||||
"The problem" with this is that it introduces an outer function with
|
||||
a different arity than the passed-in method callback. That means we
|
||||
cannot do argc validation on these. Additionally, some methods (namely
|
||||
xConnect) may have call-specific error handling. It would be a shame to
|
||||
hard-coded that per-method support in this function.
|
||||
*/
|
||||
/** vtab.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){
|
||||
return function(...args){
|
||||
try { method(...args); }
|
||||
}catch(e){ return vtab.xError(methodName, e, defaultRc) }
|
||||
};
|
||||
*/
|
||||
|
||||
/**
|
||||
A helper for sqlite3_vtab::xRowid() and xUpdate()
|
||||
implementations. It must be passed the final argument to one of
|
||||
@@ -685,12 +390,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
remethods[k] = fwrap(k, m);
|
||||
}
|
||||
}
|
||||
installMethods(mod, remethods, false);
|
||||
mod.installMethods(remethods, false);
|
||||
}else{
|
||||
// No automatic exception handling. Trust the client
|
||||
// to not throw.
|
||||
installMethods(
|
||||
mod, methods, !!opt.applyArgcCheck/*undocumented option*/
|
||||
mod.installMethods(
|
||||
methods, !!opt.applyArgcCheck/*undocumented option*/
|
||||
);
|
||||
}
|
||||
if(0===mod.$iVersion){
|
||||
+71
-66
@@ -147,6 +147,12 @@
|
||||
# define SQLITE_OS_KV_OPTIONAL 1
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_S... */
|
||||
#ifndef SQLITE_STRICT_SUBTYPE
|
||||
# define SQLITE_STRICT_SUBTYPE 1
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_T... */
|
||||
#ifndef SQLITE_TEMP_STORE
|
||||
@@ -232,28 +238,28 @@
|
||||
** Another option is to malloc() a chunk of our own and call that our
|
||||
** "stack".
|
||||
*/
|
||||
SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_end(void){
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_end(void){
|
||||
extern void __heap_base
|
||||
/* see https://stackoverflow.com/questions/10038964 */;
|
||||
return &__heap_base;
|
||||
}
|
||||
SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_begin(void){
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_begin(void){
|
||||
extern void __data_end;
|
||||
return &__data_end;
|
||||
}
|
||||
static void * pWasmStackPtr = 0;
|
||||
SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_ptr(void){
|
||||
if(!pWasmStackPtr) pWasmStackPtr = sqlite3_wasm_stack_end();
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_ptr(void){
|
||||
if(!pWasmStackPtr) pWasmStackPtr = sqlite3__wasm_stack_end();
|
||||
return pWasmStackPtr;
|
||||
}
|
||||
SQLITE_WASM_EXPORT void sqlite3_wasm_stack_restore(void * p){
|
||||
SQLITE_WASM_EXPORT void sqlite3__wasm_stack_restore(void * p){
|
||||
pWasmStackPtr = p;
|
||||
}
|
||||
SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_alloc(int n){
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_alloc(int n){
|
||||
if(n<=0) return 0;
|
||||
n = (n + 7) & ~7 /* align to 8-byte boundary */;
|
||||
unsigned char * const p = (unsigned char *)sqlite3_wasm_stack_ptr();
|
||||
unsigned const char * const b = (unsigned const char *)sqlite3_wasm_stack_begin();
|
||||
unsigned char * const p = (unsigned char *)sqlite3__wasm_stack_ptr();
|
||||
unsigned const char * const b = (unsigned const char *)sqlite3__wasm_stack_begin();
|
||||
if(b + n >= p || b + n < b/*overflow*/) return 0;
|
||||
return pWasmStackPtr = p - n;
|
||||
}
|
||||
@@ -261,7 +267,7 @@ SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_alloc(int n){
|
||||
|
||||
/*
|
||||
** State for the "pseudo-stack" allocator implemented in
|
||||
** sqlite3_wasm_pstack_xyz(). In order to avoid colliding with
|
||||
** sqlite3__wasm_pstack_xyz(). In order to avoid colliding with
|
||||
** Emscripten-controled stack space, it carves out a bit of stack
|
||||
** memory to use for that purpose. This memory ends up in the
|
||||
** WASM-managed memory, such that routines which manipulate the wasm
|
||||
@@ -285,14 +291,14 @@ static struct {
|
||||
/*
|
||||
** Returns the current pstack position.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_ptr(void){
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_ptr(void){
|
||||
return PStack.pPos;
|
||||
}
|
||||
/*
|
||||
** Sets the pstack position poitner to p. Results are undefined if the
|
||||
** given value did not come from sqlite3_wasm_pstack_ptr().
|
||||
** given value did not come from sqlite3__wasm_pstack_ptr().
|
||||
*/
|
||||
SQLITE_WASM_EXPORT void sqlite3_wasm_pstack_restore(unsigned char * p){
|
||||
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));
|
||||
if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){
|
||||
@@ -307,7 +313,7 @@ SQLITE_WASM_EXPORT void sqlite3_wasm_pstack_restore(unsigned char * p){
|
||||
** JS code from having to do so, and most uses of the pstack will
|
||||
** call for doing so).
|
||||
*/
|
||||
SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_alloc(int n){
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_alloc(int n){
|
||||
if( n<=0 ) return 0;
|
||||
//if( n & 0x7 ) n += 8 - (n & 0x7) /* align to 8-byte boundary */;
|
||||
n = (n + 7) & ~7 /* align to 8-byte boundary */;
|
||||
@@ -318,9 +324,9 @@ SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_alloc(int n){
|
||||
}
|
||||
/*
|
||||
** Return the number of bytes left which can be
|
||||
** sqlite3_wasm_pstack_alloc()'d.
|
||||
** sqlite3__wasm_pstack_alloc()'d.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_remaining(void){
|
||||
SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_remaining(void){
|
||||
assert(PStack.pPos >= PStack.pBegin);
|
||||
assert(PStack.pPos <= PStack.pEnd);
|
||||
return (int)(PStack.pPos - PStack.pBegin);
|
||||
@@ -331,7 +337,7 @@ SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_remaining(void){
|
||||
** any space which is currently allocated. This value is a
|
||||
** compile-time constant.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_quota(void){
|
||||
SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_quota(void){
|
||||
return (int)(PStack.pEnd - PStack.pBegin);
|
||||
}
|
||||
|
||||
@@ -350,7 +356,7 @@ SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_quota(void){
|
||||
** Returns err_code.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
|
||||
int sqlite3__wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
|
||||
if( db!=0 ){
|
||||
if( 0!=zMsg ){
|
||||
const int nMsg = sqlite3Strlen30(zMsg);
|
||||
@@ -374,7 +380,7 @@ struct WasmTestStruct {
|
||||
};
|
||||
typedef struct WasmTestStruct WasmTestStruct;
|
||||
SQLITE_WASM_EXPORT
|
||||
void sqlite3_wasm_test_struct(WasmTestStruct * s){
|
||||
void sqlite3__wasm_test_struct(WasmTestStruct * s){
|
||||
if(s){
|
||||
s->v4 *= 2;
|
||||
s->v8 = s->v4 * 2;
|
||||
@@ -402,7 +408,7 @@ void sqlite3_wasm_test_struct(WasmTestStruct * s){
|
||||
** increased. In debug builds that will trigger an assert().
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
const char * sqlite3_wasm_enum_json(void){
|
||||
const char * sqlite3__wasm_enum_json(void){
|
||||
static char aBuffer[1024 * 20] = {0} /* where the JSON goes */;
|
||||
int n = 0, nChildren = 0, nStruct = 0
|
||||
/* output counters for figuring out where commas go */;
|
||||
@@ -419,7 +425,7 @@ const char * sqlite3_wasm_enum_json(void){
|
||||
|
||||
/* Core output macros... */
|
||||
#define lenCheck assert(zPos < zEnd - 128 \
|
||||
&& "sqlite3_wasm_enum_json() buffer is too small."); \
|
||||
&& "sqlite3__wasm_enum_json() buffer is too small."); \
|
||||
if( zPos >= zEnd - 128 ) return 0
|
||||
#define outf(format,...) \
|
||||
zPos += snprintf(zPos, ((size_t)(zEnd - zPos)), format, __VA_ARGS__); \
|
||||
@@ -1097,7 +1103,7 @@ const char * sqlite3_wasm_enum_json(void){
|
||||
M(xShadowName, "i(s)");
|
||||
} _StructBinder;
|
||||
#undef CurrentStruct
|
||||
|
||||
|
||||
/**
|
||||
** Workaround: in order to map the various inner structs from
|
||||
** sqlite3_index_info, we have to uplift those into constructs we
|
||||
@@ -1214,7 +1220,7 @@ const char * sqlite3_wasm_enum_json(void){
|
||||
** call is returned.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
|
||||
int sqlite3__wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
|
||||
int rc = SQLITE_MISUSE /* ??? */;
|
||||
if( 0==pVfs && 0!=zName ) pVfs = sqlite3_vfs_find(0);
|
||||
if( zName && pVfs && pVfs->xDelete ){
|
||||
@@ -1232,7 +1238,7 @@ int sqlite3_wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
|
||||
** given name is open.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
sqlite3_vfs * sqlite3_wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
|
||||
sqlite3_vfs * sqlite3__wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
|
||||
sqlite3_vfs * pVfs = 0;
|
||||
sqlite3_file_control(pDb, zDbName ? zDbName : "main",
|
||||
SQLITE_FCNTL_VFS_POINTER, &pVfs);
|
||||
@@ -1255,7 +1261,7 @@ sqlite3_vfs * sqlite3_wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
|
||||
** SQLITE_MISUSE if pDb is NULL.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_db_reset(sqlite3 *pDb){
|
||||
int sqlite3__wasm_db_reset(sqlite3 *pDb){
|
||||
int rc = SQLITE_MISUSE;
|
||||
if( pDb ){
|
||||
sqlite3_table_column_metadata(pDb, "main", 0, 0, 0, 0, 0, 0, 0);
|
||||
@@ -1282,11 +1288,11 @@ int sqlite3_wasm_db_reset(sqlite3 *pDb){
|
||||
** takes no measures to ensure that is the case.
|
||||
**
|
||||
** This implementation appears to work fine, but
|
||||
** sqlite3_wasm_db_serialize() is arguably the better way to achieve
|
||||
** sqlite3__wasm_db_serialize() is arguably the better way to achieve
|
||||
** this.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_db_export_chunked( sqlite3* pDb,
|
||||
int sqlite3__wasm_db_export_chunked( sqlite3* pDb,
|
||||
int (*xCallback)(unsigned const char *zOut, int n) ){
|
||||
sqlite3_int64 nSize = 0;
|
||||
sqlite3_int64 nPos = 0;
|
||||
@@ -1337,7 +1343,7 @@ int sqlite3_wasm_db_export_chunked( sqlite3* pDb,
|
||||
** sqlite3_free() to free it.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
|
||||
int sqlite3__wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
|
||||
unsigned char **pOut,
|
||||
sqlite3_int64 *nOut, unsigned int mFlags ){
|
||||
unsigned char * z;
|
||||
@@ -1360,7 +1366,7 @@ int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
|
||||
** this function's out-of-scope use of the sqlite3_vfs/file/io_methods
|
||||
** APIs leads to triggering of assertions in the core library. Its use
|
||||
** is now deprecated and VFS-specific APIs for importing files need to
|
||||
** be found to replace it. sqlite3_wasm_posix_create_file() is
|
||||
** be found to replace it. sqlite3__wasm_posix_create_file() is
|
||||
** suitable for the "unix" family of VFSes.
|
||||
**
|
||||
** Creates a new file using the I/O API of the given VFS, containing
|
||||
@@ -1401,7 +1407,7 @@ int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
|
||||
** support is disabled or unavailable.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs,
|
||||
int sqlite3__wasm_vfs_create_file( sqlite3_vfs *pVfs,
|
||||
const char *zFilename,
|
||||
const unsigned char * pData,
|
||||
int nData ){
|
||||
@@ -1491,7 +1497,7 @@ int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs,
|
||||
** SQLITE_IOERR on error.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_posix_create_file( const char *zFilename,
|
||||
int sqlite3__wasm_posix_create_file( const char *zFilename,
|
||||
const unsigned char * pData,
|
||||
int nData ){
|
||||
int rc;
|
||||
@@ -1514,17 +1520,17 @@ int sqlite3_wasm_posix_create_file( const char *zFilename,
|
||||
** for use by the sqlite project's own JS/WASM bindings.
|
||||
**
|
||||
** Allocates sqlite3KvvfsMethods.nKeySize bytes from
|
||||
** sqlite3_wasm_pstack_alloc() and returns 0 if that allocation fails,
|
||||
** sqlite3__wasm_pstack_alloc() and returns 0 if that allocation fails,
|
||||
** else it passes that string to kvstorageMakeKey() and returns a
|
||||
** NUL-terminated pointer to that string. It is up to the caller to
|
||||
** use sqlite3_wasm_pstack_restore() to free the returned pointer.
|
||||
** use sqlite3__wasm_pstack_restore() to free the returned pointer.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
char * sqlite3_wasm_kvvfsMakeKeyOnPstack(const char *zClass,
|
||||
char * sqlite3__wasm_kvvfsMakeKeyOnPstack(const char *zClass,
|
||||
const char *zKeyIn){
|
||||
assert(sqlite3KvvfsMethods.nKeySize>24);
|
||||
char *zKeyOut =
|
||||
(char *)sqlite3_wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize);
|
||||
(char *)sqlite3__wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize);
|
||||
if(zKeyOut){
|
||||
kvstorageMakeKey(zClass, zKeyIn, zKeyOut);
|
||||
}
|
||||
@@ -1539,7 +1545,7 @@ char * sqlite3_wasm_kvvfsMakeKeyOnPstack(const char *zClass,
|
||||
** I/O methods and associated state.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
sqlite3_kvvfs_methods * sqlite3_wasm_kvvfs_methods(void){
|
||||
sqlite3_kvvfs_methods * sqlite3__wasm_kvvfs_methods(void){
|
||||
return &sqlite3KvvfsMethods;
|
||||
}
|
||||
|
||||
@@ -1554,7 +1560,7 @@ sqlite3_kvvfs_methods * sqlite3_wasm_kvvfs_methods(void){
|
||||
** valid value.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_vtab_config(sqlite3 *pDb, int op, int arg){
|
||||
int sqlite3__wasm_vtab_config(sqlite3 *pDb, int op, int arg){
|
||||
switch(op){
|
||||
case SQLITE_VTAB_DIRECTONLY:
|
||||
case SQLITE_VTAB_INNOCUOUS:
|
||||
@@ -1574,7 +1580,7 @@ int sqlite3_wasm_vtab_config(sqlite3 *pDb, int op, int arg){
|
||||
** (int,int*) variadic args.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
|
||||
int sqlite3__wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
|
||||
switch(op){
|
||||
case SQLITE_DBCONFIG_ENABLE_FKEY:
|
||||
case SQLITE_DBCONFIG_ENABLE_TRIGGER:
|
||||
@@ -1607,7 +1613,7 @@ int sqlite3_wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
|
||||
** (void*,int,int) variadic args.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){
|
||||
int sqlite3__wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){
|
||||
switch(op){
|
||||
case SQLITE_DBCONFIG_LOOKASIDE:
|
||||
return sqlite3_db_config(pDb, op, pArg1, arg2, arg3);
|
||||
@@ -1623,7 +1629,7 @@ int sqlite3_wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int
|
||||
** (const char *) variadic args.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
|
||||
int sqlite3__wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
|
||||
switch(op){
|
||||
case SQLITE_DBCONFIG_MAINDBNAME:
|
||||
return sqlite3_db_config(pDb, op, zArg);
|
||||
@@ -1640,7 +1646,7 @@ int sqlite3_wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
|
||||
** a single integer argument.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_config_i(int op, int arg){
|
||||
int sqlite3__wasm_config_i(int op, int arg){
|
||||
return sqlite3_config(op, arg);
|
||||
}
|
||||
|
||||
@@ -1652,7 +1658,7 @@ int sqlite3_wasm_config_i(int op, int arg){
|
||||
** two int arguments.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_config_ii(int op, int arg1, int arg2){
|
||||
int sqlite3__wasm_config_ii(int op, int arg1, int arg2){
|
||||
return sqlite3_config(op, arg1, arg2);
|
||||
}
|
||||
|
||||
@@ -1664,7 +1670,7 @@ int sqlite3_wasm_config_ii(int op, int arg1, int arg2){
|
||||
** a single i64 argument.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_config_j(int op, sqlite3_int64 arg){
|
||||
int sqlite3__wasm_config_j(int op, sqlite3_int64 arg){
|
||||
return sqlite3_config(op, arg);
|
||||
}
|
||||
|
||||
@@ -1683,17 +1689,17 @@ int sqlite3_wasm_config_j(int op, sqlite3_int64 arg){
|
||||
**
|
||||
** ```
|
||||
** sqlite3.wasm.functionEntry(
|
||||
** sqlite3.wasm.exports.sqlite3_wasm_ptr_to_sqlite3_free()
|
||||
** sqlite3.wasm.exports.sqlite3__wasm_ptr_to_sqlite3_free()
|
||||
** ) === sqlite3.wasm.exports.sqlite3_free
|
||||
** ```
|
||||
**
|
||||
** Using a function to return this pointer, as opposed to exporting it
|
||||
** via sqlite3_wasm_enum_json(), is an attempt to work around a
|
||||
** via sqlite3__wasm_enum_json(), is an attempt to work around a
|
||||
** Safari-specific quirk covered at
|
||||
** https://sqlite.org/forum/info/e5b20e1feb37a19a.
|
||||
**/
|
||||
SQLITE_WASM_EXPORT
|
||||
void * sqlite3_wasm_ptr_to_sqlite3_free(void){
|
||||
void * sqlite3__wasm_ptr_to_sqlite3_free(void){
|
||||
return (void*)sqlite3_free;
|
||||
}
|
||||
#endif
|
||||
@@ -1723,7 +1729,7 @@ void * sqlite3_wasm_ptr_to_sqlite3_free(void){
|
||||
** defined, SQLITE_NOTFOUND is returned without side effects.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_init_wasmfs(const char *zMountPoint){
|
||||
int sqlite3__wasm_init_wasmfs(const char *zMountPoint){
|
||||
static backend_t pOpfs = 0;
|
||||
if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs";
|
||||
if( !pOpfs ){
|
||||
@@ -1743,7 +1749,7 @@ int sqlite3_wasm_init_wasmfs(const char *zMountPoint){
|
||||
}
|
||||
#else
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_init_wasmfs(const char *zUnused){
|
||||
int sqlite3__wasm_init_wasmfs(const char *zUnused){
|
||||
//emscripten_console_warn("WASMFS OPFS is not compiled in.");
|
||||
if(zUnused){/*unused*/}
|
||||
return SQLITE_NOTFOUND;
|
||||
@@ -1753,51 +1759,51 @@ int sqlite3_wasm_init_wasmfs(const char *zUnused){
|
||||
#if SQLITE_WASM_TESTS
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_test_intptr(int * p){
|
||||
int sqlite3__wasm_test_intptr(int * p){
|
||||
return *p = *p * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
void * sqlite3_wasm_test_voidptr(void * p){
|
||||
void * sqlite3__wasm_test_voidptr(void * p){
|
||||
return p;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
int64_t sqlite3_wasm_test_int64_max(void){
|
||||
int64_t sqlite3__wasm_test_int64_max(void){
|
||||
return (int64_t)0x7fffffffffffffff;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
int64_t sqlite3_wasm_test_int64_min(void){
|
||||
return ~sqlite3_wasm_test_int64_max();
|
||||
int64_t sqlite3__wasm_test_int64_min(void){
|
||||
return ~sqlite3__wasm_test_int64_max();
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
int64_t sqlite3_wasm_test_int64_times2(int64_t x){
|
||||
int64_t sqlite3__wasm_test_int64_times2(int64_t x){
|
||||
return x * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
void sqlite3_wasm_test_int64_minmax(int64_t * min, int64_t *max){
|
||||
*max = sqlite3_wasm_test_int64_max();
|
||||
*min = sqlite3_wasm_test_int64_min();
|
||||
void sqlite3__wasm_test_int64_minmax(int64_t * min, int64_t *max){
|
||||
*max = sqlite3__wasm_test_int64_max();
|
||||
*min = sqlite3__wasm_test_int64_min();
|
||||
/*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
int64_t sqlite3_wasm_test_int64ptr(int64_t * p){
|
||||
/*printf("sqlite3_wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
|
||||
int64_t sqlite3__wasm_test_int64ptr(int64_t * p){
|
||||
/*printf("sqlite3__wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
|
||||
return *p = *p * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
void sqlite3_wasm_test_stack_overflow(int recurse){
|
||||
if(recurse) sqlite3_wasm_test_stack_overflow(recurse);
|
||||
void sqlite3__wasm_test_stack_overflow(int recurse){
|
||||
if(recurse) sqlite3__wasm_test_stack_overflow(recurse);
|
||||
}
|
||||
|
||||
/* For testing the 'string:dealloc' whwasmutil.xWrap() conversion. */
|
||||
SQLITE_WASM_EXPORT
|
||||
char * sqlite3_wasm_test_str_hello(int fail){
|
||||
char * sqlite3__wasm_test_str_hello(int fail){
|
||||
char * s = fail ? 0 : (char *)sqlite3_malloc(6);
|
||||
if(s){
|
||||
memcpy(s, "hello", 5);
|
||||
@@ -1832,12 +1838,12 @@ char * sqlite3_wasm_test_str_hello(int fail){
|
||||
** optional + or - sign in front, or a hexadecimal
|
||||
** literal of the form 0x...
|
||||
*/
|
||||
static int sqlite3_wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
|
||||
static int sqlite3__wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
|
||||
int c, c2;
|
||||
int invert;
|
||||
int seen;
|
||||
typedef int (*recurse_f)(const char *,const char *);
|
||||
static const recurse_f recurse = sqlite3_wasm_SQLTester_strnotglob;
|
||||
static const recurse_f recurse = sqlite3__wasm_SQLTester_strnotglob;
|
||||
|
||||
while( (c = (*(zGlob++)))!=0 ){
|
||||
if( c=='*' ){
|
||||
@@ -1912,11 +1918,10 @@ static int sqlite3_wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_SQLTester_strglob(const char *zGlob, const char *z){
|
||||
return !sqlite3_wasm_SQLTester_strnotglob(zGlob, z);
|
||||
int sqlite3__wasm_SQLTester_strglob(const char *zGlob, const char *z){
|
||||
return !sqlite3__wasm_SQLTester_strnotglob(zGlob, z);
|
||||
}
|
||||
|
||||
|
||||
#endif /* SQLITE_WASM_TESTS */
|
||||
|
||||
#undef SQLITE_WASM_EXPORT
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//#ifnot omit-oo1
|
||||
/*
|
||||
2022-08-24
|
||||
|
||||
@@ -199,10 +200,11 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
|
||||
msg = Object.create(null);
|
||||
msg.type = arguments[0];
|
||||
msg.args = arguments[1];
|
||||
msg.dbId = msg.args.dbId;
|
||||
}else{
|
||||
toss("Invalid arugments for sqlite3Worker1Promiser()-created factory.");
|
||||
}
|
||||
if(!msg.dbId) msg.dbId = dbId;
|
||||
if(!msg.dbId && msg.type!=='open') msg.dbId = dbId;
|
||||
msg.messageId = genMsgId(msg);
|
||||
msg.departureTime = performance.now();
|
||||
const proxy = Object.create(null);
|
||||
@@ -275,3 +277,6 @@ globalThis.sqlite3Worker1Promiser.defaultConfig = {
|
||||
,
|
||||
onerror: (...args)=>console.error('worker1 promiser error',...args)
|
||||
};
|
||||
//#else
|
||||
/* Built with the omit-oo1 flag. */
|
||||
//#endif ifnot omit-oo1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//#ifnot omit-oo1
|
||||
/*
|
||||
2022-05-23
|
||||
|
||||
@@ -48,3 +49,6 @@ import {default as sqlite3InitModule} from './sqlite3-bundler-friendly.mjs';
|
||||
}
|
||||
//#endif
|
||||
sqlite3InitModule().then(sqlite3 => sqlite3.initWorker1API());
|
||||
//#else
|
||||
/* Built with the omit-oo1 flag. */
|
||||
//#endif ifnot omit-oo1
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
<link rel="stylesheet" href="common/testing.css"/>
|
||||
<title>sqlite3-api batch SQL runner for the SAHPool VFS</title>
|
||||
</head>
|
||||
<body>
|
||||
<header id='titlebar'><span>sqlite3-api batch SQL runner for the SAHPool VFS</span></header>
|
||||
<div>
|
||||
<span class='input-wrapper'>
|
||||
<input type='checkbox' class='disable-during-eval' id='cb-reverse-log-order' checked></input>
|
||||
<label for='cb-reverse-log-order' id='lbl-reverse-log-order'>Reverse log order</label>
|
||||
</span>
|
||||
</div>
|
||||
<div id='test-output' class='reverse'></div>
|
||||
<script>
|
||||
(function(){
|
||||
const E = (sel)=>document.querySelector(sel);
|
||||
|
||||
const eOut = E('#test-output');
|
||||
const log2 = function(cssClass,...args){
|
||||
let ln;
|
||||
if(1 || cssClass){
|
||||
ln = document.createElement('div');
|
||||
if(cssClass) ln.classList.add(cssClass);
|
||||
ln.append(document.createTextNode(args.join(' ')));
|
||||
}else{
|
||||
// This doesn't work with the "reverse order" option!
|
||||
ln = document.createTextNode(args.join(' ')+'\n');
|
||||
}
|
||||
eOut.append(ln);
|
||||
};
|
||||
const log = (...args)=>{
|
||||
//console.log(...args);
|
||||
log2('', ...args);
|
||||
};
|
||||
const logErr = function(...args){
|
||||
console.error(...args);
|
||||
log2('error', ...args);
|
||||
};
|
||||
const logWarn = function(...args){
|
||||
console.warn(...args);
|
||||
log2('warning', ...args);
|
||||
};
|
||||
|
||||
const cbReverseLog = E('#cb-reverse-log-order');
|
||||
const lblReverseLog = E('#lbl-reverse-log-order');
|
||||
if(cbReverseLog.checked){
|
||||
lblReverseLog.classList.add('warning');
|
||||
eOut.classList.add('reverse');
|
||||
}
|
||||
cbReverseLog.addEventListener('change', function(){
|
||||
if(this.checked){
|
||||
eOut.classList.add('reverse');
|
||||
lblReverseLog.classList.add('warning');
|
||||
}else{
|
||||
eOut.classList.remove('reverse');
|
||||
lblReverseLog.classList.remove('warning');
|
||||
}
|
||||
}, false);
|
||||
|
||||
const w = new Worker('batch-runner-sahpool.js?sqlite3.dir=jswasm');
|
||||
w.onmessage = function(msg){
|
||||
msg = msg.data;
|
||||
switch(msg.type){
|
||||
case 'stdout': log(...msg.data); break;
|
||||
case 'warn': logWarn(...msg.data); break;
|
||||
case 'error': logErr(...msg.data); break;
|
||||
default:
|
||||
logErr("Unhandled worker message type:",msg);
|
||||
break;
|
||||
}
|
||||
};
|
||||
})();
|
||||
</script>
|
||||
<style>
|
||||
#test-output {
|
||||
white-space: break-spaces;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
2023-11-30
|
||||
|
||||
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 basic batch SQL runner for the SAHPool VFS. This file must be run in
|
||||
a worker thread. This is not a full-featured app, just a way to get some
|
||||
measurements for batch execution of SQL for the OPFS SAH Pool VFS.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const wMsg = function(msgType,...args){
|
||||
postMessage({
|
||||
type: msgType,
|
||||
data: args
|
||||
});
|
||||
};
|
||||
const toss = function(...args){throw new Error(args.join(' '))};
|
||||
const warn = (...args)=>{ wMsg('warn',...args); };
|
||||
const error = (...args)=>{ wMsg('error',...args); };
|
||||
const log = (...args)=>{ wMsg('stdout',...args); }
|
||||
let sqlite3;
|
||||
const urlParams = new URL(globalThis.location.href).searchParams;
|
||||
const cacheSize = (()=>{
|
||||
if(urlParams.has('cachesize')) return +urlParams.get('cachesize');
|
||||
return 200;
|
||||
})();
|
||||
|
||||
|
||||
/** Throws if the given sqlite3 result code is not 0. */
|
||||
const checkSqliteRc = (dbh,rc)=>{
|
||||
if(rc) toss("Prepare failed:",sqlite3.capi.sqlite3_errmsg(dbh));
|
||||
};
|
||||
|
||||
const sqlToDrop = [
|
||||
"SELECT type,name FROM sqlite_schema ",
|
||||
"WHERE name NOT LIKE 'sqlite\\_%' escape '\\' ",
|
||||
"AND name NOT LIKE '\\_%' escape '\\'"
|
||||
].join('');
|
||||
|
||||
const clearDbSqlite = function(db){
|
||||
// This would be SO much easier with the oo1 API, but we specifically want to
|
||||
// inject metrics we can't get via that API, and we cannot reliably (OPFS)
|
||||
// open the same DB twice to clear it using that API, so...
|
||||
const rc = sqlite3.wasm.exports.sqlite3_wasm_db_reset(db.handle);
|
||||
log("reset db rc =",rc,db.id, db.filename);
|
||||
};
|
||||
|
||||
const App = {
|
||||
db: undefined,
|
||||
cache:Object.create(null),
|
||||
log: log,
|
||||
warn: warn,
|
||||
error: error,
|
||||
metrics: {
|
||||
fileCount: 0,
|
||||
runTimeMs: 0,
|
||||
prepareTimeMs: 0,
|
||||
stepTimeMs: 0,
|
||||
stmtCount: 0,
|
||||
strcpyMs: 0,
|
||||
sqlBytes: 0
|
||||
},
|
||||
fileList: undefined,
|
||||
execSql: async function(name,sql){
|
||||
const db = this.db;
|
||||
const banner = "========================================";
|
||||
this.log(banner,
|
||||
"Running",name,'('+sql.length,'bytes)');
|
||||
const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
|
||||
let pStmt = 0, pSqlBegin;
|
||||
const metrics = db.metrics = Object.create(null);
|
||||
metrics.prepTotal = metrics.stepTotal = 0;
|
||||
metrics.stmtCount = 0;
|
||||
metrics.malloc = 0;
|
||||
metrics.strcpy = 0;
|
||||
if(this.gotErr){
|
||||
this.error("Cannot run SQL: error cleanup is pending.");
|
||||
return;
|
||||
}
|
||||
// Run this async so that the UI can be updated for the above header...
|
||||
const endRun = ()=>{
|
||||
metrics.evalSqlEnd = performance.now();
|
||||
metrics.evalTimeTotal = (metrics.evalSqlEnd - metrics.evalSqlStart);
|
||||
this.log("metrics:",JSON.stringify(metrics, undefined, ' '));
|
||||
this.log("prepare() count:",metrics.stmtCount);
|
||||
this.log("Time in prepare_v2():",metrics.prepTotal,"ms",
|
||||
"("+(metrics.prepTotal / metrics.stmtCount),"ms per prepare())");
|
||||
this.log("Time in step():",metrics.stepTotal,"ms",
|
||||
"("+(metrics.stepTotal / metrics.stmtCount),"ms per step())");
|
||||
this.log("Total runtime:",metrics.evalTimeTotal,"ms");
|
||||
this.log("Overhead (time - prep - step):",
|
||||
(metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms");
|
||||
this.log(banner,"End of",name);
|
||||
this.metrics.prepareTimeMs += metrics.prepTotal;
|
||||
this.metrics.stepTimeMs += metrics.stepTotal;
|
||||
this.metrics.stmtCount += metrics.stmtCount;
|
||||
this.metrics.strcpyMs += metrics.strcpy;
|
||||
this.metrics.sqlBytes += sql.length;
|
||||
};
|
||||
|
||||
const runner = function(resolve, reject){
|
||||
++this.metrics.fileCount;
|
||||
metrics.evalSqlStart = performance.now();
|
||||
const stack = wasm.scopedAllocPush();
|
||||
try {
|
||||
let t, rc;
|
||||
let sqlByteLen = sql.byteLength;
|
||||
const [ppStmt, pzTail] = wasm.scopedAllocPtr(2);
|
||||
t = performance.now();
|
||||
pSqlBegin = wasm.scopedAlloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed");
|
||||
metrics.malloc = performance.now() - t;
|
||||
metrics.byteLength = sqlByteLen;
|
||||
let pSql = pSqlBegin;
|
||||
const pSqlEnd = pSqlBegin + sqlByteLen;
|
||||
t = performance.now();
|
||||
wasm.heap8().set(sql, pSql);
|
||||
wasm.poke(pSql + sqlByteLen, 0);
|
||||
//log("SQL:",wasm.cstrToJs(pSql));
|
||||
metrics.strcpy = performance.now() - t;
|
||||
let breaker = 0;
|
||||
while(pSql && wasm.peek8(pSql)){
|
||||
wasm.pokePtr(ppStmt, 0);
|
||||
wasm.pokePtr(pzTail, 0);
|
||||
t = performance.now();
|
||||
rc = capi.sqlite3_prepare_v2(
|
||||
db.handle, pSql, sqlByteLen, ppStmt, pzTail
|
||||
);
|
||||
metrics.prepTotal += performance.now() - t;
|
||||
checkSqliteRc(db.handle, rc);
|
||||
pStmt = wasm.peekPtr(ppStmt);
|
||||
pSql = wasm.peekPtr(pzTail);
|
||||
sqlByteLen = pSqlEnd - pSql;
|
||||
if(!pStmt) continue/*empty statement*/;
|
||||
++metrics.stmtCount;
|
||||
t = performance.now();
|
||||
rc = capi.sqlite3_step(pStmt);
|
||||
capi.sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
metrics.stepTotal += performance.now() - t;
|
||||
switch(rc){
|
||||
case capi.SQLITE_ROW:
|
||||
case capi.SQLITE_DONE: break;
|
||||
default: checkSqliteRc(db.handle, rc); toss("Not reached.");
|
||||
}
|
||||
}
|
||||
resolve(this);
|
||||
}catch(e){
|
||||
if(pStmt) capi.sqlite3_finalize(pStmt);
|
||||
this.gotErr = e;
|
||||
reject(e);
|
||||
}finally{
|
||||
capi.sqlite3_exec(db.handle,"rollback;",0,0,0);
|
||||
wasm.scopedAllocPop(stack);
|
||||
}
|
||||
}.bind(this);
|
||||
const p = new Promise(runner);
|
||||
return p.catch(
|
||||
(e)=>this.error("Error via execSql("+name+",...):",e.message)
|
||||
).finally(()=>{
|
||||
endRun();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Loads batch-runner.list and populates the selection list from
|
||||
it. Returns a promise which resolves to nothing in particular
|
||||
when it completes. Only intended to be run once at the start
|
||||
of the app.
|
||||
*/
|
||||
loadSqlList: async function(){
|
||||
const infile = 'batch-runner.list';
|
||||
this.log("Loading list of SQL files:", infile);
|
||||
let txt;
|
||||
try{
|
||||
const r = await fetch(infile);
|
||||
if(404 === r.status){
|
||||
toss("Missing file '"+infile+"'.");
|
||||
}
|
||||
if(!r.ok) toss("Loading",infile,"failed:",r.statusText);
|
||||
txt = await r.text();
|
||||
}catch(e){
|
||||
this.error(e.message);
|
||||
throw e;
|
||||
}
|
||||
App.fileList = txt.split(/\n+/).filter(x=>!!x);
|
||||
this.log("Loaded",infile);
|
||||
},
|
||||
|
||||
/** Fetch ./fn and return its contents as a Uint8Array. */
|
||||
fetchFile: async function(fn, cacheIt=false){
|
||||
if(cacheIt && this.cache[fn]) return this.cache[fn];
|
||||
this.log("Fetching",fn,"...");
|
||||
let sql;
|
||||
try {
|
||||
const r = await fetch(fn);
|
||||
if(!r.ok) toss("Fetch failed:",r.statusText);
|
||||
sql = new Uint8Array(await r.arrayBuffer());
|
||||
}catch(e){
|
||||
this.error(e.message);
|
||||
throw e;
|
||||
}
|
||||
this.log("Fetched",sql.length,"bytes from",fn);
|
||||
if(cacheIt) this.cache[fn] = sql;
|
||||
return sql;
|
||||
}/*fetchFile()*/,
|
||||
|
||||
/**
|
||||
Converts this.metrics() to a form which is suitable for easy conversion to
|
||||
CSV. It returns an array of arrays. The first sub-array is the column names.
|
||||
The 2nd and subsequent are the values, one per test file (only the most recent
|
||||
metrics are kept for any given file).
|
||||
*/
|
||||
metricsToArrays: function(){
|
||||
const rc = [];
|
||||
Object.keys(this.dbs).sort().forEach((k)=>{
|
||||
const d = this.dbs[k];
|
||||
const m = d.metrics;
|
||||
delete m.evalSqlStart;
|
||||
delete m.evalSqlEnd;
|
||||
const mk = Object.keys(m).sort();
|
||||
if(!rc.length){
|
||||
rc.push(['db', ...mk]);
|
||||
}
|
||||
const row = [k.split('/').pop()/*remove dir prefix from filename*/];
|
||||
rc.push(row);
|
||||
row.push(...mk.map((kk)=>m[kk]));
|
||||
});
|
||||
return rc;
|
||||
},
|
||||
|
||||
metricsToBlob: function(colSeparator='\t'){
|
||||
const ar = [], ma = this.metricsToArrays();
|
||||
if(!ma.length){
|
||||
this.error("Metrics are empty. Run something.");
|
||||
return;
|
||||
}
|
||||
ma.forEach(function(row){
|
||||
ar.push(row.join(colSeparator),'\n');
|
||||
});
|
||||
return new Blob(ar);
|
||||
},
|
||||
|
||||
/**
|
||||
Fetch file fn and eval it as an SQL blob. This is an async
|
||||
operation and returns a Promise which resolves to this
|
||||
object on success.
|
||||
*/
|
||||
evalFile: async function(fn){
|
||||
const sql = await this.fetchFile(fn);
|
||||
return this.execSql(fn,sql);
|
||||
}/*evalFile()*/,
|
||||
|
||||
/**
|
||||
Fetches the handle of the db associated with
|
||||
this.e.selImpl.value, opening it if needed.
|
||||
*/
|
||||
initDb: function(){
|
||||
const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
|
||||
const stack = wasm.scopedAllocPush();
|
||||
let pDb = 0;
|
||||
const d = Object.create(null);
|
||||
d.filename = "/batch.db";
|
||||
try{
|
||||
const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
|
||||
const ppDb = wasm.scopedAllocPtr();
|
||||
const rc = capi.sqlite3_open_v2(d.filename, ppDb, oFlags, this.PoolUtil.vfsName);
|
||||
pDb = wasm.peekPtr(ppDb)
|
||||
if(rc) toss("sqlite3_open_v2() failed with code",rc);
|
||||
capi.sqlite3_exec(pDb, "PRAGMA cache_size="+cacheSize, 0, 0, 0);
|
||||
this.log("cache_size =",cacheSize);
|
||||
}catch(e){
|
||||
if(pDb) capi.sqlite3_close_v2(pDb);
|
||||
throw e;
|
||||
}finally{
|
||||
wasm.scopedAllocPop(stack);
|
||||
}
|
||||
d.handle = pDb;
|
||||
this.log("Opened db:",d.filename,'@',d.handle);
|
||||
return d;
|
||||
},
|
||||
|
||||
closeDb: function(){
|
||||
if(this.db.handle){
|
||||
this.sqlite3.capi.sqlite3_close_v2(this.db.handle);
|
||||
this.db.handle = undefined;
|
||||
}
|
||||
},
|
||||
|
||||
run: async function(sqlite3){
|
||||
delete this.run;
|
||||
this.sqlite3 = sqlite3;
|
||||
const capi = sqlite3.capi, wasm = sqlite3.wasm;
|
||||
this.log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
|
||||
this.log("WASM heap size =",wasm.heap8().length);
|
||||
let timeStart;
|
||||
sqlite3.installOpfsSAHPoolVfs({
|
||||
clearOnInit: true, initialCapacity: 4,
|
||||
name: 'batch-sahpool',
|
||||
verbosity: 2
|
||||
}).then(PoolUtil=>{
|
||||
App.PoolUtil = PoolUtil;
|
||||
App.db = App.initDb();
|
||||
})
|
||||
.then(async ()=>this.loadSqlList())
|
||||
.then(async ()=>{
|
||||
timeStart = performance.now();
|
||||
for(let i = 0; i < App.fileList.length; ++i){
|
||||
const fn = App.fileList[i];
|
||||
await App.evalFile(fn);
|
||||
if(App.gotErr) throw App.gotErr;
|
||||
}
|
||||
})
|
||||
.then(()=>{
|
||||
App.metrics.runTimeMs = performance.now() - timeStart;
|
||||
App.log("total metrics:",JSON.stringify(App.metrics, undefined, ' '));
|
||||
App.log("Reload the page to run this again.");
|
||||
App.closeDb();
|
||||
App.PoolUtil.removeVfs();
|
||||
})
|
||||
.catch(e=>this.error("ERROR:",e));
|
||||
}/*run()*/
|
||||
}/*App*/;
|
||||
|
||||
let sqlite3Js = 'sqlite3.js';
|
||||
if(urlParams.has('sqlite3.dir')){
|
||||
sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
|
||||
}
|
||||
importScripts(sqlite3Js);
|
||||
globalThis.sqlite3InitModule().then(async function(sqlite3_){
|
||||
log("Done initializing. Running batch runner...");
|
||||
sqlite3 = sqlite3_;
|
||||
App.run(sqlite3_);
|
||||
});
|
||||
@@ -72,7 +72,6 @@
|
||||
App.logHtml("reset db rc =",rc,db.id, db.filename);
|
||||
};
|
||||
|
||||
|
||||
const E = (s)=>document.querySelector(s);
|
||||
const App = {
|
||||
e: {
|
||||
@@ -91,6 +90,15 @@
|
||||
db: Object.create(null),
|
||||
dbs: Object.create(null),
|
||||
cache:{},
|
||||
metrics: {
|
||||
fileCount: 0,
|
||||
runTimeMs: 0,
|
||||
prepareTimeMs: 0,
|
||||
stepTimeMs: 0,
|
||||
stmtCount: 0,
|
||||
strcpyMs: 0,
|
||||
sqlBytes: 0
|
||||
},
|
||||
log: console.log.bind(console),
|
||||
warn: console.warn.bind(console),
|
||||
cls: function(){this.e.output.innerHTML = ''},
|
||||
@@ -117,7 +125,6 @@
|
||||
"Running",name,'('+sql.length,'bytes) using',db.id);
|
||||
const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
|
||||
let pStmt = 0, pSqlBegin;
|
||||
const stack = wasm.scopedAllocPush();
|
||||
const metrics = db.metrics = Object.create(null);
|
||||
metrics.prepTotal = metrics.stepTotal = 0;
|
||||
metrics.stmtCount = 0;
|
||||
@@ -142,6 +149,11 @@
|
||||
this.logHtml("Overhead (time - prep - step):",
|
||||
(metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms");
|
||||
this.logHtml(banner,"End of",name);
|
||||
this.metrics.prepareTimeMs += metrics.prepTotal;
|
||||
this.metrics.stepTimeMs += metrics.stepTotal;
|
||||
this.metrics.stmtCount += metrics.stmtCount;
|
||||
this.metrics.strcpyMs += metrics.strcpy;
|
||||
this.metrics.sqlBytes += sql.length;
|
||||
};
|
||||
|
||||
let runner;
|
||||
@@ -214,7 +226,9 @@
|
||||
}.bind(this);
|
||||
}else{/*sqlite3 db...*/
|
||||
runner = function(resolve, reject){
|
||||
++this.metrics.fileCount;
|
||||
metrics.evalSqlStart = performance.now();
|
||||
const stack = wasm.scopedAllocPush();
|
||||
try {
|
||||
let t;
|
||||
let sqlByteLen = sql.byteLength;
|
||||
@@ -269,7 +283,7 @@
|
||||
let p;
|
||||
if(1){
|
||||
p = new Promise(function(res,rej){
|
||||
setTimeout(()=>runner(res, rej), 50)/*give UI a chance to output the "running" banner*/;
|
||||
setTimeout(()=>runner(res, rej), 0)/*give UI a chance to output the "running" banner*/;
|
||||
});
|
||||
}else{
|
||||
p = new Promise(runner);
|
||||
@@ -401,7 +415,7 @@
|
||||
});
|
||||
return new Blob(ar);
|
||||
},
|
||||
|
||||
|
||||
downloadMetrics: function(){
|
||||
const b = this.metricsToBlob();
|
||||
if(!b) return;
|
||||
@@ -576,6 +590,8 @@
|
||||
const timeTotal = performance.now() - timeStart;
|
||||
who.logHtml("Run-remaining time:",timeTotal,"ms ("+(timeTotal/1000/60)+" minute(s))");
|
||||
who.clearStorage();
|
||||
App.metrics.runTimeMs = timeTotal;
|
||||
who.logHtml("Total metrics:",JSON.stringify(App.metrics,undefined,' '));
|
||||
}, false);
|
||||
}/*run()*/
|
||||
}/*App*/;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
the main (UI) thread.
|
||||
*/
|
||||
let logHtml;
|
||||
if(self.window === self /* UI thread */){
|
||||
if(globalThis.window === globalThis /* UI thread */){
|
||||
console.log("Running demo from main UI thread.");
|
||||
logHtml = function(cssClass,...args){
|
||||
const ln = document.createElement('div');
|
||||
@@ -250,7 +250,7 @@
|
||||
}/*demo1()*/;
|
||||
|
||||
log("Loading and initializing sqlite3 module...");
|
||||
if(self.window!==self) /*worker thread*/{
|
||||
if(globalThis.window!==globalThis) /*worker thread*/{
|
||||
/*
|
||||
If sqlite3.js is in a directory other than this script, in order
|
||||
to get sqlite3.js to resolve sqlite3.wasm properly, we have to
|
||||
@@ -262,19 +262,20 @@
|
||||
that's not needed.
|
||||
|
||||
URL arguments passed as part of the filename via importScripts()
|
||||
are simply lost, and such scripts see the self.location of
|
||||
are simply lost, and such scripts see the globalThis.location of
|
||||
_this_ script.
|
||||
*/
|
||||
let sqlite3Js = 'sqlite3.js';
|
||||
const urlParams = new URL(self.location.href).searchParams;
|
||||
const urlParams = new URL(globalThis.location.href).searchParams;
|
||||
if(urlParams.has('sqlite3.dir')){
|
||||
sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
|
||||
}
|
||||
importScripts(sqlite3Js);
|
||||
}
|
||||
self.sqlite3InitModule({
|
||||
// We can redirect any stdout/stderr from the module
|
||||
// like so...
|
||||
globalThis.sqlite3InitModule({
|
||||
/* We can redirect any stdout/stderr from the module like so, but
|
||||
note that doing so makes use of Emscripten-isms, not
|
||||
well-defined sqlite APIs. */
|
||||
print: log,
|
||||
printErr: error
|
||||
}).then(function(sqlite3){
|
||||
|
||||
@@ -374,9 +374,7 @@
|
||||
"for use in the dev console.", sqlite3);
|
||||
globalThis.sqlite3 = sqlite3;
|
||||
const dbVfs = sqlite3.wasm.xWrap('fiddle_db_vfs', "*", ['string']);
|
||||
fiddleModule.fsUnlink = (fn)=>{
|
||||
return sqlite3.wasm.sqlite3_wasm_vfs_unlink(dbVfs(0), fn);
|
||||
};
|
||||
fiddleModule.fsUnlink = (fn)=>fiddleModule.FS.unlink(fn);
|
||||
wMsg('fiddle-ready');
|
||||
}).catch(e=>{
|
||||
console.error("Fiddle worker init failed:",e);
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
file:// URLs.</li>
|
||||
<li>Any OPFS-related pages or tests require:
|
||||
<ul>
|
||||
<li>An OPFS-capable browser released after February
|
||||
2023. Some tests will work with Chromium-based browsers
|
||||
going back to around v102.</li>
|
||||
<li>That the web server emit the so-called
|
||||
<a href='https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy'>COOP</a>
|
||||
and
|
||||
@@ -53,12 +56,6 @@
|
||||
headers. <a href='https://sqlite.org/althttpd'>althttpd</a> requires the
|
||||
<code>-enable-sab</code> flag for that.
|
||||
</li>
|
||||
<li>A very recent version of a Chromium-based browser
|
||||
(v102 at least, possibly newer). OPFS support in the
|
||||
other major browsers is pending. Development and testing
|
||||
is currently done against a dev-channel release of
|
||||
Chrome (v111 as of 2023-02-10).
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
+3
-6
@@ -31,6 +31,9 @@
|
||||
file:// URLs.</li>
|
||||
<li>Any OPFS-related pages or tests require:
|
||||
<ul>
|
||||
<li>An OPFS-capable browser released after February
|
||||
2023. Some tests will work with Chromium-based browsers
|
||||
going back to around v102.</li>
|
||||
<li>That the web server emit the so-called
|
||||
<a href='https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy'>COOP</a>
|
||||
and
|
||||
@@ -38,12 +41,6 @@
|
||||
headers. <a href='https://sqlite.org/althttpd'>althttpd</a> requires the
|
||||
<code>-enable-sab</code> flag for that.
|
||||
</li>
|
||||
<li>A very recent version of a
|
||||
Chromium-based browser (v102 at least, possibly newer). OPFS
|
||||
support in the other major browsers is pending. Development
|
||||
and testing is currently done against a dev-channel release
|
||||
of Chrome (v111 as of 2023-02-10).
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -206,9 +206,8 @@ const MyBinder = StructBinderFactory({
|
||||
It also offers a number of other settings, but all are optional except
|
||||
for the ones shown above. Those three config options abstract away
|
||||
details which are specific to a given WASM environment. They provide
|
||||
the WASM "heap" memory (a byte array), the memory allocator, and the
|
||||
deallocator. In a conventional Emscripten setup, that config might
|
||||
simply look like:
|
||||
the WASM "heap" memory, the memory allocator, and the deallocator. In
|
||||
a conventional Emscripten setup, that config might simply look like:
|
||||
|
||||
>
|
||||
```javascript
|
||||
|
||||
@@ -350,7 +350,7 @@
|
||||
eControls.classList.remove('hidden');
|
||||
break;
|
||||
case 'stdout': log(msg.data); break;
|
||||
case 'stdout': logErr(msg.data); break;
|
||||
case 'stderr': logErr(msg.data); break;
|
||||
case 'run-start':
|
||||
eControls.disabled = true;
|
||||
log("Running speedtest1 with argv =",msg.data.join(' '));
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
}
|
||||
importScripts(speedtestJs);
|
||||
/**
|
||||
If this environment contains OPFS, this function initializes it and
|
||||
returns the name of the dir on which OPFS is mounted, else it returns
|
||||
an empty string.
|
||||
If this build includes WASMFS, this function initializes it and
|
||||
returns the name of the dir on which OPFS is mounted, else it
|
||||
returns an empty string.
|
||||
*/
|
||||
const wasmfsDir = function f(wasmUtil){
|
||||
if(undefined !== f._) return f._;
|
||||
@@ -47,6 +47,7 @@
|
||||
};
|
||||
const log = (...args)=>logMsg('stdout',args);
|
||||
const logErr = (...args)=>logMsg('stderr',args);
|
||||
const realSahName = 'opfs-sahpool-speedtest1';
|
||||
|
||||
const runSpeedtest = async function(cliFlagsArray){
|
||||
const scope = App.wasm.scopedAllocPush();
|
||||
@@ -57,7 +58,6 @@
|
||||
];
|
||||
App.logBuffer.length = 0;
|
||||
const ndxSahPool = argv.indexOf('opfs-sahpool');
|
||||
const realSahName = 'opfs-sahpool-speedtest1';
|
||||
if(ndxSahPool>0){
|
||||
argv[ndxSahPool] = realSahName;
|
||||
log("Updated argv for opfs-sahpool: --vfs",realSahName);
|
||||
@@ -73,7 +73,7 @@
|
||||
clearOnInit: true,
|
||||
verbosity: 2
|
||||
}).then(PoolUtil=>{
|
||||
log("opfs-sahpool successfully installed as",realSahName);
|
||||
log("opfs-sahpool successfully installed as",PoolUtil.vfsName);
|
||||
App.sqlite3.$SAHPoolUtil = PoolUtil;
|
||||
//console.log("sqlite3.oo1.OpfsSAHPoolDb =", App.sqlite3.oo1.OpfsSAHPoolDb);
|
||||
});
|
||||
@@ -102,19 +102,6 @@
|
||||
}
|
||||
};
|
||||
|
||||
const sahpSanityChecks = function(sqlite3){
|
||||
log("Attempting OpfsSAHPoolDb sanity checks...");
|
||||
const db = new sqlite3.oo1.OpfsSAHPoolDb('opfs-sahpoool.db');
|
||||
const fn = db.filename;
|
||||
db.exec([
|
||||
'create table t(a);',
|
||||
'insert into t(a) values(1),(2),(3);'
|
||||
]);
|
||||
db.close();
|
||||
sqlite3.wasm.sqlite3_wasm_vfs_unlink(sqlite3_vfs_find("opfs-sahpool"), fn);
|
||||
log("SAH sanity checks done.");
|
||||
};
|
||||
|
||||
const EmscriptenModule = {
|
||||
print: log,
|
||||
printErr: logErr,
|
||||
@@ -124,10 +111,6 @@
|
||||
self.sqlite3InitModule(EmscriptenModule).then(async (sqlite3)=>{
|
||||
const S = globalThis.S = App.sqlite3 = sqlite3;
|
||||
log("Loaded speedtest1 module. Setting up...");
|
||||
App.vfsUnlink = function(pDb, fname){
|
||||
const pVfs = S.wasm.sqlite3_wasm_db_vfs(pDb, 0);
|
||||
if(pVfs) S.wasm.sqlite3_wasm_vfs_unlink(pVfs, fname||0);
|
||||
};
|
||||
App.pDir = wasmfsDir(S.wasm);
|
||||
App.wasm = S.wasm;
|
||||
//if(App.pDir) log("Persistent storage:",pDir);
|
||||
|
||||
+22
-21
@@ -63,7 +63,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
/* Predicate for tests/groups. */
|
||||
const testIsTodo = ()=>false;
|
||||
const haveWasmCTests = ()=>{
|
||||
return !!wasm.exports.sqlite3_wasm_test_intptr;
|
||||
return !!wasm.exports.sqlite3__wasm_test_intptr;
|
||||
};
|
||||
const hasOpfs = ()=>{
|
||||
return globalThis.FileSystemHandle
|
||||
@@ -722,7 +722,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
|
||||
//log("xCall()...");
|
||||
{
|
||||
const pJson = w.xCall('sqlite3_wasm_enum_json');
|
||||
const pJson = w.xCall('sqlite3__wasm_enum_json');
|
||||
T.assert(Number.isFinite(pJson)).assert(w.cstrlen(pJson)>300);
|
||||
}
|
||||
|
||||
@@ -736,9 +736,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
T.mustThrowMatching(()=>fw(1), /requires 0 arg/);
|
||||
let rc = fw();
|
||||
T.assert('string'===typeof rc).assert(rc.length>5);
|
||||
rc = w.xCallWrapped('sqlite3_wasm_enum_json','*');
|
||||
rc = w.xCallWrapped('sqlite3__wasm_enum_json','*');
|
||||
T.assert(rc>0 && Number.isFinite(rc));
|
||||
rc = w.xCallWrapped('sqlite3_wasm_enum_json','utf8');
|
||||
rc = w.xCallWrapped('sqlite3__wasm_enum_json','utf8');
|
||||
T.assert('string'===typeof rc).assert(rc.length>300);
|
||||
|
||||
|
||||
@@ -821,7 +821,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
|
||||
if(haveWasmCTests()){
|
||||
if(!sqlite3.config.useStdAlloc){
|
||||
fw = w.xWrap('sqlite3_wasm_test_str_hello', 'utf8:dealloc',['i32']);
|
||||
fw = w.xWrap('sqlite3__wasm_test_str_hello', 'utf8:dealloc',['i32']);
|
||||
rc = fw(0);
|
||||
T.assert('hello'===rc);
|
||||
rc = fw(1);
|
||||
@@ -831,14 +831,14 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
if(w.bigIntEnabled){
|
||||
w.xWrap.resultAdapter('thrice', (v)=>3n*BigInt(v));
|
||||
w.xWrap.argAdapter('twice', (v)=>2n*BigInt(v));
|
||||
fw = w.xWrap('sqlite3_wasm_test_int64_times2','thrice','twice');
|
||||
fw = w.xWrap('sqlite3__wasm_test_int64_times2','thrice','twice');
|
||||
rc = fw(1);
|
||||
T.assert(12n===rc);
|
||||
|
||||
w.scopedAllocCall(function(){
|
||||
const pI1 = w.scopedAlloc(8), pI2 = pI1+4;
|
||||
w.pokePtr([pI1, pI2], 0);
|
||||
const f = w.xWrap('sqlite3_wasm_test_int64_minmax',undefined,['i64*','i64*']);
|
||||
const f = w.xWrap('sqlite3__wasm_test_int64_minmax',undefined,['i64*','i64*']);
|
||||
const [r1, r2] = w.peek64([pI1, pI2]);
|
||||
T.assert(!Number.isSafeInteger(r1)).assert(!Number.isSafeInteger(r2));
|
||||
});
|
||||
@@ -942,7 +942,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
assert(wts.pointer>0).assert(0===wts.$v4).assert(0n===wts.$v8).
|
||||
assert(0===wts.$ppV).assert(0===wts.$xFunc);
|
||||
const testFunc =
|
||||
W.xGet('sqlite3_wasm_test_struct'/*name gets mangled in -O3 builds!*/);
|
||||
W.xGet('sqlite3__wasm_test_struct'/*name gets mangled in -O3 builds!*/);
|
||||
let counter = 0;
|
||||
//log("wts.pointer =",wts.pointer);
|
||||
const wtsFunc = function(arg){
|
||||
@@ -1128,7 +1128,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
T.g('sqlite3.oo1')
|
||||
.t('Create db', function(sqlite3){
|
||||
const dbFile = '/tester1.db';
|
||||
wasm.sqlite3_wasm_vfs_unlink(0, dbFile);
|
||||
sqlite3.util.sqlite3__wasm_vfs_unlink(0, dbFile);
|
||||
const db = this.db = new sqlite3.oo1.DB(dbFile, 0 ? 'ct' : 'c');
|
||||
db.onclose = {
|
||||
disposeAfter: [],
|
||||
@@ -1459,7 +1459,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
rv = db.exec("SELECT 1 WHERE 0",{rowMode: 0});
|
||||
T.assert(Array.isArray(rv)).assert(0===rv.length);
|
||||
if(wasm.bigIntEnabled && haveWasmCTests()){
|
||||
const mI = wasm.xCall('sqlite3_wasm_test_int64_max');
|
||||
const mI = wasm.xCall('sqlite3__wasm_test_int64_max');
|
||||
const b = BigInt(Number.MAX_SAFE_INTEGER * 2);
|
||||
T.assert(b === db.selectValue("SELECT "+b)).
|
||||
assert(b === db.selectValue("SELECT ?", b)).
|
||||
@@ -1685,7 +1685,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
T.assert(n>0 && db2.selectValue(sql) === n);
|
||||
}finally{
|
||||
db2.close();
|
||||
wasm.sqlite3_wasm_vfs_unlink(0, filename);
|
||||
sqlite3.util.sqlite3__wasm_vfs_unlink(0, filename);
|
||||
}
|
||||
}
|
||||
}/*sqlite3_js_posix_create_file()*/)
|
||||
@@ -2075,7 +2075,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
try{
|
||||
ptrInt = w.scopedAlloc(4);
|
||||
w.poke32(ptrInt,origValue);
|
||||
const cf = w.xGet('sqlite3_wasm_test_intptr');
|
||||
const cf = w.xGet('sqlite3__wasm_test_intptr');
|
||||
const oldPtrInt = ptrInt;
|
||||
T.assert(origValue === w.peek32(ptrInt));
|
||||
const rc = cf(ptrInt);
|
||||
@@ -2090,13 +2090,13 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
const v64 = ()=>w.peek64(pi64)
|
||||
T.assert(v64() == o64);
|
||||
//T.assert(o64 === w.peek64(pi64));
|
||||
const cf64w = w.xGet('sqlite3_wasm_test_int64ptr');
|
||||
const cf64w = w.xGet('sqlite3__wasm_test_int64ptr');
|
||||
cf64w(pi64);
|
||||
T.assert(v64() == BigInt(2 * o64));
|
||||
cf64w(pi64);
|
||||
T.assert(v64() == BigInt(4 * o64));
|
||||
|
||||
const biTimes2 = w.xGet('sqlite3_wasm_test_int64_times2');
|
||||
const biTimes2 = w.xGet('sqlite3__wasm_test_int64_times2');
|
||||
T.assert(BigInt(2 * o64) ===
|
||||
biTimes2(BigInt(o64)/*explicit conv. required to avoid TypeError
|
||||
in the call :/ */));
|
||||
@@ -2106,13 +2106,13 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
const g64 = (p)=>w.peek64(p);
|
||||
w.poke64([pMin, pMax], 0);
|
||||
const minMaxI64 = [
|
||||
w.xCall('sqlite3_wasm_test_int64_min'),
|
||||
w.xCall('sqlite3_wasm_test_int64_max')
|
||||
w.xCall('sqlite3__wasm_test_int64_min'),
|
||||
w.xCall('sqlite3__wasm_test_int64_max')
|
||||
];
|
||||
T.assert(minMaxI64[0] < BigInt(Number.MIN_SAFE_INTEGER)).
|
||||
assert(minMaxI64[1] > BigInt(Number.MAX_SAFE_INTEGER));
|
||||
//log("int64_min/max() =",minMaxI64, typeof minMaxI64[0]);
|
||||
w.xCall('sqlite3_wasm_test_int64_minmax', pMin, pMax);
|
||||
w.xCall('sqlite3__wasm_test_int64_minmax', pMin, pMax);
|
||||
T.assert(g64(pMin) === minMaxI64[0], "int64 mismatch").
|
||||
assert(g64(pMax) === minMaxI64[1], "int64 mismatch");
|
||||
//log("pMin",g64(pMin), "pMax",g64(pMax));
|
||||
@@ -2560,7 +2560,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
.t('Close db', function(){
|
||||
T.assert(this.db).assert(wasm.isPtr(this.db.pointer));
|
||||
//wasm.sqlite3_wasm_db_reset(this.db); // will leak virtual tables!
|
||||
//wasm.sqlite3__wasm_db_reset(this.db); // will leak virtual tables!
|
||||
this.db.close();
|
||||
T.assert(!this.db.pointer);
|
||||
})
|
||||
@@ -2892,7 +2892,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
const pVfs = this.opfsVfs = capi.sqlite3_vfs_find('opfs');
|
||||
T.assert(pVfs);
|
||||
const unlink = this.opfsUnlink =
|
||||
(fn=filename)=>{wasm.sqlite3_wasm_vfs_unlink(pVfs,fn)};
|
||||
(fn=filename)=>{sqlite3.util.sqlite3__wasm_vfs_unlink(pVfs,fn)};
|
||||
unlink();
|
||||
let db = new sqlite3.oo1.OpfsDb(filename);
|
||||
try {
|
||||
@@ -3209,6 +3209,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
print: log,
|
||||
printErr: error
|
||||
}).then(async function(sqlite3){
|
||||
TestUtil.assert(!!sqlite3.util);
|
||||
log("Done initializing WASM/JS bits. Running tests...");
|
||||
sqlite3.config.warn("Installing sqlite3 bits as global S for local dev/test purposes.");
|
||||
globalThis.S = sqlite3;
|
||||
@@ -3227,9 +3228,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
logClass('warning',"BigInt/int64 support is disabled.");
|
||||
}
|
||||
if(haveWasmCTests()){
|
||||
log("sqlite3_wasm_test_...() APIs are available.");
|
||||
log("sqlite3__wasm_test_...() APIs are available.");
|
||||
}else{
|
||||
logClass('warning',"sqlite3_wasm_test_...() APIs unavailable.");
|
||||
logClass('warning',"sqlite3__wasm_test_...() APIs unavailable.");
|
||||
}
|
||||
log("registered vfs list =",capi.sqlite3_js_vfs_list().join(', '));
|
||||
TestUtil.runTests(sqlite3);
|
||||
|
||||
@@ -360,6 +360,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/prefixes.c \
|
||||
$(TOP)/ext/misc/qpvtab.c \
|
||||
$(TOP)/ext/misc/randomjson.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
$(TOP)/ext/misc/series.c \
|
||||
@@ -526,12 +527,15 @@ FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
FUZZCHECK_OPT += -DSQLITE_STRICT_SUBTYPE=1
|
||||
FUZZCHECK_OPT += -DSQLITE_STATIC_RANDOMJSON
|
||||
FUZZSRC += $(TOP)/test/fuzzcheck.c
|
||||
FUZZSRC += $(TOP)/test/ossfuzz.c
|
||||
FUZZSRC += $(TOP)/test/vt02.c
|
||||
FUZZSRC += $(TOP)/test/fuzzinvariants.c
|
||||
FUZZSRC += $(TOP)/ext/recover/dbdata.c
|
||||
FUZZSRC += $(TOP)/ext/recover/sqlite3recover.c
|
||||
FUZZSRC += $(TOP)/ext/misc/randomjson.c
|
||||
DBFUZZ_OPT =
|
||||
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
ST_OPT = -DSQLITE_THREADSAFE=0
|
||||
@@ -898,6 +902,8 @@ TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_STATIC_RANDOMJSON
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_STRICT_SUBTYPE=1
|
||||
|
||||
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C All\slegacy\stests\sare\spassing.
|
||||
D 2023-11-28T13:35:53.633
|
||||
C wasm\sbuild:\sreformulate\san\sawk\sinvocation\sto\saccount\sfor\sawks\swhich\sdo\snot\ssupport\sthe\s-e\sflag.\sProblem\sreported\son\sthe\sforum\svia\sa\sdocker-hosted\sbuild.
|
||||
D 2024-01-11T16:10:22.408
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 890caf094636c308bc981032baf8f9208bf307755f9197ae4218a9fbcec2e449
|
||||
F Makefile.in 24be65ae641c5727bbc247d60286a15ecc24fb80f14f8fb2d32533bf0ec96e79
|
||||
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
|
||||
F Makefile.msc 59bb36dba001f0b38212be0794fb838f25371008b180929bcf08aa799694c168
|
||||
F README.md 963d30019abf0cc06b263cd2824bce022893f3f93a531758f6f04ff2194a16a8
|
||||
F Makefile.msc df56c06ef05add5ebcdcc9d4823fb2ec66ac16b06acb6971a7420859025886fa
|
||||
F README.md 6358805260a03ebead84e168bbf3740ddf3f683b477e478567186aa7afb490d3
|
||||
F VERSION 73573d4545343f001bf5dc5461173a7c78c203dd046cabcf99153878cf25d3a6
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -15,7 +15,7 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am adedc1324b6a87fdd1265ddd336d2fb7d4f36a0e77b86ea553ae7cc4ea239347
|
||||
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
|
||||
F autoconf/Makefile.msc 34f8c222846db1b354720c8a78a4fa7dec9176ea447c0fffdf442b7f74e8b1df
|
||||
F autoconf/Makefile.msc ac338c36a338f6b49475da71930f45145a181d6b551578d5a7a64f113ef27b2c
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 42cfd21d0b19dc7d5d85fb5c405c5f3c6a4c923021c39128f6ba685355d8fd56
|
||||
F autoconf/configure.ac ec7fa914c5e74ff212fe879f9bb6918e1234497e05facfb641f30c4d5893b277
|
||||
@@ -39,9 +39,10 @@ F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/compile-for-windows.md 50b27d77be96195c66031a3181cb8684ed822327ea834e07f9c014213e5e3bcf
|
||||
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
|
||||
F doc/jsonb.md 5fab4b8613aa9153fbeb6259297bd4697988af8b3d23900deba588fa7841456b
|
||||
F doc/lemon.html 44a53a1d2b42d7751f7b2f478efb23c978e258d794bfd172442307a755b9fa44
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/testrunner.md 2434864be2219d4f0b6ffc99d0a2172d531c4ca4345340776f67ad4edd90dc90
|
||||
F doc/testrunner.md 8d36ec692cf4994bb66d84a4645b9afa1ce9d47dc12cbf8d437c5a5fb6ddeedb
|
||||
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
|
||||
F doc/vdbesort-memory.md 4da2639c14cd24a31e0af694b1a8dd37eaf277aff3867e9a8cc14046bc49df56
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
@@ -50,8 +51,8 @@ F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
|
||||
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
|
||||
F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad1aff3294f94
|
||||
F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
|
||||
F ext/consio/console_io.c 097323f60037d70523421f0248958d2280851f8ff2f9a443d4ee1474c4769118 x
|
||||
F ext/consio/console_io.h 3228dff1717481202a24f6dcf45ce0b75e7a778bf6877089518a44e1473b76a3
|
||||
F ext/consio/console_io.c e1be639e79e54264b3ae97ca291728987a9aa82e6a4526458e6400f5e083e524 x
|
||||
F ext/consio/console_io.h 0548b83d7c4b7270ad544a67f2bb90cebc519637fa39b1838df4744cf0d87646
|
||||
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
|
||||
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
|
||||
F ext/expert/expert1.test 0dd5cb096d66bed593e33053a3b364f6ef52ed72064bf5cf298364636dbf3cd6
|
||||
@@ -88,28 +89,28 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
|
||||
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
|
||||
F ext/fts3/unicode/mkunicode.tcl d5aebf022fa4577ee8cdf27468f0d847879993959101f6dbd6348ef0cfc324a7
|
||||
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h 05501612cc655504c5dce8ba765ab621d50fc478490089beaa0d75e00b23e520
|
||||
F ext/fts5/fts5Int.h 78a63cc0795186cde5384816a9403a68c65774b35d952e05b81a1b4b158e07c8
|
||||
F ext/fts5/fts5_aux.c ee770eec0af8646db9e18fc01a0dad7345b5f5e8cbba236704cfae2d777022ad
|
||||
F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b729225eeaf6a5
|
||||
F ext/fts5/fts5_config.c 054359543566cbff1ba65a188330660a5457299513ac71c53b3a07d934c7b081
|
||||
F ext/fts5/fts5_expr.c bd3b81ce669c4104e34ffe66570af1999a317b142c15fccb112de9fb0caa57a6
|
||||
F ext/fts5/fts5_hash.c 076058f93327051952a752dc765df1acfe783eb11b419b30652aa1fc1f987902
|
||||
F ext/fts5/fts5_index.c 458cbed8a3e17617cbf7e80cdfb7612000b9bb3781f286b345fb9655858658cf
|
||||
F ext/fts5/fts5_main.c a07ed863b8bd9e6fefb62db2fd40a3518eb30a5f7dcfda5be915dd2db45efa2f
|
||||
F ext/fts5/fts5_storage.c 5d10b9bdcce5b90656cad13c7d12ad4148677d4b9e3fca0481fca56d6601426d
|
||||
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
|
||||
F ext/fts5/extract_api_docs.tcl bc3a0ca78be7d3df08e7602c00ca48021ebae40682d75eb001bfdf6e54ffb44e
|
||||
F ext/fts5/fts5.h ecba24fed7b359b3a53016bb07e411b3b4c9cdf163aa141006536423a63b611e
|
||||
F ext/fts5/fts5Int.h defa43c0932265138ee910ca416e6baccf8b774e0f3d610e74be1ab2880e9834
|
||||
F ext/fts5/fts5_aux.c 4584e88878e54828bf7d4d0d83deedd232ec60628b7731be02bad6adb62304b1
|
||||
F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70673cb6f09
|
||||
F ext/fts5/fts5_config.c 8072a207034b51ae9b7694121d1b5715c794e94b275e088f70ae532378ca5cdf
|
||||
F ext/fts5/fts5_expr.c e91156ebdcc08d837f4f324168f69f3c0d7fdef0e521fd561efb48ef3297b696
|
||||
F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1
|
||||
F ext/fts5/fts5_index.c bb1965c3965f6fe5f64160bf1c0694a9684a790a783f293a76da1d38d319b258
|
||||
F ext/fts5/fts5_main.c 1c6c7df07fd0d8b37548887dcdc00a8cc31fd1dc13bf9091f3350a9f23e6353c
|
||||
F ext/fts5/fts5_storage.c f9e31b0d155e9b2c92d5d3a09ad7a56b937fbf1c7f962e10f4ca6281349f3934
|
||||
F ext/fts5/fts5_tcl.c cf0fd0dbe64ec272491b749e0d594f563cda03336aeb60900129e6d18b0aefb8
|
||||
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
|
||||
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
|
||||
F ext/fts5/fts5_tokenize.c 83cfcede3898001cab84432a36ce1503e3080cf9b1c682b022ec82e267ea4c13
|
||||
F ext/fts5/fts5_unicode2.c eca63dbc797f8ff0572e97caf4631389c0ab900d6364861b915bdd4735973f00
|
||||
F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d09885d1dadf80
|
||||
F ext/fts5/fts5_vocab.c aed56169ae5c1aa9b8189c779ffeef04ed516d3c712c06914e6d91a6759f4e4a
|
||||
F ext/fts5/fts5_vocab.c 209e0c151e108d5f3621fa24b91e9b02f3750ee6c3f9ccec312df39481b68a09
|
||||
F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl a9de9c2209cc4e7ae3c753e783504e67206c6c1467d08f209cd0c5923d3e8d8b
|
||||
F ext/fts5/test/fts5aa.test ba5158eba7d61359becdfca895ef471072c7bf7b20e5e60dcb4d024c8419c926
|
||||
F ext/fts5/test/fts5_common.tcl 3378732aae2a7d9a4b9b5c40bde678d4259ca16bd490883325aecc4747bcb384
|
||||
F ext/fts5/test/fts5aa.test 4db81519863244a3cab35795fe65ab6b592e7970c7409eba098b23ebbfc08d95
|
||||
F ext/fts5/test/fts5ab.test bd932720c748383277456b81f91bc00453de2174f9762cd05f95d0495dc50390
|
||||
F ext/fts5/test/fts5ac.test a7aa7e1fefc6e1918aa4d3111d5c44a09177168e962c5fd2cca9620de8a7ed6d
|
||||
F ext/fts5/test/fts5ad.test e8cf959dfcd57c8e46d6f5f25665686f3b6627130a9a981371dafdf6482790de
|
||||
@@ -123,7 +124,7 @@ F ext/fts5/test/fts5ak.test f459a64c9d38698af72a7c657ab6349bca96150241dd69fcce75
|
||||
F ext/fts5/test/fts5al.test 00c4c1c6a1366b73aa48ce2068c634520867c3cf7f5d1676ebbb775ee1f35734
|
||||
F ext/fts5/test/fts5alter.test 5565f7e4605512b69171ac18ca84398603f9f6456dbe377beeca97e83cc242cd
|
||||
F ext/fts5/test/fts5auto.test 78989e6527ce69c9eddbef7392fea5c10b0010cd2b2ae68eec7bc869c471e691
|
||||
F ext/fts5/test/fts5aux.test 3f194345fcd581f49f7fbb2e5495400efcc7d2835b77816328d8283c942f41b8
|
||||
F ext/fts5/test/fts5aux.test ed3596469f85a6cff5f6060e0cd9e3f9602051d8db2b497f5d12c85d39f20a62
|
||||
F ext/fts5/test/fts5auxdata.test eacc97ff04892f1a5f3d4df5a73f8bcbc3955ea1d12c9f24137eb1fc079e7611
|
||||
F ext/fts5/test/fts5bigid.test 2860854c2561a57594192b00c33a29f91cb85e25f3d6c03b5c2b8f62708f39dd
|
||||
F ext/fts5/test/fts5bigpl.test 6466c89b38439f0aba26ac09e232a6b963f29b1cbe1304f6a664fe1e7a8f5fd3
|
||||
@@ -135,7 +136,7 @@ F ext/fts5/test/fts5columnsize.test 45459ce4dd9fd853b6044cdc9674921bff89e3d840f3
|
||||
F ext/fts5/test/fts5config.test 60094712debc59286c59aef0e6cf511c37d866802776a825ce437d26afe0817f
|
||||
F ext/fts5/test/fts5conflict.test bf6030a77dbb1bedfcc42e589ed7980846c995765d77460551e448b56d741244
|
||||
F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c073e19b3ae9126b2f4
|
||||
F ext/fts5/test/fts5content.test 219a4e49386b9b197b9b7cadca97ea10ddff858ecd8b763a1cb8bb07575afc2a
|
||||
F ext/fts5/test/fts5content.test 282b373c58c8e798568ec2ced18b23f29bffa8d61317a0e51a035000ad6cd731
|
||||
F ext/fts5/test/fts5contentless.test 1cd1237894eeff11feb1ff8180044eac0b17dde22c181f7a722f2dcbfdb3377c
|
||||
F ext/fts5/test/fts5contentless2.test 14c83bdacf8230f5f7ca74ecf2926b87d8a7cb788a69ce9937020428ac4fe192
|
||||
F ext/fts5/test/fts5contentless3.test 353d871c5ea08992aed3e2ebda0b1bdc35116cd24fe330fe7cf05be1e2b49fd7
|
||||
@@ -145,7 +146,7 @@ F ext/fts5/test/fts5corrupt.test b6d4034b682bb3387bc44c510c71b3c67d4349e4df13949
|
||||
F ext/fts5/test/fts5corrupt2.test 99e7e23a58b4d89eb7167c6de1669cbc595cd3c79ab333e0eb56405473319e77
|
||||
F ext/fts5/test/fts5corrupt3.test 7da9895dafa404efd20728f66ff4b94399788bdc042c36fe2689801bba2ccd78
|
||||
F ext/fts5/test/fts5corrupt4.test f4c08e2182a48d8b70975fd869ee5391855c06d8a0ff87b6a2529e7c5a88a1d3
|
||||
F ext/fts5/test/fts5corrupt5.test 38a238df26c4de471e1c4b98f8de6c902bc692577a1c08d0ff4f2251f3559644
|
||||
F ext/fts5/test/fts5corrupt5.test f9dbed6785c38d891c0b947fd6e973e9c4eb44991e1322f8d7e5281a019276f2
|
||||
F ext/fts5/test/fts5corrupt6.test bf8eeae07825b088b9665d9d8e4accbd8dc9bf3cb85b6c64cf6c9e18ccc420a4
|
||||
F ext/fts5/test/fts5corrupt7.test 80ad7f683a8bda2404731bb77e8c3dbbb620c1f6cc583cca8239f6accd6338c0
|
||||
F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7
|
||||
@@ -170,6 +171,7 @@ F ext/fts5/test/fts5faultD.test e7ed7895abfe6bc98a5e853826f6b74956e7ba7f594f1860
|
||||
F ext/fts5/test/fts5faultE.test 844586ce71dab4be85bb86880e87b624d089f851654cd22e4710c77eb8ce7075
|
||||
F ext/fts5/test/fts5faultF.test 4abef99f86e99d9f0c6460dd68c586a766b6b9f1f660ada55bf2e8266bd1bbc1
|
||||
F ext/fts5/test/fts5faultG.test d2e5a4d9a34e08dcaadcaeafef74d10cbc2abdd11aa2659a18af0294bf2812d3
|
||||
F ext/fts5/test/fts5faultH.test 57f53c87ffd59be0265840f2b54a16811f9cb9012db86aad9b41d0d14d85dfe3
|
||||
F ext/fts5/test/fts5first.test 3fcf2365c00a15fc9704233674789a3b95131d12de18a9b996159f6909dc8079
|
||||
F ext/fts5/test/fts5full.test e1701a112354e0ff9a1fdffb0c940c576530c33732ee20ac5e8361777070d717
|
||||
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
|
||||
@@ -182,7 +184,7 @@ F ext/fts5/test/fts5limits.test 8ab67cf5d311c124b6ceb0062d0297767176df4572d955fc
|
||||
F ext/fts5/test/fts5matchinfo.test 10c9a6f7fe61fb132299c4183c012770b10c4d5c2f2edb6df0b6607f683d737a
|
||||
F ext/fts5/test/fts5merge.test e92a8db28b45931e7a9c7b1bbd36101692759d00274df74d83fd29d25d53b3a6
|
||||
F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2
|
||||
F ext/fts5/test/fts5misc.test 5ca82f2a5ee016b0842043155d1382f98a34d0d86b2791165a44d7807f6e0f54
|
||||
F ext/fts5/test/fts5misc.test 89dc46e37951b7f6653809f4abf6b1ca2f1fa62259efaf719339288f76fb6be9
|
||||
F ext/fts5/test/fts5multi.test a15bc91cdb717492e6e1b66fec1c356cb57386b980c7ba5af1915f97fe878581
|
||||
F ext/fts5/test/fts5multiclient.test 5ff811c028d6108045ffef737f1e9f05028af2458e456c0937c1d1b8dea56d45
|
||||
F ext/fts5/test/fts5near.test 211477940142d733ac04fad97cb24095513ab2507073a99c2765c3ddd2ef58bd
|
||||
@@ -190,6 +192,11 @@ F ext/fts5/test/fts5onepass.test f9b7d9b2c334900c6542a869760290e2ab5382af8fbd618
|
||||
F ext/fts5/test/fts5optimize.test 36a752d24c818792032e4ff502936fc9cc5ef938721696396fdc79214b2717f1
|
||||
F ext/fts5/test/fts5optimize2.test 93e742c36b487d8874621360af5b1ce4d39b04fb9e71ce9bc34015c5fc811785
|
||||
F ext/fts5/test/fts5optimize3.test bf9c91bb927d0fb2b9a06318a217a0419183ac5913842e062c7e0b98ea5d0fca
|
||||
F ext/fts5/test/fts5origintext.test d2796fa08ee7aecfabdc0c45bb8a2fb16a00ea8757e63fbc153b718dbe430a39
|
||||
F ext/fts5/test/fts5origintext2.test f3b9436de540828d01f0672df855b09ebc0863e126d5b56234701d71dfa73634
|
||||
F ext/fts5/test/fts5origintext3.test 0d25933506600452a5ab3873cbb418ed5f2de2446c3672b9997b1ea104b0e7f0
|
||||
F ext/fts5/test/fts5origintext4.test 0c4e4514b68d9ddb15e5a538d9d234da85747a3fd62432265dbdba5c8708e457
|
||||
F ext/fts5/test/fts5origintext5.test a037bdf7235a22033c4663837bdb12d9738245464a3ac2f60c71fc40d07ede7d
|
||||
F ext/fts5/test/fts5phrase.test 13e5d8e9083077b3d9c74315b3c92ec723cc6eb37c8155e0bfe1bba00559f07b
|
||||
F ext/fts5/test/fts5plan.test b65cfcca9ddd6fdaa118c61e17aeec8e8433bc5b6bb307abd116514f79c49c5a
|
||||
F ext/fts5/test/fts5porter.test 8d08010c28527db66bc3feebd2b8767504aaeb9b101a986342fa7833d49d0d15
|
||||
@@ -204,7 +211,7 @@ F ext/fts5/test/fts5rowid.test b8790ec170a8dc1942a15aef3db926a5f3061b1ff17101300
|
||||
F ext/fts5/test/fts5savepoint.test 050796b24929325cdbbb2fbfe2794816ae95d298e940ae15032200c2f4a73725
|
||||
F ext/fts5/test/fts5secure.test a02f771742fb2b1b9bdcb4bf523bcf2d0aa1ff597831d40fe3e72aaa6d0ec40f
|
||||
F ext/fts5/test/fts5secure2.test 2e961d7eef939f294c56b5d895cac7f1c3a60b934ee2cfd5e5e620bdf1ba6bbc
|
||||
F ext/fts5/test/fts5secure3.test c7e1080a6912f2a3ac68f2e05b88b72a99de38543509b2bbf427cac5c9c1c610
|
||||
F ext/fts5/test/fts5secure3.test 6d066828d225b0dbe5db818d4d6165df7bb70210e68a577e858e8762400d5a23
|
||||
F ext/fts5/test/fts5secure4.test 0d10a80590c07891478700af7793b232962042677432b9846cf7fc8337b67c97
|
||||
F ext/fts5/test/fts5secure5.test c07a68ced5951567ac116c22f2d2aafae497e47fe9fcb6a335c22f9c7a4f2c3a
|
||||
F ext/fts5/test/fts5secure6.test 74bf04733cc523bccca519bb03d3b4e2ed6f6e3db7c59bf6be82c88a0ac857fd
|
||||
@@ -212,10 +219,10 @@ F ext/fts5/test/fts5secure7.test fd03d0868d64340a1db8615b02e5508fea409de13910114
|
||||
F ext/fts5/test/fts5secure8.test eb3579e9d58b0acad97e8082dee1f99b2d393198f03500b453c2b25761c0c298
|
||||
F ext/fts5/test/fts5securefault.test dbca2b6a1c16700017f5051138991b705410889933f2a37c57ae8a23b296b10b
|
||||
F ext/fts5/test/fts5simple.test a298670508c1458b88ce6030440f26a30673931884eb5f4094ac1773b3ba217b
|
||||
F ext/fts5/test/fts5simple2.test 258a1b0c590409bfa5271e872c79572b319d2a56554d0585f68f146a0da603f0
|
||||
F ext/fts5/test/fts5simple2.test 8dd2389ee75e21a1429fe87e5f8c7d9a97ad1470304a8a2d3ba4b8c3c345fecd
|
||||
F ext/fts5/test/fts5simple3.test d5c74a9d3ca71bd5dd5cacb7c55b86ea12cdddfc8b1910e3de2995206898380f
|
||||
F ext/fts5/test/fts5synonym.test 1651815b8008de170e8e600dcacc17521d765482ea8f074ae82cfa870d8bb7fb
|
||||
F ext/fts5/test/fts5synonym2.test 8f891fc49cc1e8daed727051e77e1f42849c784a6a54bef82564761b2cb3e016
|
||||
F ext/fts5/test/fts5synonym2.test e2f6ff68c4fbe12a866a3a87510f553d9dac99bcb74c10b56487c4c0a562fcf5
|
||||
F ext/fts5/test/fts5tok1.test 1f7817499f5971450d8c4a652114b3d833393c8134e32422d0af27884ffe9cef
|
||||
F ext/fts5/test/fts5tok2.test dcacb32d4a2a3f0dd3215d4a3987f78ae4be21a2
|
||||
F ext/fts5/test/fts5tokenizer.test ac3c9112b263a639fb0508ae73a3ee886bf4866d2153771a8e8a20c721305a43
|
||||
@@ -232,7 +239,7 @@ F ext/fts5/test/fts5unindexed.test 9021af86a0fb9fc616f7a69a996db0116e7936d0db638
|
||||
F ext/fts5/test/fts5update.test b8affd796e45c94a4d19ad5c26606ea06065a0f162a9562d9f005b5a80ccf0bc
|
||||
F ext/fts5/test/fts5version.test d6e5a5897550afeccc2f8531d87404dc1c289ee89385dd4318dbdd75e71d7a67
|
||||
F ext/fts5/test/fts5vocab.test 7ed80d9af1ddaaa1637da05e406327b5aac250848bc604c1c1cc667908b87760
|
||||
F ext/fts5/test/fts5vocab2.test 681980e92e031c9f3fe8d9c149189e876c108da2fb0fb3a25bd8a9b94bff8f68
|
||||
F ext/fts5/test/fts5vocab2.test 1b1f0059f762ffb404213d35dac013e010621f08128589b6ec7bec59d9a710f3
|
||||
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
|
||||
F ext/fts5/tool/fts5txt2db.tcl c0d43c8590656f8240e622b00957b3a0facc49482411a9fdc2870b45c0c82f9f
|
||||
F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
|
||||
@@ -244,7 +251,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
|
||||
F ext/jni/GNUmakefile 59eb05f2a363bdfac8d15d66bed624bfe1ff289229184f3861b95f98a19cf4b2
|
||||
F ext/jni/README.md d899789a9082a07b99bf30b1bbb6204ae57c060efcaa634536fa669323918f42
|
||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||
F ext/jni/src/c/sqlite3-jni.c 6040c0de97644a1fb14bb589ee9f2f4208f6e6b165d14a0e33ed24945b118838
|
||||
F ext/jni/src/c/sqlite3-jni.c c1292e690a20c7787a63e8d8ac6e2dfed49c97282ed056a7cfda5da461f0b7d8
|
||||
F ext/jni/src/c/sqlite3-jni.h 913ab8e8fee432ae40f0e387c8231118d17053714703f5ded18202912a8a3fbf
|
||||
F ext/jni/src/org/sqlite/jni/annotation/Experimental.java 8603498634e41d0f7c70f661f64e05df64376562ea8f126829fd1e0cdd47e82b
|
||||
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 38e7e58a69b26dc100e458b31dfa3b2a7d67bc36d051325526ef1987d5bc8a24
|
||||
@@ -255,7 +262,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63
|
||||
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 d428a1fd3b827f01c55d10d21ff35e33e7dac9e8a1d92a8b5c7d7255e67407d8
|
||||
F ext/jni/src/org/sqlite/jni/capi/CApi.java 27bbd944ea8c147afd25b93f17dc397f3627611ebe2878944a32ffeffc98e99e
|
||||
F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b
|
||||
F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a
|
||||
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
|
||||
@@ -291,7 +298,7 @@ F ext/jni/src/org/sqlite/jni/fts5/Fts5Context.java 338637e6e5a2cc385d962b220f3c1
|
||||
F ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java 7da0fbb5728f7c056a43e6407f13dd0c7c9c445221267786a109b987f5fc8a9d
|
||||
F ext/jni/src/org/sqlite/jni/fts5/Fts5PhraseIter.java 28045042d593a1f1b9b80d54ec77cbf1d8a1bc95e442eceefa9a3a6f56600b0e
|
||||
F ext/jni/src/org/sqlite/jni/fts5/Fts5Tokenizer.java 3c8f677ffb85b8782f865d6fcbc16200b3375d0e3c29ed541a494fde3011bf49
|
||||
F ext/jni/src/org/sqlite/jni/fts5/TesterFts5.java eaee4d641229a098eb704b96a45c9a23c6514dc39009d3611e265bab33834deb
|
||||
F ext/jni/src/org/sqlite/jni/fts5/TesterFts5.java 51e16bf9050af7cb246d17d6a19c001cfc916bf20f425c96625aaccaf74688e8
|
||||
F ext/jni/src/org/sqlite/jni/fts5/XTokenizeCallback.java 1efd1220ea328a32f2d2a1b16c735864159e929480f71daad4de9d5944839167
|
||||
F ext/jni/src/org/sqlite/jni/fts5/fts5_api.java a8e88c3783d21cec51b0748568a96653fead88f8f4953376178d9c7385b197ea
|
||||
F ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java 9e2b954d210d572552b28aca523b272fae14bd41e318921b22f65b728d5bf978
|
||||
@@ -388,7 +395,7 @@ F ext/misc/pcachetrace.c f4227ce03fb16aa8d6f321b72dd051097419d7a028a9853af048bee
|
||||
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
|
||||
F ext/misc/prefixes.c 82645f79229877afab08c8b08ca1e7fa31921280906b90a61c294e4f540cd2a6
|
||||
F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47cc06c
|
||||
F ext/misc/randomjson.c 7dd13664155319d47b9facc0d8dbf45e13062966a47168e54e3f26d48240d7ea
|
||||
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
|
||||
F ext/misc/regexp.c 4bdd0045912f81c84908bd535ec5ad3b1c8540b4287c70ab84070963624047db
|
||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||
@@ -401,7 +408,7 @@ F ext/misc/spellfix.c c0aa7b80d6df45f7da59d912b38752bcac1af53a5766966160e6c5cdd3
|
||||
F ext/misc/sqlar.c 53e7d48f68d699a24f1a92e68e71eca8b3a9ff991fe9588c2a05bde103c6e7b7
|
||||
F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321
|
||||
F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b
|
||||
F ext/misc/totype.c fa4aedeb07f66169005dffa8de3b0a2b621779fd44f85c103228a42afa71853b
|
||||
F ext/misc/totype.c 75ed9827d19cc3b434fc2aeb60725d4d46e1534373615612a4d1cfdcc3d60922
|
||||
F ext/misc/uint.c 053fed3bce2e89583afcd4bf804d75d659879bbcedac74d0fa9ed548839a030b
|
||||
F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785
|
||||
F ext/misc/urifuncs.c f71360d14fa9e7626b563f1f781c6148109462741c5235ac63ae0f8917b9c751
|
||||
@@ -460,7 +467,7 @@ F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69
|
||||
F ext/rbu/sqlite3rbu.c d4ddf8f0e93772556e452a6c2814063cf47efb760a0834391a9d0cd9859fa4b9
|
||||
F ext/rbu/sqlite3rbu.h 9d923eb135c5d04aa6afd7c39ca47b0d1d0707c100e02f19fdde6a494e414304
|
||||
F ext/rbu/test_rbu.c ee6ede75147bc081fe9bc3931e6b206277418d14d3fbceea6fdc6216d9b47055
|
||||
F ext/recover/dbdata.c fc7147a68422cbbbaa481ee92ae1752cc25f5a24302bece1c70dcb76345bd736
|
||||
F ext/recover/dbdata.c b7746c2ec801b453840831311be4b31f8c8f9dd97791060a69bbf12392c78949
|
||||
F ext/recover/recover1.test c484d01502239f11b61f23c1cee9f5dd19fa17617f8974e42e74d64639c524cf
|
||||
F ext/recover/recover_common.tcl a61306c1eb45c0c3fc45652c35b2d4ec19729e340bdf65a272ce4c229cefd85a
|
||||
F ext/recover/recoverbuild.test c74170e0f7b02456af41838afeb5353fdb985a48cc2331d661bbabbca7c6b8e3
|
||||
@@ -488,7 +495,7 @@ F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c3350
|
||||
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/geopoly.c 0dd4775e896cee6067979d67aff7c998e75c2c9d9cd8d62a1a790c09cde7adca
|
||||
F ext/rtree/rtree.c 2e1452a9338fe4db057fa677277bed86b65c667ed48b9b59144adae99f85a7cb
|
||||
F ext/rtree/rtree.c d0134bb75bc92b18a1dc011ec10419642f055c67af8ff44fc4a07c5fa9f189cb
|
||||
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
|
||||
F ext/rtree/rtree1.test 2b5b8c719c6a4abe377f57766f428a49af36a93061cb146cccfdc3b30000c0a4
|
||||
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
|
||||
@@ -568,7 +575,7 @@ F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
||||
F ext/wasm/GNUmakefile 0e362f3fc04eab6628cbe4f1e35f4ab4a200881f6b5f753b27fb45eabeddd9d2
|
||||
F ext/wasm/GNUmakefile 867c903a27fa0d53a3bf1b01d8c7bb713456f87e0939c3cac9f07faa68f58734
|
||||
F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
|
||||
F ext/wasm/README.md a8a2962c3aebdf8d2104a9102e336c5554e78fc6072746e5daf9c61514e7d193
|
||||
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
|
||||
@@ -579,27 +586,30 @@ F ext/wasm/SQLTester/touint8array.c 2d5ece04ec1393a6a60c4bf96385bda5e1a10ad49f30
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api f442460ed9a109e637dd3ea1caa4489553ad9414e8988118b208bb7a4bbece6b
|
||||
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 5eb44fa02e9c693a1884a3692428647894b0380b24bca120866b7a24c8786134
|
||||
F ext/wasm/api/README.md 34fe11466f9c1d81b10a0469e1114e5f1c5a6365c73d80a1a6ca639a1a358b73
|
||||
F ext/wasm/api/extern-post-js.c-pp.js c4154a7f90c2d7e51fd6738273908152036c3457fdc0b6523f1be3ef51105aac
|
||||
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
|
||||
F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1
|
||||
F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62
|
||||
F ext/wasm/api/post-js-header.js 04dc12c3edd666b64a1b4ef3b6690c88dcc653f26451fd4734472d8e29c1c122
|
||||
F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219
|
||||
F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
|
||||
F ext/wasm/api/sqlite3-api-glue.js 119b91c8a7ce6648679eb66fcdd1ed07ef7fd892eb501d658fbfefcc962012d9
|
||||
F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 9aeba7b45cf41b3a26d34d7fb2525633cd1adfc544888c1ea8dbb077496f4ce9
|
||||
F ext/wasm/api/sqlite3-api-worker1.js 88770ac01fc756f89a3e060eec17111d6c1688e89ebfd34cb9d9e54d25affbb9
|
||||
F ext/wasm/api/sqlite3-api-glue.js 587dc6db2d69329a5f4cb9635c377f516cf4a8e30f443f33380e5044889ec71b
|
||||
F ext/wasm/api/sqlite3-api-oo1.js 7f3bcf0549ac44cde4b9da0b642d771916738d3f6781fb8a1757c50a91e506c0
|
||||
F ext/wasm/api/sqlite3-api-prologue.js fffcee629bf020a8ccf5c367fbe6a169f5d5d73dfce1707a75c9fbf4aa21c7da
|
||||
F ext/wasm/api/sqlite3-api-worker1.js 8d9c0562831f62218170a3373468d8a0b7a6503b5985e309b69bf71187b525cf
|
||||
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
|
||||
F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
|
||||
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 595953994aa3ae2287c889c4da39ab3d6f17b6461ecf4bec334b7a3faafddb02
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 46c4afa6c50d7369252c104f274ad977a97e91ccfafc38b400fe36e90bdda88e
|
||||
F ext/wasm/api/sqlite3-wasm.c d0e09eb5ed3743c00294e30019e591c3aa150572ae7ffe8a8994568a7377589f
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 569d4e859968e65f55dec5fac0b879828a23c8b179162cc7812fec19f844dd21
|
||||
F ext/wasm/api/sqlite3-worker1.c-pp.js a541112aa51e16705f13a99bb943c64efe178aa28c86704a955f8fd9afe4ba37
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js ebf6c7e997cd8948b35b3afc550b0503dd53febd9d2b56354efd11d985e5f0f2
|
||||
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js a2fcbc3fecdd0eea229283584ebc122f29d98194083675dbe5cb2cf3a17fe309
|
||||
F ext/wasm/api/sqlite3-wasm.c d33a16495ca871781e78812d3a18fed78b797468fffee657b8d7199b277ff359
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js f234191fe6bf41a5a1e59c9f43ed816e74a522b3d60d3f556f66c3085c448503
|
||||
F ext/wasm/api/sqlite3-worker1.c-pp.js 5e8706c2c4af2a57fbcdc02f4e7ef79869971bc21bb8ede777687786ce1c92d5
|
||||
F ext/wasm/batch-runner-sahpool.html e9a38fdeb36a13eac7b50241dfe7ae066fe3f51f5c0b0151e7baee5fce0d07a7
|
||||
F ext/wasm/batch-runner-sahpool.js 54a3ac228e6c4703fe72fb65c897e19156263a51fe9b7e21d2834a45e876aabd
|
||||
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
|
||||
F ext/wasm/batch-runner.js 0dad6a02ad796f1003d3b7048947d275c4d6277f63767b8e685c27df8fdac93e
|
||||
F ext/wasm/batch-runner.js 05ec254f5dbfe605146d9640b3db17d6ef8c3fbef6aa8396051ca72bb5884e3f
|
||||
F ext/wasm/c-pp.c 6d80d8569d85713effe8b0818a3cf51dc779e3f0bf8dc88771b8998552ee25b4
|
||||
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
|
||||
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
|
||||
@@ -607,7 +617,7 @@ F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a7
|
||||
F ext/wasm/common/whwasmutil.js 4c64594eecc7af4ae64259e95a71ba2a7edf118881aaff0bba86d0c7164e78e4
|
||||
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
|
||||
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
|
||||
F ext/wasm/demo-123.js 38aa8faec4d0ace1c973bc8a7a1533584463ebeecd4c420daa7d9687beeb9cb5
|
||||
F ext/wasm/demo-123.js c7b3cca50c55841c381a9ca4f9396e5bbdc6114273d0b10a43e378e32e7be5bf
|
||||
F ext/wasm/demo-jsstorage.html 409c4be4af5f207fb2877160724b91b33ea36a3cd8c204e8da1acb828ffe588e
|
||||
F ext/wasm/demo-jsstorage.js 44e3ae7ec2483b6c511384c3c290beb6f305c721186bcf5398ca4e00004a06b8
|
||||
F ext/wasm/demo-worker1-promiser.html 1de7c248c7c2cfd4a5783d2aa154bce62d74c6de98ab22f5786620b3354ed15f
|
||||
@@ -618,20 +628,20 @@ F ext/wasm/dist.make 3a851858aad72e246a5d9c5aaf6b6a144305f1bf898ac1846760ea7bab9
|
||||
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
|
||||
F ext/wasm/fiddle.make fa2ba6e90457ba2a71cb745f200d409caf773076df75ae5b177cc225d7627a11
|
||||
F ext/wasm/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
|
||||
F ext/wasm/fiddle/fiddle-worker.js e0153f9af6500805c6f09c0b3cfdb7d857e9d6863dbee9d50d1628fccf5f4b4d
|
||||
F ext/wasm/fiddle/fiddle-worker.js 9be57887756c6854dbdcb5e7d8b7a26935d565491333a2f91dc4113598c659b5
|
||||
F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5653284071715
|
||||
F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
|
||||
F ext/wasm/index-dist.html 22379774f0ad4edcaaa8cf9c674c82e794cc557719a8addabed74eb8069d412e
|
||||
F ext/wasm/index.html 4e7847b909f4ae0da8c829b150b79454050e53b3658431f138636257729cd42b
|
||||
F ext/wasm/index-dist.html e91d76e4581185238fd3d42ed86ec600f7023ed3e3a944c5c356f25304bf1263
|
||||
F ext/wasm/index.html b31ce41c0da476d5ffcef23069b9d3415b419d65af5779096ebcfbcbade453a9
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 1264710db3cfbcb6887d95665b7aeba60c1126eaef789ca4cf1a4a17d5bc7f54
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 37911f00db12cbcca73aa1ed72594430365f30aafae2fa9c886961de74e5e0eb
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 59a20df389abcc3606eb4eaea7fb7ba14504beb3e345dbea9b99a0618ba3bec8
|
||||
F ext/wasm/module-symbols.html dc476b403369b26a1a23773e13b80f41b9a49f0825e81435fe3600a7cfbbe337
|
||||
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
|
||||
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
|
||||
F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2d7c36218bb7d67379d
|
||||
F ext/wasm/speedtest1-wasmfs.mjs ac5cadbf4ffe69e9eaac8b45e8523f030521e02bb67d654c6eb5236d9c456cbe
|
||||
F ext/wasm/speedtest1-worker.html e33e2064bda572c0c3ebaec7306c35aa758d9d27e245d67e807f8cc4a9351cc5
|
||||
F ext/wasm/speedtest1-worker.js 315d26198c46be7c85e26fda15d80ef882424276abde25ffd8b026fb02a35d8c
|
||||
F ext/wasm/speedtest1-worker.html 864b65ed78ce24847a348c180e7f267621a02ca027068a1863ec1c90187c1852
|
||||
F ext/wasm/speedtest1-worker.js 95e549e13a4d35863a9a7fc66122b5f546c0130d3be7b06dfcc556eb66d24bde
|
||||
F ext/wasm/speedtest1.html ff048b4a623aa192e83e143e48f1ce2a899846dd42c023fdedc8772b6e3f07da
|
||||
F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
|
||||
F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
|
||||
@@ -640,7 +650,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
||||
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
|
||||
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
|
||||
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
|
||||
F ext/wasm/tester1.c-pp.js a92dc256738dbd1b50f142d1fd0c835294ba09b7bb6526650360e942f88cb63f
|
||||
F ext/wasm/tester1.c-pp.js 7c51d19f3644904156a154ddedd7024539ffba1a4e2df5e1efe10333e5b91b8f
|
||||
F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1
|
||||
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
|
||||
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
||||
@@ -648,7 +658,7 @@ F ext/wasm/wasmfs.make 8a4955882aaa0783b3f60a9484a1f0f3d8b6f775c0fcd17c082f31966
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk 51fd5fc8565007266e6bfd9e299199c752b171707a667b8914a204b38258e1b1
|
||||
F main.mk ef8d6b0e76b27d2b32d7b71ea30a2b2626b668f998a4f32f6171c9623a310a53
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
|
||||
@@ -661,16 +671,16 @@ F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
|
||||
F src/alter.c 30c2333b8bb3af71e4eb9adeadee8aa20edb15917ed44b8422e5cd15f3dfcddc
|
||||
F src/analyze.c d4cc28738c29e009640ec20ebb6936ba6fcefff0d11aa93398d9bb9a5ead6c1f
|
||||
F src/analyze.c 0f15753308c3bca7674f31fa7e0807ffcb8b120c36eef7d00b62b33079ddc854
|
||||
F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39
|
||||
F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
|
||||
F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
|
||||
F src/btree.c f3b09c5414de3a11db73e11e1d66f4c5e53c9e89876ff3b531a887ab656ca303 x
|
||||
F src/btree.c dee25e097b749275333b55d64a5ffc079249576f8e88a2ee476468cf67510f4b
|
||||
F src/btree.h 03e3356f5208bcab8eed4e094240fdac4a7f9f5ddf5e91045ce589f67d47c240
|
||||
F src/btreeInt.h 3e2589726c4f105e653461814f65857465da68be1fac688de340c43b873f4062
|
||||
F src/build.c 189e4517d67f09f0a3e0d8e1faa6e2ef0c2e95f6ac82e33c912cb7efa2a359cc
|
||||
F src/build.c f640dbe723e35f29a91870ff8bd9fb015b1cbc49666014b1d422c012eb333de9
|
||||
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
|
||||
@@ -678,20 +688,20 @@ F src/date.c 3b8d02977d160e128469de38493b4085f7c5cf4073193459909a6af3cf6d7c91
|
||||
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
|
||||
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
|
||||
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
|
||||
F src/expr.c e9a491c7f156e5b25641c28af11b735a424e108a21b9f83b6f3e51c99a8141d9
|
||||
F src/expr.c 3381ee4c9aa7ccde22a2a7f35ce343925a7a25d96bdc943649131f9decdebad2
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
|
||||
F src/func.c 472f6dcfa39cf54f89a6aec76c79c225fb880a6c14469c15d361331662b9bf43
|
||||
F src/global.c 29f56a330ed9d1b5cd9b79ac0ca36f97ac3afc730ff8bfa987b0db9e559d684d
|
||||
F src/global.c 765a0656d6cbf043cb272ff0ae38f39cc46713539ffe6793258ed3eb4b188b52
|
||||
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
|
||||
F src/json.c fa3a1b6f2432848dc03448d359a07040f7e4a44d868e9e16512c6066b65aeef9
|
||||
F src/json.c 4913fd22c4f0fa30643afb93a4d78d289cd490620e782b31016c3d4b2049b1cc
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
||||
F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
|
||||
F src/main.c 438b95162acfa17b7d218f586f5bde11d6ae82bcf030c9611fc537556870ad6b
|
||||
F src/malloc.c f016922435dc7d1f1f5083a03338a3e91f8c67ce2c5bdcfa4cdef62e612f5fcc
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@@ -712,33 +722,33 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
|
||||
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
|
||||
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
|
||||
F src/os_unix.c dc5404b56da7fb13cf272ddb94c3753cf9e82d32a65cba35dbb6aadcb849419c
|
||||
F src/os_unix.c 1672c708df279fca1b6ba619cbb26a88baa7913b21dda95817290d76666a9688
|
||||
F src/os_win.c 4a50a154aeebc66a1f8fb79c1ff6dd5fe3d005556533361e0d460d41cb6a45a8
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 987ab3a2cd9065d62e9955474470ff733445e2357432a67e3d0f5a8f9313e334
|
||||
F src/pager.h f4d33fec8052603758792045493423b8871a996da2d0973927b7d36cd6070473
|
||||
F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd
|
||||
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
|
||||
F src/parse.y 020d80386eb216ec9520549106353c517d2bbc89be28752ffdca649a9eaf56ec
|
||||
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
|
||||
F src/pragma.c b3b4ad9c0298d63098a067acca613c21a5f56b4d176d5842922bcd0b07b7164e
|
||||
F src/pragma.c b5b4cff830575e6188cd56a295a57448d2b9dbc53f0dae58e22b97354cda3781
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c
|
||||
F src/printf.c 9da63b9ae1c14789bcae12840f5d800fd9302500cd2d62733fac77f0041b4750
|
||||
F src/printf.c 18fbdf028345c8fbe6044f5f5bfda5a10d48d6287afef088cc21b0ca57985640
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916
|
||||
F src/resolve.c e25f51a473a5f30a0d978e4df2aaa98aeec84eac29ecae1ad4708a6c3e669345
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c 85857bedd2913d888aa571755b48c54cd2e6e7fcb0087e19b226ee0368cfda1e
|
||||
F src/shell.c.in a492f9209fe62ce3d1048802d59cd6e38e8444f88573fe1aebaadcd22e04156b
|
||||
F src/sqlite.h.in d93a4821d2f792467a60f7dc81268d1bb8634f40c31694ef254cab4f9921f96a
|
||||
F src/select.c f1a81ff4f8e9e76c224e2ab3a4baa799add0db22158c7fcede65d8cc4a6fa2da
|
||||
F src/shell.c.in 85f8d52fa4f7773823736dd39d0a268fd739207fcae95883c9ec8ce4af59f7df
|
||||
F src/sqlite.h.in 61a60b4ea04db8ead15e1579b20b64cb56e9f55d52c5f9f9694de630110593a3
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
|
||||
F src/sqliteInt.h 6b82eb99a9d2887e873fb29e56befb7c50cf4624df615d23a28f071dc8abf5f6
|
||||
F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
|
||||
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
|
||||
F src/sqliteInt.h 73800d73e21180e6b3df8d0fe7d11758dc24367fd2b0b0075b48fc116de406bb
|
||||
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
|
||||
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c ecbc3c99c0d0c3ed122a913f143026c26d38d57f33e06bb71185dd5c1efe37cd
|
||||
F src/test1.c f9620e8f0d0fa4edb239201a732c4dd1562f0cdd9741955c89332d49e14a5edd
|
||||
F src/test1.c ac6542cddd1f405e332d869946b977b2ce8b4dc28b9f7cc61df38abe1fe49bc3
|
||||
F src/test2.c 54520d0565ef2b9bf0f8f1dcac43dc4d06baf4ffe13d10905f8d8c3ad3e4b9ab
|
||||
F src/test3.c e5178558c41ff53236ae0271e9acb3d6885a94981d2eb939536ee6474598840e
|
||||
F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664
|
||||
@@ -757,7 +767,7 @@ F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf
|
||||
F src/test_demovfs.c 38a459d1c78fd9afa770445b224c485e079018d6ac07332ff9bd07b54d2b8ce9
|
||||
F src/test_devsym.c 649434ed34d0b03fbd5a6b42df80f0f9a7e53f94dd1710aad5dd8831e91c4e86
|
||||
F src/test_fs.c 56cc17e4fdc57efa61695026e2ba96e910b17060d7ee01d775ec048791522e2f
|
||||
F src/test_func.c 24df3a346c012b1fc9e1001d346db6054deb426db0a7437e92490630e71c9b0a
|
||||
F src/test_func.c 4d2dc7e3e0946e55091784ddaf0302294f2ee300614f6f3e19a4b38df77d5167
|
||||
F src/test_hexio.c 9478e56a0f08e07841a014a93b20e4ba2709ab56d039d1ca8020e26846aa19bd
|
||||
F src/test_init.c f2cc4774b7c9140f76e45ecbb2ae219f68e3acbbe248c0179db666a70eae9f08
|
||||
F src/test_intarray.c 26ffba666beb658d73cd925d9b4fb56913a3ca9aaeac122b3691436abb192b92
|
||||
@@ -795,26 +805,26 @@ F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70e
|
||||
F src/trigger.c 0905b96b04bb6658509f711a8207287f1315cdbc3df1a1b13ba6483c8e341c81
|
||||
F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92
|
||||
F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c b22cc9f203a8c0b9ee5338a67f8860347d14845864c10248bebe84518a781677
|
||||
F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
|
||||
F src/util.c 078f040366d5bd5f47658d045f901c768c1c636c6eaea121f3a1cbd63c3edb5b
|
||||
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
|
||||
F src/vdbe.c a5bf636ef502cfac538418fbf537a5e0cf825c7ce9ff784cddee2eb813dfe7a7
|
||||
F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
|
||||
F src/vdbe.c 96ac876e57f480bd35ec8d74ed992bca6ae9deebe8b527a3a718e7b4714d6c2e
|
||||
F src/vdbe.h 88e19a982df9027ec1c177c793d1a5d34dc23d8f06e3b2d997f43688b05ee0eb
|
||||
F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
|
||||
F src/vdbeapi.c 8f57d60c89da0b60e6d4e272358c511f6bae4e24330bdb11f8b42f986d1bf21b
|
||||
F src/vdbeaux.c b34dfbc09403ccb676608da16ff0780d23d466470563d24fdf6350b8d2271d5e
|
||||
F src/vdbeaux.c c5a471b34e9c4cfc0295a3e10734fd197670ffaebcb742f284c8e17e8026ceea
|
||||
F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5
|
||||
F src/vdbemem.c 0012d5f01cc866833847c2f3ae4c318ac53a1cb3d28acad9c35e688039464cf0
|
||||
F src/vdbesort.c 237840ca1947511fa59bd4e18b9eeae93f2af2468c34d2427b059f896230a547
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbevtab.c 2143db7db0ceed69b21422581f434baffc507a08d831565193a7a02882a1b6a7
|
||||
F src/vtab.c 154725ebecd3bc02f7fbd7ad3974334f73fff76e02a964e828e48a7c5fb7efff
|
||||
F src/vtab.c 11948e105f56e84099ca17f1f434b1944539ea84de26d0d767eadfbc670ce1ea
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 69aa3ce60b2862a24cd86bb528e653e2137388ead258ef64db49ec9038807f5f
|
||||
F src/wal.c b08f88e69b9c43572f0703355dccc5b2f08296256fc6a82a582fcae68f8f9cd1
|
||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
|
||||
F src/where.c 1fdc69ce1333e9bd6d7d3df9fa5af1373a3f5bfdd52108d1dbc0ca85a55f777e
|
||||
F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1
|
||||
F src/where.c 217fe82a26c0fb6a3c7fd01865d821e752f9c01fb72f114af3f0b77ce234d1fb
|
||||
F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
|
||||
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
|
||||
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
|
||||
F src/window.c 5b1387d59df30d481ed14cceef5f4d1dab1f8752aa106ba72c8b62777bd139d2
|
||||
@@ -823,8 +833,8 @@ F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867d
|
||||
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
|
||||
F test/aggnested.test ce85a6af7d59c3109e35c5f03b2cd11da1a9b1417371e2f942102d0f0d77fd62
|
||||
F test/aggorderby.test e6b98dbbf3ababa96892435d387de2dcf602ef02c2b848d2d817473066f154ba
|
||||
F test/aggnested.test 610b0ce2c3e8f3daee25f9752800ee8d785db10da4aa1fbeea0ea1aabaf1d704
|
||||
F test/aggorderby.test cc3abf5de64d46ff66395ca8c2346b66c2576d5aedb7bffc5b0742508856e3bf
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
|
||||
F test/alter.test 3c00eff1e2036b9f93e9cd0f3d3e63750ac87ecb5bc71b9d7bd07cbf2ac4c494
|
||||
@@ -1161,6 +1171,7 @@ F test/fts3fault2.test 7b2741e5095367238380b0fcdb837f36c24484c7a5f353659b387df63
|
||||
F test/fts3fault3.test 4a39a1618546776255dc1de306213b600aef87eca589ca8428a70c00fd11961b
|
||||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
F test/fts3fuzz001.test c78afcd8ad712ea0b8d2ed50851a8aab3bc9dc52c64a536291e07112f519357c
|
||||
F test/fts3integrity.test 0c6fe7353d7b24d78862f4272ee9df4da2f32b3ff30fa3396945cda8119580a8
|
||||
F test/fts3join.test 1a4d786539b2b79a41c28ef2ac22cacd92a8ee830249b68a7dee4a020848e3bb
|
||||
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
|
||||
F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a
|
||||
@@ -1208,7 +1219,7 @@ F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test 3a29323b640c0552f6e9f1577407ced3a68e7d8c0bc04b61dd6040fa593a3a02
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a
|
||||
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
|
||||
F test/func4.test e8ef9b2bd6a192a213cbd5cf31a3b35e25cd6ff2fdaeea0b58d63be31b03d220
|
||||
F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a
|
||||
F test/func6.test 9cc9b1f43b435af34fe1416eb1e318c8920448ea7a6962f2121972f5215cb9b0
|
||||
F test/func7.test adbfc910385a6ffd15dc47be3c619ef070c542fcb7488964badb17b2d9a4d080
|
||||
@@ -1221,7 +1232,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
|
||||
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
|
||||
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
|
||||
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
|
||||
F test/fuzzcheck.c 69b8549e112fb815931a8c14c7955a0c407ae91a79356eecb82458384f2cb989
|
||||
F test/fuzzcheck.c 7e1bcc242dc4b42e43e4708c8140fe268db83a6901fbc681d150c77aa185e328
|
||||
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
|
||||
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
@@ -1320,18 +1331,19 @@ F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ff
|
||||
F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946
|
||||
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
|
||||
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/json/README.md 63e3e589e1df8fd3cc1588ba1faaff659214003f8b77a15af5c6452b35e30ee2
|
||||
F test/json/README.md de59d5ba0bd2796d797115688630a6405bbf43a2891bad445ac6b9f38b83f236
|
||||
F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
|
||||
F test/json/json-q1-b.txt 606818a5fba6d9e418c9f4ea7d8418af026775042dad81439b72447a147a462c
|
||||
F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
|
||||
F test/json/json-speed-check.sh b060a9a6c696c0a807d8929400fa11bd7113edc58b0d66b9795f424f8d0db326 x
|
||||
F test/json101.test 643936557daeb2eeeb839e9d87a682c7d7c6f6aee66045eedd8613cb8471d8d8
|
||||
F test/json/json-speed-check.sh 912ee03e700a65c827ee0c7b4752c21ec5ef69cf7679d2f482ca817042bead52 x
|
||||
F test/json/jsonb-q1.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7
|
||||
F test/json101.test 70587d7d35ef9e2126364ba70f0c951f70827cfbd28649d779ff3df7e8f87547
|
||||
F test/json102.test 557a46e16df1aa9bdbc4076a71a45814ea0e7503d6621d87d42a8c04cbc2b0ef
|
||||
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
|
||||
F test/json104.test 1b844a70cddcfa2e4cd81a5db0657b2e61e7f00868310f24f56a9ba0114348c1
|
||||
F test/json105.test 11670a4387f4308ae0318cadcbd6a918ea7edcd19fbafde020720a073952675d
|
||||
F test/json501.test c419deb835b70c1a2c8532936927bcc1146730328edd2052276715bfd209724d
|
||||
F test/json502.test 98c38e3c4573841028a1381dfb81d4c3f9b105d39668167da10d055e503f6d0b
|
||||
F test/json105.test 043838b56e68f3252a0dcf5be1689016f6f3f05056f8dcfcdc9d074f4d932988
|
||||
F test/json106.test 1d46a9294e2ced35c7f87cebbcb9626d01abab04f1969d7ded7b6f6a1d9be0f2
|
||||
F test/json501.test ab168a12eb6eb14d479f8c1cdae3ac062fd5a4679f17f976e96f1af518408330
|
||||
F test/json502.test 84634d3dbb521d2814e43624025b760c6198456c8197bbec6c977c0236648f5b
|
||||
F test/jsonb01.test cace70765b36a36aec9a85a41ea65667d3bbf647d4400ddc3ac76f8fe7d94f90
|
||||
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
|
||||
F test/kvtest.c 6e0228409ea7ca0497dad503fbd109badb5e59545d131014b6aaac68b56f484a
|
||||
@@ -1655,8 +1667,8 @@ F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d163
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 68454ef88508c196d19e8694daa27bff7107a91857799eaa12f417188ae53ede
|
||||
F test/testrunner.tcl 8a6721213bce1cfd3b33e1588cc6431143d96b98819206bf91f5a205fbb150d4
|
||||
F test/testrunner_data.tcl e4d5017290a6d5c11785e36cc94c67d8bb950c8cdc2dbe4c1db2a3a583812560
|
||||
F test/testrunner.tcl 8e2a5c7550b78d3283eee6103104ae2bcf56aa1df892dbd1608f27b93ebf4de8
|
||||
F test/testrunner_data.tcl 7ffd951527bbc614e723fd8d123b6834321878530696adecfdf6035100bac64e
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1854,7 +1866,7 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unhex.test b7f1b806207cb77fa31c3e434fe92fba524464e3e9356809bfcc28f15af1a8b7
|
||||
F test/unionall.test eb9afa030897af75fd2f0dd28354ef63c8a5897b6c76aa1f15acae61a12eabcf
|
||||
F test/unionall.test 5b1c4186a661e4bf762875caf4c61d8fda3dd04a6fa9005187f6ba8900c2913f
|
||||
F test/unionall2.test 71e8fa08d5699d50dc9f9dc0c9799c2e7a6bb7931a330d369307a4df7f157fa1
|
||||
F test/unionallfault.test 652bfbb630e6c43135965dc1e8f0a9a791da83aec885d626a632fe1909c56f73
|
||||
F test/unionvtab.test e1704ab1b4c1bb3ffc9da4681f8e85a0b909fd80b937984fc94b27415ac8e5a4
|
||||
@@ -1959,7 +1971,7 @@ F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2a
|
||||
F test/walvfs.test e1a6ad0f3c78e98b55c3d5f0889cf366cc0d0a1cb2bccb44ac9ec67384adc4a1
|
||||
F test/where.test 59abb854eee24f166b5f7ba9d17eb250abc59ce0a66c48912ffb10763648196d
|
||||
F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6
|
||||
F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753
|
||||
F test/where3.test 4ccb156ae33de86414a52775a6f590a9d60ba2cbc7a93a24fa331b7bcf5b6030
|
||||
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
@@ -2106,8 +2118,8 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
|
||||
F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d40618 x
|
||||
F tool/split-sqlite3c.tcl 5aa60643afca558bc732b1444ae81a522326f91e1dc5665b369c54f09e20de60
|
||||
F tool/sqldiff.c fcccbc07da942b4534d0c769e9fcc21c67cbd7086ddc1c8f13372c40a83d4634
|
||||
F tool/sqlite3_analyzer.c.in f88615bf33098945e0a42f17733f472083d150b58bdaaa5555a7129d0a51621c
|
||||
F tool/sqldiff.c 985452ffc8554baee0f945d078859d393a22abc0bbf553a9f12acae1b6e1fdd0
|
||||
F tool/sqlite3_analyzer.c.in 8da2b08f56eeac331a715036cf707cc20f879f231362be0c22efd682e2b89b4f
|
||||
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
|
||||
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
|
||||
F tool/src-verify.c 41c586dee84d0b190ad13e0282ed83d4a65ec9fefde9adf4943efdf6558eea7f
|
||||
@@ -2145,8 +2157,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P e0099464a0045a04f4ccf29bc2b8325fc8c7f39ccf4847e74818f928c9153588
|
||||
R e5b38e7d70999e4556fdfbbe91a82c08
|
||||
U drh
|
||||
Z 686f56079312574c393270803643d299
|
||||
P c8284170f66374fc528e9d6e5a03ee7321f27e80acf4360701a8b176497b7130
|
||||
R acd9470388512134bc217adbff86bef2
|
||||
U stephan
|
||||
Z ccc05bb973966212e05811d87616f96f
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2c436806b8d5f57de99c00f6154b038454fb9ae427d00d7b4a46ab9c7c69bcb9
|
||||
5836657929d7d6d3f0d5865c9f6de4e4c00edd53d15a246802b375fa15d0f255
|
||||
+21
-5
@@ -264,9 +264,9 @@ static void openStatTable(
|
||||
typedef struct StatAccum StatAccum;
|
||||
typedef struct StatSample StatSample;
|
||||
struct StatSample {
|
||||
tRowcnt *anEq; /* sqlite_stat4.nEq */
|
||||
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
tRowcnt *anEq; /* sqlite_stat4.nEq */
|
||||
tRowcnt *anLt; /* sqlite_stat4.nLt */
|
||||
union {
|
||||
i64 iRowid; /* Rowid in main table of the key */
|
||||
@@ -424,9 +424,9 @@ static void statInit(
|
||||
|
||||
/* Allocate the space required for the StatAccum object */
|
||||
n = sizeof(*p)
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
|
||||
+ sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
|
||||
+ sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
n += sizeof(tRowcnt)*nColUp; /* StatAccum.anEq */
|
||||
if( mxSample ){
|
||||
n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
||||
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
||||
@@ -447,9 +447,9 @@ static void statInit(
|
||||
p->nKeyCol = nKeyCol;
|
||||
p->nSkipAhead = 0;
|
||||
p->current.anDLt = (tRowcnt*)&p[1];
|
||||
p->current.anEq = &p->current.anDLt[nColUp];
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
p->current.anEq = &p->current.anDLt[nColUp];
|
||||
p->mxSample = p->nLimit==0 ? mxSample : 0;
|
||||
if( mxSample ){
|
||||
u8 *pSpace; /* Allocated space not yet assigned */
|
||||
@@ -716,7 +716,9 @@ static void statPush(
|
||||
|
||||
if( p->nRow==0 ){
|
||||
/* This is the first call to this function. Do initialization. */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
|
||||
#endif
|
||||
}else{
|
||||
/* Second and subsequent calls get processed here */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
@@ -725,15 +727,17 @@ static void statPush(
|
||||
|
||||
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
||||
** to the current row of the index. */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
for(i=0; i<iChng; i++){
|
||||
p->current.anEq[i]++;
|
||||
}
|
||||
#endif
|
||||
for(i=iChng; i<p->nCol; i++){
|
||||
p->current.anDLt[i]++;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
|
||||
#endif
|
||||
p->current.anEq[i] = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,7 +871,9 @@ static void statGet(
|
||||
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
|
||||
if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
|
||||
sqlite3_str_appendf(&sStat, " %llu", iVal);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
assert( p->current.anEq[i] );
|
||||
#endif
|
||||
}
|
||||
sqlite3ResultStrAccum(context, &sStat);
|
||||
}
|
||||
@@ -1556,6 +1562,16 @@ static void decodeIntArray(
|
||||
while( z[0]!=0 && z[0]!=' ' ) z++;
|
||||
while( z[0]==' ' ) z++;
|
||||
}
|
||||
|
||||
/* Set the bLowQual flag if the peak number of rows obtained
|
||||
** from a full equality match is so large that a full table scan
|
||||
** seems likely to be faster than using the index.
|
||||
*/
|
||||
if( aLog[0] > 66 /* Index has more than 100 rows */
|
||||
&& aLog[0] <= aLog[nOut-1] /* And only a single value seen */
|
||||
){
|
||||
pIndex->bLowQual = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
-1
@@ -5161,7 +5161,6 @@ static int accessPayload(
|
||||
assert( aWrite>=pBufStart ); /* due to (6) */
|
||||
memcpy(aSave, aWrite, 4);
|
||||
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
|
||||
if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT;
|
||||
nextPage = get4byte(aWrite);
|
||||
memcpy(aWrite, aSave, 4);
|
||||
}else
|
||||
|
||||
+12
-5
@@ -720,7 +720,7 @@ void sqlite3ColumnSetExpr(
|
||||
*/
|
||||
Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){
|
||||
if( pCol->iDflt==0 ) return 0;
|
||||
if( NEVER(!IsOrdinaryTable(pTab)) ) return 0;
|
||||
if( !IsOrdinaryTable(pTab) ) return 0;
|
||||
if( NEVER(pTab->u.tab.pDfltList==0) ) return 0;
|
||||
if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0;
|
||||
return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
|
||||
@@ -873,6 +873,9 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
||||
if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
|
||||
deleteTable(db, pTable);
|
||||
}
|
||||
void sqlite3DeleteTableGeneric(sqlite3 *db, void *pTable){
|
||||
sqlite3DeleteTable(db, (Table*)pTable);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -1410,7 +1413,8 @@ void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
|
||||
/*
|
||||
** Clean up the data structures associated with the RETURNING clause.
|
||||
*/
|
||||
static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){
|
||||
static void sqlite3DeleteReturning(sqlite3 *db, void *pArg){
|
||||
Returning *pRet = (Returning*)pArg;
|
||||
Hash *pHash;
|
||||
pHash = &(db->aDb[1].pSchema->trigHash);
|
||||
sqlite3HashInsert(pHash, pRet->zName, 0);
|
||||
@@ -1452,8 +1456,7 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){
|
||||
pParse->u1.pReturning = pRet;
|
||||
pRet->pParse = pParse;
|
||||
pRet->pReturnEL = pList;
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet);
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet);
|
||||
testcase( pParse->earlyCleanup );
|
||||
if( db->mallocFailed ) return;
|
||||
sqlite3_snprintf(sizeof(pRet->zName), pRet->zName,
|
||||
@@ -1652,7 +1655,8 @@ char sqlite3AffinityType(const char *zIn, Column *pCol){
|
||||
|
||||
assert( zIn!=0 );
|
||||
while( zIn[0] ){
|
||||
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
|
||||
u8 x = *(u8*)zIn;
|
||||
h = (h<<8) + sqlite3UpperToLower[x];
|
||||
zIn++;
|
||||
if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
|
||||
aff = SQLITE_AFF_TEXT;
|
||||
@@ -5692,4 +5696,7 @@ void sqlite3WithDelete(sqlite3 *db, With *pWith){
|
||||
sqlite3DbFree(db, pWith);
|
||||
}
|
||||
}
|
||||
void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){
|
||||
sqlite3WithDelete(db, (With*)pWith);
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CTE) */
|
||||
|
||||
+16
-9
@@ -1223,9 +1223,7 @@ void sqlite3ExprAddFunctionOrderBy(
|
||||
assert( ExprUseXList(pExpr) );
|
||||
if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){
|
||||
/* Ignore ORDER BY on zero-argument aggregates */
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3ExprListDelete,
|
||||
pOrderBy);
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pOrderBy);
|
||||
return;
|
||||
}
|
||||
if( IsWindowFunc(pExpr) ){
|
||||
@@ -1406,6 +1404,9 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
||||
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p ) sqlite3ExprDeleteNN(db, p);
|
||||
}
|
||||
void sqlite3ExprDeleteGeneric(sqlite3 *db, void *p){
|
||||
if( ALWAYS(p) ) sqlite3ExprDeleteNN(db, (Expr*)p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear both elements of an OnOrUsing object
|
||||
@@ -1431,9 +1432,7 @@ void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
|
||||
** pExpr to the pParse->pConstExpr list with a register number of 0.
|
||||
*/
|
||||
void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3ExprDelete,
|
||||
pExpr);
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr);
|
||||
}
|
||||
|
||||
/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
|
||||
@@ -2239,6 +2238,9 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
|
||||
void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
||||
if( pList ) exprListDeleteNN(db, pList);
|
||||
}
|
||||
void sqlite3ExprListDeleteGeneric(sqlite3 *db, void *pList){
|
||||
if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the bitwise-OR of all Expr.flags fields in the given
|
||||
@@ -2738,9 +2740,10 @@ int sqlite3ExprCanBeNull(const Expr *p){
|
||||
case TK_COLUMN:
|
||||
assert( ExprUseYTab(p) );
|
||||
return ExprHasProperty(p, EP_CanBeNull) ||
|
||||
p->y.pTab==0 || /* Reference to column of index on expression */
|
||||
NEVER(p->y.pTab==0) || /* Reference to column of index on expr */
|
||||
(p->iColumn>=0
|
||||
&& p->y.pTab->aCol!=0 /* Possible due to prior error */
|
||||
&& ALWAYS(p->iColumn<p->y.pTab->nCol)
|
||||
&& p->y.pTab->aCol[p->iColumn].notNull==0);
|
||||
default:
|
||||
return 1;
|
||||
@@ -5322,8 +5325,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||
if( inReg!=target ){
|
||||
u8 op;
|
||||
if( ALWAYS(pExpr)
|
||||
&& (ExprHasProperty(pExpr,EP_Subquery) || pExpr->op==TK_REGISTER)
|
||||
Expr *pX = sqlite3ExprSkipCollateAndLikely(pExpr);
|
||||
testcase( pX!=pExpr );
|
||||
if( ALWAYS(pX)
|
||||
&& (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER)
|
||||
){
|
||||
op = OP_Copy;
|
||||
}else{
|
||||
@@ -6819,6 +6824,8 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
}else{
|
||||
pItem->bOBPayload = 1;
|
||||
}
|
||||
pItem->bUseSubtype =
|
||||
(pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0;
|
||||
}else{
|
||||
pItem->iOBTab = -1;
|
||||
}
|
||||
|
||||
@@ -244,6 +244,9 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* bSmallMalloc */
|
||||
1, /* bExtraSchemaChecks */
|
||||
sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */
|
||||
#ifdef SQLITE_DEBUG
|
||||
0, /* bJsonSelfcheck */
|
||||
#endif
|
||||
0x7ffffffe, /* mxStrlen */
|
||||
0, /* neverCorrupt */
|
||||
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
|
||||
|
||||
+1754
-3149
File diff suppressed because it is too large
Load Diff
+22
@@ -4659,6 +4659,28 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff);
|
||||
**
|
||||
** Activate or deactivate validation of JSONB that is generated from
|
||||
** text. Off by default, as the validation is slow. Validation is
|
||||
** only available if compiled using SQLITE_DEBUG.
|
||||
**
|
||||
** If onOff is initially 1, then turn it on. If onOff is initially
|
||||
** off, turn it off. If onOff is initially -1, then change onOff
|
||||
** to be the current setting.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_JSON_SELFCHECK: {
|
||||
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
|
||||
int *pOnOff = va_arg(ap, int*);
|
||||
if( *pOnOff<0 ){
|
||||
*pOnOff = sqlite3Config.bJsonSelfcheck;
|
||||
}else{
|
||||
sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_UNTESTABLE */
|
||||
|
||||
+22
-3
@@ -4434,9 +4434,15 @@ static int unixShmSystemLock(
|
||||
|
||||
pShmNode = pFile->pInode->pShmNode;
|
||||
|
||||
/* Assert that the correct mutex or mutexes are held. */
|
||||
if( pShmNode->nRef==0 ){
|
||||
assert( ofst==UNIX_SHM_DMS && n==1 && unixMutexHeld() );
|
||||
/* Assert that the parameters are within expected range and that the
|
||||
** correct mutex or mutexes are held. */
|
||||
assert( pShmNode->nRef>=0 );
|
||||
assert( (ofst==UNIX_SHM_DMS && n==1)
|
||||
|| (ofst>=UNIX_SHM_BASE && ofst+n<=(UNIX_SHM_BASE+SQLITE_SHM_NLOCK))
|
||||
);
|
||||
if( ofst==UNIX_SHM_DMS ){
|
||||
assert( pShmNode->nRef>0 || unixMutexHeld() );
|
||||
assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
int ii;
|
||||
@@ -4595,7 +4601,20 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
|
||||
pShmNode->isUnlocked = 1;
|
||||
rc = SQLITE_READONLY_CANTINIT;
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
/* Do not use a blocking lock here. If the lock cannot be obtained
|
||||
** immediately, it means some other connection is truncating the
|
||||
** *-shm file. And after it has done so, it will not release its
|
||||
** lock, but only downgrade it to a shared lock. So no point in
|
||||
** blocking here. The call below to obtain the shared DMS lock may
|
||||
** use a blocking lock. */
|
||||
int iSaveTimeout = pDbFd->iBusyTimeout;
|
||||
pDbFd->iBusyTimeout = 0;
|
||||
#endif
|
||||
rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
pDbFd->iBusyTimeout = iSaveTimeout;
|
||||
#endif
|
||||
/* The first connection to attach must truncate the -shm file. We
|
||||
** truncate to 3 bytes (an arbitrary small number, less than the
|
||||
** -shm header size) rather than 0 as a system debugging aid, to
|
||||
|
||||
+8
-9
@@ -688,7 +688,7 @@ struct Pager {
|
||||
char *zJournal; /* Name of the journal file */
|
||||
int (*xBusyHandler)(void*); /* Function to call when busy */
|
||||
void *pBusyHandlerArg; /* Context argument for xBusyHandler */
|
||||
int aStat[4]; /* Total cache hits, misses, writes, spills */
|
||||
u32 aStat[4]; /* Total cache hits, misses, writes, spills */
|
||||
#ifdef SQLITE_TEST
|
||||
int nRead; /* Database pages read */
|
||||
#endif
|
||||
@@ -818,9 +818,8 @@ int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
if( pPager->pWal ){
|
||||
u32 iRead = 0;
|
||||
int rc;
|
||||
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
|
||||
return (rc==SQLITE_OK && iRead==0);
|
||||
(void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
|
||||
return iRead==0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
@@ -6832,11 +6831,11 @@ int *sqlite3PagerStats(Pager *pPager){
|
||||
a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
|
||||
a[4] = pPager->eState;
|
||||
a[5] = pPager->errCode;
|
||||
a[6] = pPager->aStat[PAGER_STAT_HIT];
|
||||
a[7] = pPager->aStat[PAGER_STAT_MISS];
|
||||
a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff;
|
||||
a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff;
|
||||
a[8] = 0; /* Used to be pPager->nOvfl */
|
||||
a[9] = pPager->nRead;
|
||||
a[10] = pPager->aStat[PAGER_STAT_WRITE];
|
||||
a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff;
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
@@ -6852,7 +6851,7 @@ int *sqlite3PagerStats(Pager *pPager){
|
||||
** reset parameter is non-zero, the cache hit or miss count is zeroed before
|
||||
** returning.
|
||||
*/
|
||||
void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
|
||||
void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){
|
||||
|
||||
assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
|
||||
|| eStat==SQLITE_DBSTATUS_CACHE_MISS
|
||||
@@ -7792,7 +7791,7 @@ int sqlite3PagerWalFramesize(Pager *pPager){
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_USE_SEH
|
||||
#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
|
||||
int sqlite3PagerWalSystemErrno(Pager *pPager){
|
||||
return sqlite3WalSystemErrno(pPager->pWal);
|
||||
}
|
||||
|
||||
+1
-1
@@ -216,7 +216,7 @@ sqlite3_file *sqlite3PagerJrnlFile(Pager*);
|
||||
const char *sqlite3PagerJournalname(Pager*);
|
||||
void *sqlite3PagerTempSpace(Pager*);
|
||||
int sqlite3PagerIsMemdb(Pager*);
|
||||
void sqlite3PagerCacheStat(Pager *, int, int, int *);
|
||||
void sqlite3PagerCacheStat(Pager *, int, int, u64*);
|
||||
void sqlite3PagerClearCache(Pager*);
|
||||
int sqlite3SectorSize(sqlite3_file *);
|
||||
|
||||
|
||||
+2
-1
@@ -1779,7 +1779,8 @@ void sqlite3Pragma(
|
||||
if( pVTab->pModule->iVersion<4 ) continue;
|
||||
if( pVTab->pModule->xIntegrity==0 ) continue;
|
||||
sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
|
||||
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
|
||||
pTab->nTabRef++;
|
||||
sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF);
|
||||
a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
|
||||
integrityCheckResultRow(v);
|
||||
sqlite3VdbeJumpHere(v, a1);
|
||||
|
||||
+1
-1
@@ -1369,7 +1369,7 @@ void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Reference counted string storage
|
||||
** Reference counted string/blob storage
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
|
||||
+3
-1
@@ -182,6 +182,7 @@ Bitmask sqlite3ExprColUsed(Expr *pExpr){
|
||||
assert( ExprUseYTab(pExpr) );
|
||||
pExTab = pExpr->y.pTab;
|
||||
assert( pExTab!=0 );
|
||||
assert( n < pExTab->nCol );
|
||||
if( (pExTab->tabFlags & TF_HasGenerated)!=0
|
||||
&& (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
|
||||
){
|
||||
@@ -758,6 +759,7 @@ static int lookupName(
|
||||
sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
|
||||
pParse->checkSchema = 1;
|
||||
pTopNC->nNcErr++;
|
||||
eNewExprOp = TK_NULL;
|
||||
}
|
||||
assert( pFJMatch==0 );
|
||||
|
||||
@@ -784,7 +786,7 @@ static int lookupName(
|
||||
** If a generated column is referenced, set bits for every column
|
||||
** of the table.
|
||||
*/
|
||||
if( pExpr->iColumn>=0 && pMatch!=0 ){
|
||||
if( pExpr->iColumn>=0 && cnt==1 && pMatch!=0 ){
|
||||
pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
|
||||
}
|
||||
|
||||
|
||||
+45
-24
@@ -184,6 +184,9 @@ Select *sqlite3SelectNew(
|
||||
void sqlite3SelectDelete(sqlite3 *db, Select *p){
|
||||
if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
|
||||
}
|
||||
void sqlite3SelectDeleteGeneric(sqlite3 *db, void *p){
|
||||
if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the right-most SELECT statement in a compound.
|
||||
@@ -3204,9 +3207,7 @@ multi_select_end:
|
||||
pDest->iSdst = dest.iSdst;
|
||||
pDest->nSdst = dest.nSdst;
|
||||
if( pDelete ){
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3SelectDelete,
|
||||
pDelete);
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -3757,8 +3758,7 @@ static int multiSelectOrderBy(
|
||||
/* Make arrangements to free the 2nd and subsequent arms of the compound
|
||||
** after the parse has finished */
|
||||
if( pSplit->pPrior ){
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSplit->pPrior);
|
||||
}
|
||||
pSplit->pPrior = pPrior;
|
||||
pPrior->pNext = pSplit;
|
||||
@@ -4579,9 +4579,7 @@ static int flattenSubquery(
|
||||
Table *pTabToDel = pSubitem->pTab;
|
||||
if( pTabToDel->nTabRef==1 ){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
sqlite3ParserAddCleanup(pToplevel,
|
||||
(void(*)(sqlite3*,void*))sqlite3DeleteTable,
|
||||
pTabToDel);
|
||||
sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
|
||||
testcase( pToplevel->earlyCleanup );
|
||||
}else{
|
||||
pTabToDel->nTabRef--;
|
||||
@@ -5628,8 +5626,7 @@ static struct Cte *searchWith(
|
||||
With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
|
||||
if( pWith ){
|
||||
if( bFree ){
|
||||
pWith = (With*)sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3WithDelete,
|
||||
pWith = (With*)sqlite3ParserAddCleanup(pParse, sqlite3WithDeleteGeneric,
|
||||
pWith);
|
||||
if( pWith==0 ) return 0;
|
||||
}
|
||||
@@ -6662,6 +6659,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
assert( pFunc->pFExpr->pLeft!=0 );
|
||||
assert( pFunc->pFExpr->pLeft->op==TK_ORDER );
|
||||
assert( ExprUseXList(pFunc->pFExpr->pLeft) );
|
||||
assert( pFunc->pFunc!=0 );
|
||||
pOBList = pFunc->pFExpr->pLeft->x.pList;
|
||||
if( !pFunc->bOBUnique ){
|
||||
nExtra++; /* One extra column for the OP_Sequence */
|
||||
@@ -6671,6 +6669,9 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
assert( ExprUseXList(pFunc->pFExpr) );
|
||||
nExtra += pFunc->pFExpr->x.pList->nExpr;
|
||||
}
|
||||
if( pFunc->bUseSubtype ){
|
||||
nExtra += pFunc->pFExpr->x.pList->nExpr;
|
||||
}
|
||||
pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra);
|
||||
if( !pFunc->bOBUnique && pParse->nErr==0 ){
|
||||
pKeyInfo->nKeyField++;
|
||||
@@ -6697,16 +6698,17 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
||||
assert( ExprUseXList(pF->pFExpr) );
|
||||
pList = pF->pFExpr->x.pList;
|
||||
if( pF->iOBTab>=0 ){
|
||||
/* For an ORDER BY aggregate, calls to OP_AggStep where deferred and
|
||||
** all content was stored in emphermal table pF->iOBTab. Extract that
|
||||
** content now (in ORDER BY order) and make all calls to OP_AggStep
|
||||
/* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs
|
||||
** were stored in emphermal table pF->iOBTab. Here, we extract those
|
||||
** inputs (in ORDER BY order) and make all calls to OP_AggStep
|
||||
** before doing the OP_AggFinal call. */
|
||||
int iTop; /* Start of loop for extracting columns */
|
||||
int nArg; /* Number of columns to extract */
|
||||
int nKey; /* Key columns to be skipped */
|
||||
int regAgg; /* Extract into this array */
|
||||
int j; /* Loop counter */
|
||||
|
||||
|
||||
assert( pF->pFunc!=0 );
|
||||
nArg = pList->nExpr;
|
||||
regAgg = sqlite3GetTempRange(pParse, nArg);
|
||||
|
||||
@@ -6723,6 +6725,15 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
||||
for(j=nArg-1; j>=0; j--){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j);
|
||||
}
|
||||
if( pF->bUseSubtype ){
|
||||
int regSubtype = sqlite3GetTempReg(pParse);
|
||||
int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0);
|
||||
for(j=nArg-1; j>=0; j--){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype);
|
||||
sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regSubtype);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
|
||||
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)nArg);
|
||||
@@ -6777,6 +6788,7 @@ static void updateAccumulator(
|
||||
ExprList *pList;
|
||||
assert( ExprUseXList(pF->pFExpr) );
|
||||
assert( !IsWindowFunc(pF->pFExpr) );
|
||||
assert( pF->pFunc!=0 );
|
||||
pList = pF->pFExpr->x.pList;
|
||||
if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
|
||||
Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
|
||||
@@ -6821,6 +6833,9 @@ static void updateAccumulator(
|
||||
if( pF->bOBPayload ){
|
||||
regAggSz += nArg;
|
||||
}
|
||||
if( pF->bUseSubtype ){
|
||||
regAggSz += nArg;
|
||||
}
|
||||
regAggSz++; /* One extra register to hold result of MakeRecord */
|
||||
regAgg = sqlite3GetTempRange(pParse, regAggSz);
|
||||
regDistinct = regAgg;
|
||||
@@ -6833,6 +6848,14 @@ static void updateAccumulator(
|
||||
if( pF->bOBPayload ){
|
||||
regDistinct = regAgg+jj;
|
||||
sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP);
|
||||
jj += nArg;
|
||||
}
|
||||
if( pF->bUseSubtype ){
|
||||
int kk;
|
||||
int regBase = pF->bOBPayload ? regDistinct : regAgg;
|
||||
for(kk=0; kk<nArg; kk++, jj++){
|
||||
sqlite3VdbeAddOp2(v, OP_GetSubtype, regBase+kk, regAgg+jj);
|
||||
}
|
||||
}
|
||||
}else if( pList ){
|
||||
nArg = pList->nExpr;
|
||||
@@ -7037,7 +7060,8 @@ static SrcItem *isSelfJoinView(
|
||||
/*
|
||||
** Deallocate a single AggInfo object
|
||||
*/
|
||||
static void agginfoFree(sqlite3 *db, AggInfo *p){
|
||||
static void agginfoFree(sqlite3 *db, void *pArg){
|
||||
AggInfo *p = (AggInfo*)pArg;
|
||||
sqlite3DbFree(db, p->aCol);
|
||||
sqlite3DbFree(db, p->aFunc);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
@@ -7111,7 +7135,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
pSub->selFlags |= SF_Aggregate;
|
||||
pSub->selFlags &= ~SF_Compound;
|
||||
pSub->nSelectRow = 0;
|
||||
sqlite3ExprListDelete(db, pSub->pEList);
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList);
|
||||
pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
|
||||
pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
|
||||
pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
|
||||
@@ -7291,9 +7315,8 @@ int sqlite3Select(
|
||||
sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY");
|
||||
}
|
||||
#endif
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3ExprListDelete,
|
||||
p->pOrderBy);
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric,
|
||||
p->pOrderBy);
|
||||
testcase( pParse->earlyCleanup );
|
||||
p->pOrderBy = 0;
|
||||
}
|
||||
@@ -7485,9 +7508,8 @@ int sqlite3Select(
|
||||
){
|
||||
TREETRACE(0x800,pParse,p,
|
||||
("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1));
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3ExprListDelete,
|
||||
pSub->pOrderBy);
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric,
|
||||
pSub->pOrderBy);
|
||||
pSub->pOrderBy = 0;
|
||||
}
|
||||
|
||||
@@ -8016,8 +8038,7 @@ int sqlite3Select(
|
||||
*/
|
||||
pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
|
||||
if( pAggInfo ){
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))agginfoFree, pAggInfo);
|
||||
sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo);
|
||||
testcase( pParse->earlyCleanup );
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
|
||||
+26
-16
@@ -439,7 +439,7 @@ static void endTimer(void){
|
||||
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
|
||||
sqlite3_int64 ftWallEnd = timeOfDay();
|
||||
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
|
||||
oputf("Run Time: real %.3f user %f sys %f\n",
|
||||
sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
|
||||
(ftWallEnd - ftWallBegin)*0.001,
|
||||
timeDiff(&ftUserBegin, &ftUserEnd),
|
||||
timeDiff(&ftKernelBegin, &ftKernelEnd));
|
||||
@@ -736,14 +736,14 @@ static int strlenChar(const char *z){
|
||||
*/
|
||||
static FILE * openChrSource(const char *zFile){
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
struct _stat x = {0};
|
||||
struct __stat64 x = {0};
|
||||
# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
|
||||
/* On Windows, open first, then check the stream nature. This order
|
||||
** is necessary because _stat() and sibs, when checking a named pipe,
|
||||
** effectively break the pipe as its supplier sees it. */
|
||||
FILE *rv = fopen(zFile, "rb");
|
||||
if( rv==0 ) return 0;
|
||||
if( _fstat(_fileno(rv), &x) != 0
|
||||
if( _fstat64(_fileno(rv), &x) != 0
|
||||
|| !STAT_CHR_SRC(x.st_mode)){
|
||||
fclose(rv);
|
||||
rv = 0;
|
||||
@@ -5319,7 +5319,6 @@ static void open_db(ShellState *p, int openFlags){
|
||||
break;
|
||||
}
|
||||
}
|
||||
globalDb = p->db;
|
||||
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
|
||||
eputf("Error: unable to open database \"%s\": %s\n",
|
||||
zDbFilename, sqlite3_errmsg(p->db));
|
||||
@@ -5336,6 +5335,7 @@ static void open_db(ShellState *p, int openFlags){
|
||||
zDbFilename);
|
||||
}
|
||||
}
|
||||
globalDb = p->db;
|
||||
sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0);
|
||||
|
||||
/* Reflect the use or absence of --unsafe-testing invocation. */
|
||||
@@ -10756,6 +10756,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
{"fk_no_action", SQLITE_TESTCTRL_FK_NO_ACTION, 0, "BOOLEAN" },
|
||||
{"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
|
||||
{"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" },
|
||||
{"json_selfcheck", SQLITE_TESTCTRL_JSON_SELFCHECK ,0,"BOOLEAN" },
|
||||
{"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" },
|
||||
{"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" },
|
||||
{"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" },
|
||||
@@ -10974,6 +10975,16 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
isOk = 3;
|
||||
}
|
||||
break;
|
||||
case SQLITE_TESTCTRL_JSON_SELFCHECK:
|
||||
if( nArg==2 ){
|
||||
rc2 = -1;
|
||||
isOk = 1;
|
||||
}else{
|
||||
rc2 = booleanValue(azArg[2]);
|
||||
isOk = 3;
|
||||
}
|
||||
sqlite3_test_control(testctrl, &rc2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( isOk==0 && iCtrl>=0 ){
|
||||
@@ -11860,14 +11871,14 @@ static void printBold(const char *zText){
|
||||
FOREGROUND_RED|FOREGROUND_INTENSITY
|
||||
);
|
||||
#endif
|
||||
oputz(zText);
|
||||
sputz(stdout, zText);
|
||||
#if !SQLITE_OS_WINRT
|
||||
SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static void printBold(const char *zText){
|
||||
oputf("\033[1m%s\033[0m", zText);
|
||||
sputf(stdout, "\033[1m%s\033[0m", zText);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -12061,10 +12072,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
}else if( cli_strcmp(z,"-init")==0 ){
|
||||
zInitFile = cmdline_option_value(argc, argv, ++i);
|
||||
}else if( cli_strcmp(z,"-interactive")==0 ){
|
||||
/* Need to check for interactive override here to so that it can
|
||||
** affect console setup (for Windows only) and testing thereof.
|
||||
*/
|
||||
stdin_is_interactive = 1;
|
||||
}else if( cli_strcmp(z,"-batch")==0 ){
|
||||
/* Need to check for batch mode here to so we can avoid printing
|
||||
** informational messages (like from process_sqliterc) before
|
||||
@@ -12334,11 +12341,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
}else if( cli_strcmp(z,"-bail")==0 ){
|
||||
/* No-op. The bail_on_error flag should already be set. */
|
||||
}else if( cli_strcmp(z,"-version")==0 ){
|
||||
oputf("%s %s (%d-bit)\n", sqlite3_libversion(), sqlite3_sourceid(),
|
||||
8*(int)sizeof(char*));
|
||||
sputf(stdout, "%s %s (%d-bit)\n",
|
||||
sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
|
||||
return 0;
|
||||
}else if( cli_strcmp(z,"-interactive")==0 ){
|
||||
/* already handled */
|
||||
/* Need to check for interactive override here to so that it can
|
||||
** affect console setup (for Windows only) and testing thereof.
|
||||
*/
|
||||
stdin_is_interactive = 1;
|
||||
}else if( cli_strcmp(z,"-batch")==0 ){
|
||||
/* already handled */
|
||||
}else if( cli_strcmp(z,"-utf8")==0 ){
|
||||
@@ -12467,13 +12477,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
#else
|
||||
# define SHELL_CIO_CHAR_SET ""
|
||||
#endif
|
||||
oputf("SQLite version %s %.19s%s\n" /*extra-version-info*/
|
||||
sputf(stdout, "SQLite version %s %.19s%s\n" /*extra-version-info*/
|
||||
"Enter \".help\" for usage hints.\n",
|
||||
sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
|
||||
if( warnInmemoryDb ){
|
||||
oputz("Connected to a ");
|
||||
sputz(stdout, "Connected to a ");
|
||||
printBold("transient in-memory database");
|
||||
oputz(".\nUse \".open FILENAME\" to reopen on a"
|
||||
sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a"
|
||||
" persistent database.\n");
|
||||
}
|
||||
zHistory = getenv("SQLITE_HISTORY");
|
||||
|
||||
+6
-3
@@ -8039,9 +8039,11 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
**
|
||||
** ^(Some systems (for example, Windows 95) do not support the operation
|
||||
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
|
||||
** will always return SQLITE_BUSY. The SQLite core only ever uses
|
||||
** sqlite3_mutex_try() as an optimization so this is acceptable
|
||||
** behavior.)^
|
||||
** will always return SQLITE_BUSY. In most cases the SQLite core only uses
|
||||
** sqlite3_mutex_try() as an optimization, so this is acceptable
|
||||
** behavior. The exceptions are unix builds that set the
|
||||
** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
|
||||
** sqlite3_mutex_try() is required.)^
|
||||
**
|
||||
** ^The sqlite3_mutex_leave() routine exits a mutex that was
|
||||
** previously entered by the same thread. The behavior
|
||||
@@ -8300,6 +8302,7 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_ASSERT 12
|
||||
#define SQLITE_TESTCTRL_ALWAYS 13
|
||||
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
|
||||
#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
|
||||
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
|
||||
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
|
||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
|
||||
|
||||
@@ -328,6 +328,19 @@
|
||||
# undef SQLITE_USE_SEH
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Enable SQLITE_DIRECT_OVERFLOW_READ, unless the build explicitly
|
||||
** disables it using -DSQLITE_DIRECT_OVERFLOW_READ=0
|
||||
*/
|
||||
#if defined(SQLITE_DIRECT_OVERFLOW_READ) && SQLITE_DIRECT_OVERFLOW_READ+1==1
|
||||
/* Disable if -DSQLITE_DIRECT_OVERFLOW_READ=0 */
|
||||
# undef SQLITE_DIRECT_OVERFLOW_READ
|
||||
#else
|
||||
/* In all other cases, enable */
|
||||
# define SQLITE_DIRECT_OVERFLOW_READ 1
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
|
||||
** 0 means mutexes are permanently disable and the library is never
|
||||
@@ -2753,6 +2766,7 @@ struct Index {
|
||||
unsigned isCovering:1; /* True if this is a covering index */
|
||||
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
|
||||
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
|
||||
unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */
|
||||
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
|
||||
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
|
||||
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
|
||||
@@ -2866,6 +2880,7 @@ struct AggInfo {
|
||||
int iOBTab; /* Ephemeral table to implement ORDER BY */
|
||||
u8 bOBPayload; /* iOBTab has payload columns separate from key */
|
||||
u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */
|
||||
u8 bUseSubtype; /* Transfer subtype info through sorter */
|
||||
} *aFunc;
|
||||
int nFunc; /* Number of entries in aFunc[] */
|
||||
u32 selId; /* Select to which this AggInfo belongs */
|
||||
@@ -4116,6 +4131,9 @@ struct sqlite3_str {
|
||||
**
|
||||
** 3. Make a (read-only) copy of a read-only RCStr string using
|
||||
** sqlite3RCStrRef().
|
||||
**
|
||||
** "String" is in the name, but an RCStr object can also be used to hold
|
||||
** binary data.
|
||||
*/
|
||||
struct RCStr {
|
||||
u64 nRCRef; /* Number of references */
|
||||
@@ -4174,6 +4192,9 @@ struct Sqlite3Config {
|
||||
u8 bSmallMalloc; /* Avoid large memory allocations if true */
|
||||
u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
|
||||
u8 bUseLongDouble; /* Make use of long double */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 bJsonSelfcheck; /* Double-check JSON parsing */
|
||||
#endif
|
||||
int mxStrlen; /* Maximum string length */
|
||||
int neverCorrupt; /* Database is always well-formed */
|
||||
int szLookaside; /* Default lookaside buffer size */
|
||||
@@ -4800,6 +4821,7 @@ void sqlite3ExprOrderByAggregateError(Parse*,Expr*);
|
||||
void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
|
||||
void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
|
||||
void sqlite3ExprDelete(sqlite3*, Expr*);
|
||||
void sqlite3ExprDeleteGeneric(sqlite3*,void*);
|
||||
void sqlite3ExprDeferredDelete(Parse*, Expr*);
|
||||
void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
|
||||
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
|
||||
@@ -4809,6 +4831,7 @@ void sqlite3ExprListSetSortOrder(ExprList*,int,int);
|
||||
void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int);
|
||||
void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
|
||||
void sqlite3ExprListDelete(sqlite3*, ExprList*);
|
||||
void sqlite3ExprListDeleteGeneric(sqlite3*,void*);
|
||||
u32 sqlite3ExprListFlags(const ExprList*);
|
||||
int sqlite3IndexHasDuplicateRootPage(Index*);
|
||||
int sqlite3Init(sqlite3*, char**);
|
||||
@@ -4899,6 +4922,7 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
|
||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||
void sqlite3CodeDropTable(Parse*, Table*, int, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
void sqlite3DeleteTableGeneric(sqlite3*, void*);
|
||||
void sqlite3FreeIndex(sqlite3*, Index*);
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
void sqlite3AutoincrementBegin(Parse *pParse);
|
||||
@@ -4935,6 +4959,7 @@ int sqlite3Select(Parse*, Select*, SelectDest*);
|
||||
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
|
||||
Expr*,ExprList*,u32,Expr*);
|
||||
void sqlite3SelectDelete(sqlite3*, Select*);
|
||||
void sqlite3SelectDeleteGeneric(sqlite3*,void*);
|
||||
Table *sqlite3SrcListLookup(Parse*, SrcList*);
|
||||
int sqlite3IsReadOnly(Parse*, Table*, Trigger*);
|
||||
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
||||
@@ -5161,6 +5186,7 @@ int sqlite3Utf16ByteLen(const void *pData, int nChar);
|
||||
#endif
|
||||
int sqlite3Utf8CharLen(const char *pData, int nByte);
|
||||
u32 sqlite3Utf8Read(const u8**);
|
||||
int sqlite3Utf8ReadLimited(const u8*, int, u32*);
|
||||
LogEst sqlite3LogEst(u64);
|
||||
LogEst sqlite3LogEstAdd(LogEst,LogEst);
|
||||
LogEst sqlite3LogEstFromDouble(double);
|
||||
@@ -5507,6 +5533,7 @@ const char *sqlite3JournalModename(int);
|
||||
void sqlite3CteDelete(sqlite3*,Cte*);
|
||||
With *sqlite3WithAdd(Parse*,With*,Cte*);
|
||||
void sqlite3WithDelete(sqlite3*,With*);
|
||||
void sqlite3WithDeleteGeneric(sqlite3*,void*);
|
||||
With *sqlite3WithPush(Parse*, With*, u8);
|
||||
#else
|
||||
# define sqlite3CteNew(P,T,E,S) ((void*)0)
|
||||
|
||||
+1
-1
@@ -187,7 +187,7 @@
|
||||
** max_page_count macro.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_PAGE_COUNT
|
||||
# define SQLITE_MAX_PAGE_COUNT 1073741823
|
||||
# define SQLITE_MAX_PAGE_COUNT 0xfffffffe /* 4294967294 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
+2
-2
@@ -362,7 +362,7 @@ int sqlite3_db_status(
|
||||
case SQLITE_DBSTATUS_CACHE_MISS:
|
||||
case SQLITE_DBSTATUS_CACHE_WRITE:{
|
||||
int i;
|
||||
int nRet = 0;
|
||||
u64 nRet = 0;
|
||||
assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
|
||||
assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
|
||||
|
||||
@@ -375,7 +375,7 @@ int sqlite3_db_status(
|
||||
*pHighwater = 0; /* IMP: R-42420-56072 */
|
||||
/* IMP: R-54100-20147 */
|
||||
/* IMP: R-29431-39229 */
|
||||
*pCurrent = nRet;
|
||||
*pCurrent = (int)nRet & 0x7fffffff;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -8120,6 +8120,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
extern int sqlite3_prefixes_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
#endif
|
||||
extern int sqlite3_qpvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_randomjson_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
@@ -8152,6 +8153,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
{ "prefixes", sqlite3_prefixes_init },
|
||||
#endif
|
||||
{ "qpvtab", sqlite3_qpvtab_init },
|
||||
{ "randomjson", sqlite3_randomjson_init },
|
||||
{ "regexp", sqlite3_regexp_init },
|
||||
{ "remember", sqlite3_remember_init },
|
||||
{ "series", sqlite3_series_init },
|
||||
|
||||
+2
-1
@@ -694,7 +694,8 @@ static int registerTestFunctions(
|
||||
{ "test_extract", 2, SQLITE_UTF8, test_extract},
|
||||
{ "test_zeroblob", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, test_zeroblob},
|
||||
{ "test_getsubtype", 1, SQLITE_UTF8, test_getsubtype},
|
||||
{ "test_setsubtype", 2, SQLITE_UTF8, test_setsubtype},
|
||||
{ "test_setsubtype", 2, SQLITE_UTF8|SQLITE_RESULT_SUBTYPE,
|
||||
test_setsubtype},
|
||||
{ "test_frombind", -1, SQLITE_UTF8, test_frombind},
|
||||
};
|
||||
int i;
|
||||
|
||||
@@ -164,7 +164,38 @@ u32 sqlite3Utf8Read(
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Read a single UTF8 character out of buffer z[], but reading no
|
||||
** more than n characters from the buffer. z[] is not zero-terminated.
|
||||
**
|
||||
** Return the number of bytes used to construct the character.
|
||||
**
|
||||
** Invalid UTF8 might generate a strange result. No effort is made
|
||||
** to detect invalid UTF8.
|
||||
**
|
||||
** At most 4 bytes will be read out of z[]. The return value will always
|
||||
** be between 1 and 4.
|
||||
*/
|
||||
int sqlite3Utf8ReadLimited(
|
||||
const u8 *z,
|
||||
int n,
|
||||
u32 *piOut
|
||||
){
|
||||
u32 c;
|
||||
int i = 1;
|
||||
assert( n>0 );
|
||||
c = z[0];
|
||||
if( c>=0xc0 ){
|
||||
c = sqlite3Utf8Trans1[c-0xc0];
|
||||
if( n>4 ) n = 4;
|
||||
while( i<n && (z[i] & 0xc0)==0x80 ){
|
||||
c = (c<<6) + (0x3f & z[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
*piOut = c;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ void sqlite3ErrorClear(sqlite3 *db){
|
||||
*/
|
||||
void sqlite3SystemError(sqlite3 *db, int rc){
|
||||
if( rc==SQLITE_IOERR_NOMEM ) return;
|
||||
#ifdef SQLITE_USE_SEH
|
||||
#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
|
||||
if( rc==SQLITE_IOERR_IN_PAGE ){
|
||||
int ii;
|
||||
int iErr;
|
||||
|
||||
+38
-3
@@ -8180,9 +8180,10 @@ case OP_VCheck: { /* out2 */
|
||||
|
||||
pOut = &aMem[pOp->p2];
|
||||
sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */
|
||||
assert( pOp->p4type==P4_TABLE );
|
||||
assert( pOp->p4type==P4_TABLEREF );
|
||||
pTab = pOp->p4.pTab;
|
||||
assert( pTab!=0 );
|
||||
assert( pTab->nTabRef>0 );
|
||||
assert( IsVirtual(pTab) );
|
||||
if( pTab->u.vtab.p==0 ) break;
|
||||
pVtab = pTab->u.vtab.p->pVtab;
|
||||
@@ -8191,13 +8192,11 @@ case OP_VCheck: { /* out2 */
|
||||
assert( pModule!=0 );
|
||||
assert( pModule->iVersion>=4 );
|
||||
assert( pModule->xIntegrity!=0 );
|
||||
pTab->nTabRef++;
|
||||
sqlite3VtabLock(pTab->u.vtab.p);
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName,
|
||||
pOp->p3, &zErr);
|
||||
sqlite3VtabUnlock(pTab->u.vtab.p);
|
||||
sqlite3DeleteTable(db, pTab);
|
||||
if( rc ){
|
||||
sqlite3_free(zErr);
|
||||
goto abort_due_to_error;
|
||||
@@ -8675,6 +8674,42 @@ case OP_ClrSubtype: { /* in1 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: GetSubtype P1 P2 * * *
|
||||
** Synopsis: r[P2] = r[P1].subtype
|
||||
**
|
||||
** Extract the subtype value from register P1 and write that subtype
|
||||
** into register P2. If P1 has no subtype, then P1 gets a NULL.
|
||||
*/
|
||||
case OP_GetSubtype: { /* in1 out2 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
pOut = &aMem[pOp->p2];
|
||||
if( pIn1->flags & MEM_Subtype ){
|
||||
sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype);
|
||||
}else{
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SetSubtype P1 P2 * * *
|
||||
** Synopsis: r[P2].subtype = r[P1]
|
||||
**
|
||||
** Set the subtype value of register P2 to the integer from register P1.
|
||||
** If P1 is NULL, clear the subtype from p2.
|
||||
*/
|
||||
case OP_SetSubtype: { /* in1 out2 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
pOut = &aMem[pOp->p2];
|
||||
if( pIn1->flags & MEM_Null ){
|
||||
pOut->flags &= ~MEM_Subtype;
|
||||
}else{
|
||||
assert( pIn1->flags & MEM_Int );
|
||||
pOut->flags |= MEM_Subtype;
|
||||
pOut->eSubtype = (u8)(pIn1->u.i & 0xff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: FilterAdd P1 * P3 P4 *
|
||||
** Synopsis: filter(P1) += key(P3@P4)
|
||||
**
|
||||
|
||||
@@ -126,6 +126,7 @@ typedef struct VdbeOpList VdbeOpList;
|
||||
#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
|
||||
#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
|
||||
#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */
|
||||
#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */
|
||||
|
||||
/* Error message codes for OP_Halt */
|
||||
#define P5_ConstraintNotNull 1
|
||||
|
||||
@@ -1400,6 +1400,10 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
|
||||
break;
|
||||
}
|
||||
case P4_TABLEREF: {
|
||||
if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -315,7 +315,6 @@ void sqlite3VtabUnlockList(sqlite3 *db){
|
||||
|
||||
if( p ){
|
||||
db->pDisconnect = 0;
|
||||
sqlite3ExpirePreparedStatements(db, 0);
|
||||
do {
|
||||
VTable *pNext = p->pNext;
|
||||
sqlite3VtabUnlock(p);
|
||||
|
||||
@@ -2004,6 +2004,19 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
|
||||
|
||||
/*
|
||||
** Attempt to enable blocking locks that block for nMs ms. Return 1 if
|
||||
** blocking locks are successfully enabled, or 0 otherwise.
|
||||
*/
|
||||
static int walEnableBlockingMs(Wal *pWal, int nMs){
|
||||
int rc = sqlite3OsFileControl(
|
||||
pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs
|
||||
);
|
||||
return (rc==SQLITE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
|
||||
** they are supported by the VFS, and (b) the database handle is configured
|
||||
@@ -2015,11 +2028,7 @@ static int walEnableBlocking(Wal *pWal){
|
||||
if( pWal->db ){
|
||||
int tmout = pWal->db->busyTimeout;
|
||||
if( tmout ){
|
||||
int rc;
|
||||
rc = sqlite3OsFileControl(
|
||||
pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
|
||||
);
|
||||
res = (rc==SQLITE_OK);
|
||||
res = walEnableBlockingMs(pWal, tmout);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@@ -2068,20 +2077,10 @@ void sqlite3WalDb(Wal *pWal, sqlite3 *db){
|
||||
pWal->db = db;
|
||||
}
|
||||
|
||||
/*
|
||||
** Take an exclusive WRITE lock. Blocking if so configured.
|
||||
*/
|
||||
static int walLockWriter(Wal *pWal){
|
||||
int rc;
|
||||
walEnableBlocking(pWal);
|
||||
rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
walDisableBlocking(pWal);
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
# define walEnableBlocking(x) 0
|
||||
# define walDisableBlocking(x)
|
||||
# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
|
||||
# define walEnableBlockingMs(pWal, ms) 0
|
||||
# define sqlite3WalDb(pWal, db)
|
||||
#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
|
||||
|
||||
@@ -2682,7 +2681,9 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
||||
}
|
||||
}else{
|
||||
int bWriteLock = pWal->writeLock;
|
||||
if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
|
||||
if( bWriteLock
|
||||
|| SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
|
||||
){
|
||||
pWal->writeLock = 1;
|
||||
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
||||
badHdr = walIndexTryHdr(pWal, pChanged);
|
||||
@@ -2690,7 +2691,8 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
||||
/* If the wal-index header is still malformed even while holding
|
||||
** a WRITE lock, it can only mean that the header is corrupted and
|
||||
** needs to be reconstructed. So run recovery to do exactly that.
|
||||
*/
|
||||
** Disable blocking locks first. */
|
||||
walDisableBlocking(pWal);
|
||||
rc = walIndexRecover(pWal);
|
||||
*pChanged = 1;
|
||||
}
|
||||
@@ -2957,6 +2959,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
int i; /* Loop counter */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
u32 mxFrame; /* Wal frame to lock to */
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
int nBlockTmout = 0;
|
||||
#endif
|
||||
|
||||
assert( pWal->readLock<0 ); /* Not currently locked */
|
||||
|
||||
@@ -2987,6 +2992,19 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
return SQLITE_PROTOCOL;
|
||||
}
|
||||
if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
/* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor
|
||||
** to block for locks for approximately nDelay us. This affects three
|
||||
** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if
|
||||
** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the
|
||||
** first attempted read fails, and (c) the shared lock taken on the DMS
|
||||
** slot in os_unix.c. All three of these locks are attempted from within
|
||||
** the call to walIndexReadHdr() below. */
|
||||
nBlockTmout = (nDelay+998) / 1000;
|
||||
if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){
|
||||
nDelay = 1;
|
||||
}
|
||||
#endif
|
||||
sqlite3OsSleep(pWal->pVfs, nDelay);
|
||||
}
|
||||
|
||||
@@ -2995,6 +3013,10 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
if( pWal->bShmUnreliable==0 ){
|
||||
rc = walIndexReadHdr(pWal, pChanged);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
walDisableBlocking(pWal);
|
||||
if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
|
||||
#endif
|
||||
if( rc==SQLITE_BUSY ){
|
||||
/* If there is not a recovery running in another thread or process
|
||||
** then convert BUSY errors to WAL_RETRY. If recovery is known to
|
||||
@@ -3109,9 +3131,12 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
|
||||
}
|
||||
|
||||
(void)walEnableBlockingMs(pWal, nBlockTmout);
|
||||
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
|
||||
walDisableBlocking(pWal);
|
||||
if( rc ){
|
||||
return rc==SQLITE_BUSY ? WAL_RETRY : rc;
|
||||
assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT );
|
||||
return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc;
|
||||
}
|
||||
/* Now that the read-lock has been obtained, check that neither the
|
||||
** value in the aReadMark[] array or the contents of the wal-index
|
||||
@@ -3480,6 +3505,7 @@ static int walFindFrame(
|
||||
iRead = iFrame;
|
||||
}
|
||||
if( (nCollide--)==0 ){
|
||||
*piRead = 0;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
iKey = walNextHash(iKey);
|
||||
|
||||
+87
-35
@@ -2020,7 +2020,8 @@ static int whereRangeScanEst(
|
||||
** sample, then assume they are 4x more selective. This brings
|
||||
** the estimated selectivity more in line with what it would be
|
||||
** if estimated without the use of STAT4 tables. */
|
||||
if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) );
|
||||
if( iLwrIdx==iUprIdx ){ nNew -= 20; }
|
||||
assert( 20==sqlite3LogEst(4) );
|
||||
}else{
|
||||
nNew = 10; assert( 10==sqlite3LogEst(2) );
|
||||
}
|
||||
@@ -2244,17 +2245,34 @@ void sqlite3WhereClausePrint(WhereClause *pWC){
|
||||
#ifdef WHERETRACE_ENABLED
|
||||
/*
|
||||
** Print a WhereLoop object for debugging purposes
|
||||
**
|
||||
** Format example:
|
||||
**
|
||||
** .--- Position in WHERE clause rSetup, rRun, nOut ---.
|
||||
** | |
|
||||
** | .--- selfMask nTerm ------. |
|
||||
** | | | |
|
||||
** | | .-- prereq Idx wsFlags----. | |
|
||||
** | | | Name | | |
|
||||
** | | | __|__ nEq ---. ___|__ | __|__
|
||||
** | / \ / \ / \ | / \ / \ / \
|
||||
** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31
|
||||
*/
|
||||
void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
|
||||
WhereInfo *pWInfo = pWC->pWInfo;
|
||||
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
|
||||
Table *pTab = pItem->pTab;
|
||||
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
|
||||
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
|
||||
sqlite3DebugPrintf(" %12s",
|
||||
pItem->zAlias ? pItem->zAlias : pTab->zName);
|
||||
void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
|
||||
if( pWC ){
|
||||
WhereInfo *pWInfo = pWC->pWInfo;
|
||||
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
|
||||
Table *pTab = pItem->pTab;
|
||||
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
|
||||
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
|
||||
sqlite3DebugPrintf(" %12s",
|
||||
pItem->zAlias ? pItem->zAlias : pTab->zName);
|
||||
}else{
|
||||
sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d",
|
||||
p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab);
|
||||
}
|
||||
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
|
||||
const char *zName;
|
||||
if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
|
||||
@@ -2291,6 +2309,15 @@ void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
|
||||
}
|
||||
}
|
||||
}
|
||||
void sqlite3ShowWhereLoop(const WhereLoop *p){
|
||||
if( p ) sqlite3WhereLoopPrint(p, 0);
|
||||
}
|
||||
void sqlite3ShowWhereLoopList(const WhereLoop *p){
|
||||
while( p ){
|
||||
sqlite3ShowWhereLoop(p);
|
||||
p = p->pNextLoop;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -2403,46 +2430,60 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if all of the following are true:
|
||||
** Return TRUE if X is a proper subset of Y but is of equal or less cost.
|
||||
** In other words, return true if all constraints of X are also part of Y
|
||||
** and Y has additional constraints that might speed the search that X lacks
|
||||
** but the cost of running X is not more than the cost of running Y.
|
||||
**
|
||||
** (1) X has the same or lower cost, or returns the same or fewer rows,
|
||||
** than Y.
|
||||
** (2) X uses fewer WHERE clause terms than Y
|
||||
** (3) Every WHERE clause term used by X is also used by Y
|
||||
** (4) X skips at least as many columns as Y
|
||||
** (5) If X is a covering index, than Y is too
|
||||
** In other words, return true if the cost relationwship between X and Y
|
||||
** is inverted and needs to be adjusted.
|
||||
**
|
||||
** Conditions (2) and (3) mean that X is a "proper subset" of Y.
|
||||
** If X is a proper subset of Y then Y is a better choice and ought
|
||||
** to have a lower cost. This routine returns TRUE when that cost
|
||||
** relationship is inverted and needs to be adjusted. Constraint (4)
|
||||
** was added because if X uses skip-scan less than Y it still might
|
||||
** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
|
||||
** was added because a covering index probably deserves to have a lower cost
|
||||
** than a non-covering index even if it is a proper subset.
|
||||
** Case 1:
|
||||
**
|
||||
** (1a) X and Y use the same index.
|
||||
** (1b) X has fewer == terms than Y
|
||||
** (1c) Neither X nor Y use skip-scan
|
||||
** (1d) X does not have a a greater cost than Y
|
||||
**
|
||||
** Case 2:
|
||||
**
|
||||
** (2a) X has the same or lower cost, or returns the same or fewer rows,
|
||||
** than Y.
|
||||
** (2b) X uses fewer WHERE clause terms than Y
|
||||
** (2c) Every WHERE clause term used by X is also used by Y
|
||||
** (2d) X skips at least as many columns as Y
|
||||
** (2e) If X is a covering index, than Y is too
|
||||
*/
|
||||
static int whereLoopCheaperProperSubset(
|
||||
const WhereLoop *pX, /* First WhereLoop to compare */
|
||||
const WhereLoop *pY /* Compare against this WhereLoop */
|
||||
){
|
||||
int i, j;
|
||||
if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
|
||||
return 0; /* X is not a subset of Y */
|
||||
if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; /* (1d) and (2a) */
|
||||
assert( (pX->wsFlags & WHERE_VIRTUALTABLE)==0 );
|
||||
assert( (pY->wsFlags & WHERE_VIRTUALTABLE)==0 );
|
||||
if( pX->u.btree.nEq < pY->u.btree.nEq /* (1b) */
|
||||
&& pX->u.btree.pIndex==pY->u.btree.pIndex /* (1a) */
|
||||
&& pX->nSkip==0 && pY->nSkip==0 /* (1c) */
|
||||
){
|
||||
return 1; /* Case 1 is true */
|
||||
}
|
||||
if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0;
|
||||
if( pY->nSkip > pX->nSkip ) return 0;
|
||||
if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
|
||||
return 0; /* (2b) */
|
||||
}
|
||||
if( pY->nSkip > pX->nSkip ) return 0; /* (2d) */
|
||||
for(i=pX->nLTerm-1; i>=0; i--){
|
||||
if( pX->aLTerm[i]==0 ) continue;
|
||||
for(j=pY->nLTerm-1; j>=0; j--){
|
||||
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
|
||||
}
|
||||
if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
|
||||
if( j<0 ) return 0; /* (2c) */
|
||||
}
|
||||
if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
|
||||
&& (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
|
||||
return 0; /* Constraint (5) */
|
||||
return 0; /* (2e) */
|
||||
}
|
||||
return 1; /* All conditions meet */
|
||||
return 1; /* Case 2 is true */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2932,7 +2973,10 @@ static int whereLoopAddBtreeIndex(
|
||||
assert( pNew->u.btree.nBtm==0 );
|
||||
opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
|
||||
}
|
||||
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
|
||||
if( pProbe->bUnordered || pProbe->bLowQual ){
|
||||
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
|
||||
if( pProbe->bLowQual ) opMask &= ~(WO_EQ|WO_IN|WO_IS);
|
||||
}
|
||||
|
||||
assert( pNew->u.btree.nEq<pProbe->nColumn );
|
||||
assert( pNew->u.btree.nEq<pProbe->nKeyCol
|
||||
@@ -6037,7 +6081,10 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** field (type Bitmask) it must be aligned on an 8-byte boundary on
|
||||
** some architectures. Hence the ROUND8() below.
|
||||
*/
|
||||
nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
|
||||
nByteWInfo = ROUND8P(sizeof(WhereInfo));
|
||||
if( nTabList>1 ){
|
||||
nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel));
|
||||
}
|
||||
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DbFree(db, pWInfo);
|
||||
@@ -6599,6 +6646,11 @@ whereBeginError:
|
||||
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
|
||||
whereInfoFree(db, pWInfo);
|
||||
}
|
||||
#ifdef WHERETRACE_ENABLED
|
||||
/* Prevent harmless compiler warnings about debugging routines
|
||||
** being declared but never used */
|
||||
sqlite3ShowWhereLoopList(0);
|
||||
#endif /* WHERETRACE_ENABLED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user