Compare commits

..

25 Commits

Author SHA1 Message Date
drh 43fa051ec7 Version 3.43.2
FossilOrigin-Name: 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790
2023-10-10 12:14:04 +00:00
drh 1a39e85292 Use snprintf() in place of sprintf() in a debugging function in the CLI.
FossilOrigin-Name: 88a118905b95bd82e15c3c1e63a7620071ab9ab3517b77820553fcd7e600b0c8
2023-10-09 22:50:30 +00:00
drh db1e112d2d Add a TCL script that does various verification checks on the source tree
to make sure that generated code has been updated correctly.

FossilOrigin-Name: dc8681c4864f1973ce6d667cc4670e3800bc8e39b44944da7de74faa715bc434
2023-10-09 14:59:42 +00:00
drh c6d29559fb Change the TEA version number to 3.43.2 also.
FossilOrigin-Name: 170ab8d102424994fd3f1e7d9ef94a3f6814de70cdc6ded4e571df264825b620
2023-10-09 14:12:44 +00:00
drh 7a37af268c Update the version number to 3.43.2.
FossilOrigin-Name: 0bd1199bb3f7bd3fcc421d2c3834d04c35cbfd611457554e4f9f9a992c4bf1f5
2023-10-09 14:10:07 +00:00
drh 3736d87422 Fix a potential UAF caused by JSON parser cache spill.
FossilOrigin-Name: 5b09212ac05615fc21bed41c069b5083345194f1ed969cf162f0784e03aa0d60
2023-10-09 12:51:58 +00:00
drh 436e85b49b Fix a resource leak: sqlite3_blob_reopen() was failing to invoke the
xDel() distructor on a register when it sets that register to the new
rowid.

FossilOrigin-Name: 83846af5df1c91ffe3a9feb5833e818702eca8395d46d9303bb0f15077ebd703
2023-10-07 08:11:38 +00:00
drh ac3704e5d8 Improved detection of corrupt databases in balance_nonroot().
dbsqlfuzz d1cf013c50a620b68c2a5bd240d29afd65e5f58e.

FossilOrigin-Name: f4aa1bfc97e7c5e04462dfa0152c0ced37a5b342782c0efe4966ebda977c5ea5
2023-10-05 11:09:07 +00:00
stephan f5eb69d009 Correct an undefined-value deref in the JS bindings, triggered by passing invalid args and then tripping over an undefined value while trying to report that. Reported in [forum:dd42df144651d779|forum post dd42df144651d779].
FossilOrigin-Name: 1545f0f7359d00ed47fce6be029e0c4d87ec092cdf9e609f86e0e5b93412c8a4
2023-09-30 13:16:15 +00:00
drh 181ed2dcb9 Do not try to convert a double into an unsigned 64-bit integer, as that does
not work on all platforms.  A double can only be converted into a signed
64-bit integer.

FossilOrigin-Name: 4ce5a03e7436fbe93baa746312014d8b04cde0787066989f60c2454a42e817d6
2023-09-15 10:27:34 +00:00
drh 666d20ef72 Fix a use-after-free error in fts5 that could occur when querying the "rank" column immediately after another connection changes its definition.
FossilOrigin-Name: dfc42411e6630325691176439e662c1cf46cbc6923b5c11836de1f43ecfe0b7d
2023-09-12 23:11:44 +00:00
drh 861f12b3a4 Remove a harmlessly unused variable from FTS5.
FossilOrigin-Name: 958d62c7773e009df10b121ee8a74a8f502ac9c5643422ad73893f8d10479249
2023-09-11 15:35:02 +00:00
drh 5f48099117 Refuse to build amalgamation-tarball and snapshot-tarball if the TEA version
number disagrees with ./VERSION.

FossilOrigin-Name: ad5cc3758b28bfc2370028695bde2615e7ebdbd26036de87031a04f5db22da5e
2023-09-11 15:28:31 +00:00
drh 89b364e116 Fix the TEA version number to be 3.43.1
FossilOrigin-Name: e00f1fedc9ec524a1b6fa5740865cd38828883f7bf53040e5826f69433ae1875
2023-09-11 15:04:59 +00:00
drh f1f6a0bba1 Version 3.43.1
FossilOrigin-Name: 2d3a40c05c49e1a49264912b1a05bc2143ac0e7c3df588276ce80a4cbc9bd1b0
2023-09-11 12:01:27 +00:00
drh 3f5717f192 Fix a problem with fts5 secure-delete mode causing fts5 to corrupt its records.
FossilOrigin-Name: fb24ca17fa1be739395fc471a8d4c9f876874c1709d41803925027b56587cf83
2023-09-08 19:35:02 +00:00
drh 4892d20b31 Fix a bad assert() in FTS3.
FossilOrigin-Name: 61d2074c695b011c51ea0e0e22051889e843e67dbc4b91c71f5b1b9177d0b9c8
2023-09-07 14:10:33 +00:00
drh 0a8b9b7884 Fix a buffer overread in the sessions extension that could occur when processing a corrupt changeset.
FossilOrigin-Name: 6009c871a48555efd2451b8b44d441548b9bdbc71141a52b81c1f4c7d99d3790
2023-09-07 14:04:01 +00:00
drh 9da6f3ab50 Version number to 3.43.1.
FossilOrigin-Name: fdfe4d60b3226516d497a57a3fb1c5ce52b8da368e7b9b9a301df7c6e0c9ebfd
2023-09-07 11:48:29 +00:00
stephan 4eeb32ce18 In the OPFS VFS' importDb() methods, overwrite the header bytes 18 and 19 with 1 instead of 0. Correct a potentially leaked/unclosed SharedAccessHandle when importDb() throws.
FossilOrigin-Name: 6795a6107bc8e6965c078fb4ddecbaae1f6a8e273effe4c8c0555358f0fbf32b
2023-09-01 11:30:55 +00:00
drh 213543b554 Do not disable unused columns in a UNION ALL sub-query if any component of the sub-query is DISTINCT.
FossilOrigin-Name: 0d50d27197f3566f65c2c37f175765a6c6e534d20c34994115a04a040fc3e446
2023-08-31 18:26:55 +00:00
drh 5baa631cea Fix a bug in json_array_length() introduced in version 3.43.0
If the JSON input comes from json_remove(),
the removed array entries are still counted as part of the array length.

FossilOrigin-Name: db7cb6cb73e606667f0ac52a2e84be6e755ae2792fc64e494ed08d0d3fab2863
2023-08-30 18:27:46 +00:00
drh 6541f01805 Fix the AVG() and TOTAL() functions so that they work with infinitites.
FossilOrigin-Name: 97e20716c7c5c9c96a693835f99692d4cea088edebb9e422057bcb59829b798f
2023-08-30 16:08:30 +00:00
drh f256437e5e Fix an issue with infinity handling by the SUM() function that goes back
to the extended-precision SUM() enhancement of
check-in c63e26e705f5e967.  Problem reported by
forum post 1c06ddcacc86032a.

FossilOrigin-Name: 692266abd107920ef8bec16c5e2c6226746948140dd8da17cdf2132fee4338f6
2023-08-28 12:57:30 +00:00
stephan 58c3d20baf Resolve a makefile bug which causes sqlite3-worker1-bundler-friendly.mjs to be built incorrectly. Reported in [forum:a874e435cf4690c1|forum post a874e435cf4690c1].
FossilOrigin-Name: 289d2a0e64d760aded18cd457fe06a55f3fa0bfd56914e7b41297e437861b4d9
2023-08-28 05:06:08 +00:00
335 changed files with 16002 additions and 34890 deletions
+30 -72
View File
@@ -57,7 +57,6 @@ LIBTCL = @TCL_LIB_SPEC@
#
READLINE_FLAGS = -DHAVE_READLINE=@TARGET_HAVE_READLINE@ @TARGET_READLINE_INC@
READLINE_FLAGS += -DHAVE_EDITLINE=@TARGET_HAVE_EDITLINE@
READLINE_FLAGS += -DHAVE_LINENOISE=@TARGET_HAVE_LINENOISE@
# The library that programs using readline() must link against.
#
@@ -707,24 +706,6 @@ fuzzcheck$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
fuzzcheck-asan$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
$(LTLINK) -o $@ -fsanitize=address $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)
fuzzcheck-ubsan$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
$(LTLINK) -o $@ -fsanitize=undefined $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)
# Usage: FUZZDB=filename make run-fuzzcheck
#
# Where filename is a fuzzcheck database, this target builds and runs
# fuzzcheck, fuzzcheck-asan, and fuzzcheck-ubsan on that database.
#
# FUZZDB can be a glob pattern of two or more databases. Example:
#
# FUZZDB=test/fuzzdata*.db make run-fuzzcheck
#
run-fuzzcheck: fuzzcheck$(TEXE) fuzzcheck-asan$(TEXE) fuzzcheck-ubsan$(TEXE)
@if test "$(FUZZDB)" = ""; then echo 'ERROR: No FUZZDB specified. Rerun with FUZZDB=filename'; exit 1; fi
./fuzzcheck$(TEXE) --spinner $(FUZZDB)
./fuzzcheck-asan$(TEXE) --spinner $(FUZZDB)
./fuzzcheck-ubsan$(TEXE) --spinner $(FUZZDB)
ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \
$(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS)
@@ -784,22 +765,13 @@ mptest: mptester$(TEXE)
$(MPTEST2) --journalmode DELETE
has_tclsh84:
sh $(TOP)/tool/cktclsh.sh 8.4 $(TCLSH_CMD)
touch has_tclsh84
has_tclsh85:
sh $(TOP)/tool/cktclsh.sh 8.5 $(TCLSH_CMD)
touch has_tclsh85
# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system. Some of the C source code and header
# files are automatically generated. This target takes care of
# all that automatic generation.
#
.target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl has_tclsh84 fts5.c
.target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl fts5.c
rm -rf tsrc
mkdir tsrc
cp -f $(SRC) tsrc
@@ -809,15 +781,15 @@ has_tclsh85:
cp fts5.c fts5.h tsrc
touch .target_source
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl src-verify has_tclsh84
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl src-verify
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS)
cp tsrc/sqlite3ext.h .
cp $(TOP)/ext/session/sqlite3session.h .
sqlite3r.h: sqlite3.h has_tclsh84
sqlite3r.h: sqlite3.h
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) --enable-recover >sqlite3r.h
sqlite3r.c: sqlite3.c sqlite3r.h has_tclsh84
sqlite3r.c: sqlite3.c sqlite3r.h
cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
cp $(TOP)/ext/recover/sqlite3recover.h tsrc/
cp $(TOP)/ext/recover/dbdata.c tsrc/
@@ -832,7 +804,7 @@ tclsqlite3.c: sqlite3.c
echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c
cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c
sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl has_tclsh84
sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl
$(TCLSH_CMD) $(TOP)/tool/split-sqlite3c.tcl
# Rule to build the amalgamation
@@ -1120,10 +1092,10 @@ tclsqlite3$(TEXE): tclsqlite-shell.lo libsqlite3.la
# Rules to build opcodes.c and opcodes.h
#
opcodes.c: opcodes.h $(TOP)/tool/mkopcodec.tcl has_tclsh84
opcodes.c: opcodes.h $(TOP)/tool/mkopcodec.tcl
$(TCLSH_CMD) $(TOP)/tool/mkopcodec.tcl opcodes.h >opcodes.c
opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl has_tclsh84
opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl
cat parse.h $(TOP)/src/vdbe.c | $(TCLSH_CMD) $(TOP)/tool/mkopcodeh.tcl >opcodes.h
# Rules to build parse.c and parse.h - the outputs of lemon.
@@ -1134,10 +1106,10 @@ parse.c: $(TOP)/src/parse.y lemon$(BEXE)
cp $(TOP)/src/parse.y .
./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) -S parse.y
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION has_tclsh84
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION has_tclsh84
sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION
echo '#ifndef SQLITE_RESOURCE_VERSION' >$@
echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@
cat $(TOP)/VERSION | $(TCLSH_CMD) $(TOP)/tool/replace.tcl exact . , >>$@
@@ -1150,21 +1122,19 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
# Source files that go into making shell.c
SHELL_SRC = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/consio/console_io.c \
$(TOP)/ext/consio/console_io.h \
$(TOP)/ext/misc/appendvfs.c \
$(TOP)/ext/misc/appendvfs.c \
$(TOP)/ext/misc/completion.c \
$(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/basexx.c \
$(TOP)/ext/misc/base64.c \
$(TOP)/ext/misc/base85.c \
$(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/basexx.c \
$(TOP)/ext/misc/base64.c \
$(TOP)/ext/misc/base85.c \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/regexp.c \
$(TOP)/ext/misc/series.c \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/regexp.c \
$(TOP)/ext/misc/series.c \
$(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/expert/sqlite3expert.c \
$(TOP)/ext/expert/sqlite3expert.h \
$(TOP)/ext/misc/zipfile.c \
@@ -1173,9 +1143,9 @@ SHELL_SRC = \
$(TOP)/ext/recover/dbdata.c \
$(TOP)/ext/recover/sqlite3recover.c \
$(TOP)/ext/recover/sqlite3recover.h \
$(TOP)/src/test_windirent.c
$(TOP)/src/test_windirent.c
shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl has_tclsh84
shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
$(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c
@@ -1263,7 +1233,7 @@ fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon$(BEXE)
fts5parse.h: fts5parse.c
fts5.c: $(FTS5_SRC) has_tclsh84
fts5.c: $(FTS5_SRC)
$(TCLSH_CMD) $(TOP)/ext/fts5/tool/mkfts5c.tcl
cp $(TOP)/ext/fts5/fts5.h .
@@ -1297,7 +1267,7 @@ TESTFIXTURE_SRC1 = sqlite3.c
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c
TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
testfixture$(TEXE): has_tclsh85 $(TESTFIXTURE_SRC)
testfixture$(TEXE): $(TESTFIXTURE_SRC)
$(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
-o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
@@ -1321,17 +1291,11 @@ fulltestonly: $(TESTPROGS) fuzztest
./testfixture$(TEXE) $(TOP)/test/full.test
# Fuzz testing
#
# WARNING: When the "fuzztest" target is run by the testrunner.tcl script,
# it does not actually run this code. Instead, it schedules equivalent
# commands. Therefore, if this target is updated, then code in
# testrunner_data.tcl (search for "trd_fuzztest_data") must also be updated.
#
fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE)
fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db
./fuzzcheck$(TEXE) $(FUZZDATA)
./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) sessionfuzz$(TEXE)
valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db
valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M $(FUZZDATA)
valgrind ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
@@ -1350,10 +1314,10 @@ testrunner: testfixture$(TEXE)
#
devtest: srctree-check testfixture$(TEXE) fuzztest testrunner
mdevtest: srctree-check has_tclsh85
mdevtest: srctree-check
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl mdevtest
sdevtest: has_tclsh85
sdevtest:
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl sdevtest
# Validate that various generated files in the source tree
@@ -1393,13 +1357,13 @@ smoketest: $(TESTPROGS) fuzzcheck$(TEXE)
shelltest: $(TESTPROGS)
./testfixture$(TEXT) $(TOP)/test/permutations.test shell
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in has_tclsh85
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in has_tclsh85
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
sqltclsh$(TEXE): sqltclsh.c
@@ -1418,7 +1382,7 @@ CHECKER_DEPS =\
$(TOP)/ext/misc/btreeinfo.c \
$(TOP)/ext/repair/sqlite3_checker.c.in
sqlite3_checker.c: $(CHECKER_DEPS) has_tclsh85
sqlite3_checker.c: $(CHECKER_DEPS)
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/ext/repair/sqlite3_checker.c.in >$@
sqlite3_checker$(TEXE): sqlite3_checker.c
@@ -1504,11 +1468,6 @@ amalgamation-tarball: sqlite3.c sqlite3rc.h
snapshot-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
# Build a ZIP archive containing various command-line tools.
#
tool-zip: testfixture sqlite3 sqldiff sqlite3_analyzer $(TOP)/tool/mktoolzip.tcl
./testfixture $(TOP)/tool/mktoolzip.tcl
# The next two rules are used to support the "threadtest" target. Building
# threadtest runs a few thread-safety tests that are implemented in C. This
# target is invoked by the releasetest.tcl script.
@@ -1584,7 +1543,6 @@ clean:
rm -f threadtest5
rm -f src-verify
rm -f custom.rws
rm -f has_tclsh84 has_tclsh85
distclean: clean
rm -f sqlite_cfg.h config.log config.status libtool Makefile sqlite3.pc \
@@ -1629,7 +1587,7 @@ fiddle: sqlite3.c shell.c
@echo 'Updating custom dictionary from tool/custom.txt'
aspell --lang=en create master ./custom.rws < $<
misspell: ./custom.rws has_tclsh84
misspell: ./custom.rws
$(TCLSH_CMD) ./tool/spellsift.tcl ./src/*.c ./src/*.h ./src/*.in
#
+10 -19
View File
@@ -52,8 +52,8 @@ MINIMAL_AMALGAMATION = 0
USE_STDCALL = 0
!ENDIF
# Use the USE_SEH=0 option on the nmake command line to omit structured
# exception handling (SEH) support. SEH is on by default.
# Set this non-0 to use structured exception handling (SEH) for WAL mode
# in the core library.
#
!IFNDEF USE_SEH
USE_SEH = 1
@@ -374,7 +374,6 @@ SQLITE_TCL_DEP =
!IFNDEF OPT_FEATURE_FLAGS
!IF $(MINIMAL_AMALGAMATION)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_GEOPOLY=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
@@ -404,11 +403,10 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
!ENDIF
# Should structured exception handling (SEH) be enabled for WAL mode in
# the core library? It is on by default. Only omit it if the
# USE_SEH=0 option is provided on the nmake command-line.
# the core library?
#
!IF $(USE_SEH)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_OMIT_SEH=1
!IF $(USE_SEH)!=0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_USE_SEH=1
!ENDIF
# These are the "extended" SQLite compilation options used when compiling for
@@ -1594,7 +1592,8 @@ TESTEXT = \
$(TOP)\ext\rtree\test_rtreedoc.c \
$(TOP)\ext\recover\sqlite3recover.c \
$(TOP)\ext\recover\test_recover.c \
$(TOP)\ext\recover\dbdata.c
$(TOP)\ext\recover\dbdata.c \
fts5.c
# If use of zlib is enabled, add the "zipfile.c" source file.
#
@@ -1610,8 +1609,7 @@ TESTSRC2 = \
$(SRC01) \
$(SRC07) \
$(SRC10) \
$(TOP)\ext\async\sqlite3async.c \
fts5.c
$(TOP)\ext\async\sqlite3async.c
# Header files used by all library source files.
#
@@ -1690,8 +1688,6 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
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
!ENDIF
# <<mark>>
@@ -1823,8 +1819,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 $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -2261,8 +2257,6 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
# Source files that go into making shell.c
SHELL_SRC = \
$(TOP)\src\shell.c.in \
$(TOP)\ext\consio\console_io.c \
$(TOP)\ext\consio\console_io.h \
$(TOP)\ext\misc\appendvfs.c \
$(TOP)\ext\misc\completion.c \
$(TOP)\ext\misc\base64.c \
@@ -2472,9 +2466,6 @@ extensiontest: testfixture.exe testloadext.dll
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
tool-zip: testfixture.exe sqlite3.exe sqldiff.exe sqlite3_analyzer.exe $(TOP)\tool\mktoolzip.tcl
.\testfixture.exe $(TOP)\tool\mktoolzip.tcl
coretestprogs: $(TESTPROGS)
testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe
+1 -1
View File
@@ -1 +1 @@
3.45.0
3.43.2
+5 -9
View File
@@ -52,8 +52,8 @@ MINIMAL_AMALGAMATION = 0
USE_STDCALL = 0
!ENDIF
# Use the USE_SEH=0 option on the nmake command line to omit structured
# exception handling (SEH) support. SEH is on by default.
# Set this non-0 to use structured exception handling (SEH) for WAL mode
# in the core library.
#
!IFNDEF USE_SEH
USE_SEH = 1
@@ -296,7 +296,6 @@ SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
!IFNDEF OPT_FEATURE_FLAGS
!IF $(MINIMAL_AMALGAMATION)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_GEOPOLY=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
@@ -326,11 +325,10 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
!ENDIF
# Should structured exception handling (SEH) be enabled for WAL mode in
# the core library? It is on by default. Only omit it if the
# USE_SEH=0 option is provided on the nmake command-line.
# the core library?
#
!IF $(USE_SEH)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_OMIT_SEH=1
!IF $(USE_SEH)!=0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_USE_SEH=1
!ENDIF
# These are the "extended" SQLite compilation options used when compiling for
@@ -988,8 +986,6 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
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
!ENDIF
+1 -1
View File
@@ -19,7 +19,7 @@ dnl to configure the system for the local environment.
# so that we create the export library with the dll.
#-----------------------------------------------------------------------
AC_INIT([sqlite],[3.45.0])
AC_INIT([sqlite],[3.43.2])
#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
Vendored
+24 -48
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.45.0.
# Generated by GNU Autoconf 2.69 for sqlite 3.43.2.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -726,8 +726,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.45.0'
PACKAGE_STRING='sqlite 3.45.0'
PACKAGE_VERSION='3.43.2'
PACKAGE_STRING='sqlite 3.43.2'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -776,7 +776,6 @@ OPT_FEATURE_FLAGS
HAVE_ZLIB
USE_AMALGAMATION
TARGET_DEBUG
TARGET_HAVE_LINENOISE
TARGET_HAVE_EDITLINE
TARGET_HAVE_READLINE
TARGET_READLINE_INC
@@ -904,7 +903,6 @@ enable_editline
enable_readline
with_readline_lib
with_readline_inc
with_linenoise
enable_debug
enable_amalgamation
enable_load_extension
@@ -1472,7 +1470,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.45.0 to adapt to many kinds of systems.
\`configure' configures sqlite 3.43.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1537,7 +1535,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.45.0:";;
short | recursive ) echo "Configuration of sqlite 3.43.2:";;
esac
cat <<\_ACEOF
@@ -1589,7 +1587,6 @@ Optional Packages:
(tclConfig.sh)
--with-readline-lib specify readline library
--with-readline-inc specify readline include paths
--with-linenoise=DIR source directory for linenoise library
Some influential environment variables:
CC C compiler command
@@ -1668,7 +1665,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.45.0
sqlite configure 3.43.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2087,7 +2084,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.45.0, which was
It was created by sqlite $as_me 3.43.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3945,13 +3942,13 @@ if ${lt_cv_nm_interface+:} false; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:3948: $ac_compile\"" >&5)
(eval echo "\"\$as_me:3945: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:3951: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:3948: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:3954: output\"" >&5)
(eval echo "\"\$as_me:3951: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5157,7 +5154,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 5160 "configure"' > conftest.$ac_ext
echo '#line 5157 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6682,11 +6679,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6685: $lt_compile\"" >&5)
(eval echo "\"\$as_me:6682: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6689: \$? = $ac_status" >&5
echo "$as_me:6686: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7021,11 +7018,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7024: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7021: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:7028: \$? = $ac_status" >&5
echo "$as_me:7025: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7126,11 +7123,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7129: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7126: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7133: \$? = $ac_status" >&5
echo "$as_me:7130: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -7181,11 +7178,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7184: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7181: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7188: \$? = $ac_status" >&5
echo "$as_me:7185: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9561,7 +9558,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9564 "configure"
#line 9561 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9657,7 +9654,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9660 "configure"
#line 9657 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11248,27 +11245,6 @@ fi
fi
fi
# Check whether --with-linenoise was given.
if test "${with_linenoise+set}" = set; then :
withval=$with_linenoise; with_linenoise=$withval
else
with_linenoise="no"
fi
if test "x$with_linenoise" != "xno"; then
TARGET_HAVE_READLINE=0
TARGET_HAVE_EDITLINE=0
TARGET_HAVE_LINENOISE=1
TARGET_READLINE_INC="-I${with_linenoise}"
TARGET_READLINE_LIBS="${with_linenoise}/linenoise.c"
echo "using linenoise source code at ${with_linenoise}"
else
TARGET_HAVE_LINENOISE=0
echo "not using linenoise"
fi
@@ -11345,7 +11321,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build type" >&5
$as_echo_n "checking build type... " >&6; }
if test "${enable_debug}" = "yes" ; then
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall"
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: debug" >&5
$as_echo "debug" >&6; }
else
@@ -12481,7 +12457,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.45.0, which was
This file was extended by sqlite $as_me 3.43.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12547,7 +12523,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
sqlite config.status 3.45.0
sqlite config.status 3.43.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
+2 -19
View File
@@ -74,7 +74,7 @@
# you don't need (for example BLT) by erasing or commenting out
# the corresponding code.
#
AC_INIT([sqlite],m4_esyscmd(cat VERSION | tr -d '\n'))
AC_INIT([sqlite],[m4_esyscmd(cat VERSION | tr -d '\n')])
dnl Make sure the local VERSION file matches this configure script
sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'`
@@ -598,28 +598,11 @@ if test x"$with_readline" != xno; then
TARGET_HAVE_READLINE=1
fi
fi
AC_ARG_WITH([linenoise],
[AS_HELP_STRING([--with-linenoise=DIR],[source directory for linenoise library])],
[with_linenoise=$withval],
[with_linenoise="no"])
if test "x$with_linenoise" != "xno"; then
TARGET_HAVE_READLINE=0
TARGET_HAVE_EDITLINE=0
TARGET_HAVE_LINENOISE=1
TARGET_READLINE_INC="-I${with_linenoise}"
TARGET_READLINE_LIBS="${with_linenoise}/linenoise.c"
echo "using linenoise source code at ${with_linenoise}"
else
TARGET_HAVE_LINENOISE=0
echo "not using linenoise"
fi
AC_SUBST(TARGET_READLINE_LIBS)
AC_SUBST(TARGET_READLINE_INC)
AC_SUBST(TARGET_HAVE_READLINE)
AC_SUBST(TARGET_HAVE_EDITLINE)
AC_SUBST(TARGET_HAVE_LINENOISE)
##########
# Figure out what C libraries are required to compile programs
@@ -632,7 +615,7 @@ AC_SEARCH_LIBS(fdatasync, [rt])
AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],[enable debugging & verbose explain]))
AC_MSG_CHECKING([build type])
if test "${enable_debug}" = "yes" ; then
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall"
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0"
AC_MSG_RESULT([debug])
else
TARGET_DEBUG="-DNDEBUG"
+2 -65
View File
@@ -1,7 +1,7 @@
# Notes On Compiling SQLite On Windows 11
Here are step-by-step instructions on how to build SQLite from
canonical source on a new Windows 11 PC, as of 2023-11-01:
canonical source on a new Windows 11 PC, as of 2023-08-16:
1. Install Microsoft Visual Studio. The free "community edition"
will work fine. Do a standard install for C++ development.
@@ -16,7 +16,7 @@ canonical source on a new Windows 11 PC, as of 2023-11-01:
a 32-bit build.) The subsequent steps will not work in a vanilla
DOS prompt. Nor will they work in PowerShell.
3. Install TCL development libraries. This note assumes that you will
3. Install TCL development libraries. This note assumes that you wil
install the TCL development libraries in the "`c:\Tcl`" directory.
Make adjustments
if you want TCL installed somewhere else. SQLite needs both the
@@ -83,66 +83,3 @@ following minor changes:
<ul>
<li> `set PATH=c:\tcl32\bin;%PATH%`
</ul>
## Building a DLL
The command the developers use for building the deliverable DLL on the
[download page](https://sqlite.org/download.html) is as follows:
> ~~~~
nmake /f Makefile.msc sqlite3.dll USE_NATIVE_LIBPATHS=1 "OPTS=-DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 -DSQLITE_ENABLE_SERIALIZE=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
~~~~
That command generates both the sqlite3.dll and sqlite3.def files. The same
command works for both 32-bit and 64-bit builds.
## Statically Linking The TCL Library
Some utility programs associated with SQLite need to be linked
with TCL in order to function. The [sqlite3_analyzer.exe program](https://sqlite.org/sqlanalyze.html)
is an example. You can build as described above, and then
enter:
> ~~~~
nmake /f Makefile.msc sqlite3_analyzer.exe
~~~~
And you will end up with a working executable. However, that executable
will depend on having the "tcl86.dll" library somewhere on your %PATH%.
Use the following steps to build an executable that has the TCL library
statically linked so that it does not depend on separate DLL:
1. Use the appropriate "Command Prompt" window - either x86 or
x64, depending on whether you want a 32-bit or 64-bit executable.
2. Untar the TCL source tarball into a fresh directory. CD into
the "win/" subfolder.
3. Run: `nmake /f makefile.vc OPTS=nothreads,static shell`
4. CD into the "Release*" subfolder that is created (note the
wildcard - the full name of the directory might vary). There
you will find the "tcl86s.lib" file. Copy this file into the
same directory that you put the "tcl86.lib" on your initial
installation. (In this document, that directory is
"`C:\Tcl32\lib`" for 32-bit builds and
"`C:\Tcl\lib`" for 64-bit builds.)
5. CD into your SQLite source code directory and build the desired
utility program, but add the following extra arguments to the
nmake command line:
<blockquote><pre>
CCOPTS="-DSTATIC_BUILD" LIBTCL="tcl86s.lib netapi32.lib user32.lib"
</pre></blockquote>
<p>So, for example, to build a statically linked version of
sqlite3_analyzer.exe, you might type:
<blockquote><pre>
nmake /f Makefile.msc CCOPTS="-DSTATIC_BUILD" LIBTCL="tcl86s.lib netapi32.lib user32.lib" sqlite3_analyzer.exe
</pre></blockquote>
6. After your executable is built, you can verify that it does not
depend on the TCL DLL by running:
<blockquote><pre>
dumpbin /dependents sqlite3_analyzer.exe
</pre></blockquote>
-344
View File
@@ -1,344 +0,0 @@
# 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
multiple jobs. It supports the following types of tests:
* Tcl test scripts.
* Tests run with [make] commands. Specifically, at time of writing,
[make fuzztest], [make mptest], [make sourcetest] and [make threadtest].
testrunner.tcl pipes the output of all tests and builds run into log file
**testrunner.log**, created in the cwd directory. Searching this file for
"failed" is a good way to find the output of a failed test.
testrunner.tcl also populates SQLite database **testrunner.db**. This database
contains details of all tests run, running and to be run. A useful query
might be:
```
SELECT * FROM script WHERE state='failed'
```
Running the command:
```
./testfixture $(TESTDIR)/testrunner.tcl status
```
in the directory containing the testrunner.db database runs various queries
to produce a succinct report on the state of a running testrunner.tcl script.
Running:
```
watch ./testfixture $(TESTDIR)/testrunner.tcl status
```
in another terminal is a good way to keep an eye on a long running test.
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
test scripts using the [testfixture] binary used to run the testrunner.tcl
script (i.e. they do not invoke the compiler to build new binaries, or the
[make] command to run tests that are not Tcl scripts). The procedure to run
these tests is therefore:
1. Build the "testfixture" (or "testfixture.exe" for windows) binary using
whatever method seems convenient.
2. Test the binary built in step 1 by running testrunner.tcl with it,
perhaps with various options.
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
found in both the $TOP/test/ directory, and in the various sub-directories
of the $TOP/ext/ directory of the source tree. Not all *\*.test* files
contain Tcl tests - a handful are Tcl scripts designed to invoke other
*\*.test* files.
The **veryquick** set of tests is a subset of all Tcl test scripts in the
source tree. In includes most tests, but excludes some that are very slow.
Almost all fault-injection tests (those that test the response of the library
to OOM or IO errors) are excluded. It is defined in source file
*test/permutations.test*.
The **full** set of tests includes all Tcl test scripts in the source tree.
To run a "full" test is to run all Tcl test scripts that can be found in the
source tree.
File *permutations.test* defines various test "permutations". A permutation
consists of:
* A subset of Tcl test scripts, and
* Runtime configuration to apply before running each test script
(e.g. enabling auto-vacuum, or disable lookaside).
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:
```
./testfixture $TESTDIR/testrunner.tcl
./testfixture $TESTDIR/testrunner.tcl veryquick
```
To run the "full" test suite:
```
./testfixture $TESTDIR/testrunner.tcl full
```
To run the subset of the "full" test suite for which the test file name matches
a specified pattern (e.g. all tests that start with "fts5"), either of:
```
./testfixture $TESTDIR/testrunner.tcl fts5%
./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):
```
./testfixture $TESTDIR/testrunner.tcl all
```
<a name=binary_test_failures></a>
## 2.3. Investigating Binary Test Failures
If a test fails, testrunner.tcl reports name of the Tcl test script and, if
applicable, the name of the permutation, to stdout. This information can also
be retrieved from either *testrunner.log* or *testrunner.db*.
If there is no permutation, the individual test script may be run with:
```
./testfixture $PATH_TO_SCRIPT
```
Or, if the failure occured as part of a permutation:
```
./testfixture $TESTDIR/testrunner.tcl $PERMUTATION $PATH_TO_SCRIPT
```
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
binaries from the source tree, then use those binaries to run Tcl and
other tests. The advantages of this are that:
* it is possible to test multiple build configurations with a single
command, and
* it ensures that tests are always run using binaries created with the
same set of compiler options.
The testrunner.tcl commands described in this section may be run using
either a *testfixture* (or testfixture.exe) build, or with any other Tcl
shell that supports SQLite 3.31.1 or newer via "package require sqlite3".
TODO: ./configure + Makefile.msc build systems.
<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
with debugging enabled and one without:
```
tclsh $TESTDIR/testrunner.tcl mdevtest
```
In other words, it is equivalent to running:
```
$TOP/configure --enable-all --enable-debug
make fuzztest
make testfixture
./testfixture $TOP/test/testrunner.tcl veryquick
# Then, after removing files created by the tests above:
$TOP/configure --enable-all OPTS="-O0"
make fuzztest
make testfixture
./testfixture $TOP/test/testrunner.tcl veryquick
```
The **sdevtest** command is identical to the mdevtest command, except that the
second of the two builds is a sanitizer build. Specifically, this means that
OPTS="-fsanitize=address,undefined" is specified instead of OPTS="-O0":
```
tclsh $TESTDIR/testrunner.tcl sdevtest
```
The **release** command runs lots of tests under lots of builds. It runs
different combinations of builds and tests depending on whether it is run
on Linux, Windows or OSX. Refer to *testrunner\_data.tcl* for the details
of the specific tests run.
```
tclsh $TESTDIR/testrunner.tcl release
```
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:
```
tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS
```
This can be combined with any of "mdevtest", "sdevtest" or "release" to
test both SQLite and Zipvfs with a single command:
```
tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
```
<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:
1. Recreating the build configuration in which the test failed, and
2. Re-running the actual test.
To recreate a build configuration, use the testrunner.tcl **script** command
to create a build script. A build script is a bash script on Linux or OSX, or
a dos \*.bat file on windows. For example:
```
# Create a script that recreates build configuration "Device-One" on
# Linux or OSX:
tclsh $TESTDIR/testrunner.tcl script Device-One > make.sh
# Create a script that recreates build configuration "Have-Not" on Windows:
tclsh $TESTDIR/testrunner.tcl script Have-Not > make.bat
```
The generated bash or \*.bat file script accepts a single argument - a makefile
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.
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.
```
$ ./testfixture $TESTDIR/testrunner.tcl
splitting work across 16 jobs
... more output ...
```
By default, testfixture.tcl attempts to set the number of jobs to the number
of real cores on the machine. This can be overridden using the "--jobs" (or -j)
switch:
```
$ ./testfixture $TESTDIR/testrunner.tcl --jobs 8
splitting work across 8 jobs
... more output ...
```
The number of jobs may also be changed while an instance of testrunner.tcl is
running by exucuting the following command from the directory containing the
testrunner.log and testrunner.db files:
```
$ ./testfixture $TESTDIR/testrunner.tcl njob $NEW_NUMBER_OF_JOBS
```
-678
View File
@@ -1,678 +0,0 @@
/*
** 2023 November 4
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
********************************************************************************
** This file implements various interfaces used for console and stream I/O
** by the SQLite project command-line tools, as explained in console_io.h .
** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there.
*/
#ifndef SQLITE_CDECL
# define SQLITE_CDECL
#endif
#ifndef SHELL_NO_SYSINC
# include <stdarg.h>
# include <string.h>
# include <stdlib.h>
# include <limits.h>
# include <assert.h>
# include "console_io.h"
# include "sqlite3.h"
#endif
#ifndef SQLITE_CIO_NO_TRANSLATE
# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
# ifndef SHELL_NO_SYSINC
# include <io.h>
# include <fcntl.h>
# undef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# endif
# define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */
# else
# ifndef SHELL_NO_SYSINC
# include <unistd.h>
# endif
# define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
# endif
#else
# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
#endif
#if CIO_WIN_WC_XLATE
/* Character used to represent a known-incomplete UTF-8 char group () */
static WCHAR cBadGroup = 0xfffd;
#endif
#if CIO_WIN_WC_XLATE
static HANDLE handleOfFile(FILE *pf){
int fileDesc = _fileno(pf);
union { intptr_t osfh; HANDLE fh; } fid = {
(fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
};
return fid.fh;
}
#endif
#ifndef SQLITE_CIO_NO_TRANSLATE
typedef struct PerStreamTags {
# if CIO_WIN_WC_XLATE
HANDLE hx;
DWORD consMode;
char acIncomplete[4];
# else
short reachesConsole;
# endif
FILE *pf;
} PerStreamTags;
/* Define NULL-like value for things which can validly be 0. */
# define SHELL_INVALID_FILE_PTR ((FILE *)~0)
# if CIO_WIN_WC_XLATE
# define SHELL_INVALID_CONS_MODE 0xFFFF0000
# endif
# if CIO_WIN_WC_XLATE
# define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \
{0,0,0,0}, SHELL_INVALID_FILE_PTR }
# else
# define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
# endif
/* Quickly say whether a known output is going to the console. */
# if CIO_WIN_WC_XLATE
static short pstReachesConsole(PerStreamTags *ppst){
return (ppst->hx != INVALID_HANDLE_VALUE);
}
# else
# define pstReachesConsole(ppst) 0
# endif
# if CIO_WIN_WC_XLATE
static void restoreConsoleArb(PerStreamTags *ppst){
if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode);
}
# else
# define restoreConsoleArb(ppst)
# endif
/* Say whether FILE* appears to be a console, collect associated info. */
static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
# if CIO_WIN_WC_XLATE
short rv = 0;
DWORD dwCM = SHELL_INVALID_CONS_MODE;
HANDLE fh = handleOfFile(pf);
ppst->pf = pf;
if( INVALID_HANDLE_VALUE != fh ){
rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
}
ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
ppst->consMode = dwCM;
return rv;
# else
ppst->pf = pf;
ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
return ppst->reachesConsole;
# endif
}
# if CIO_WIN_WC_XLATE
/* Define console modes for use with the Windows Console API. */
# define SHELL_CONI_MODE \
(ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
| ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
# define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
| ENABLE_VIRTUAL_TERMINAL_PROCESSING)
# endif
typedef struct ConsoleInfo {
PerStreamTags pstSetup[3];
PerStreamTags pstDesignated[3];
StreamsAreConsole sacSetup;
} ConsoleInfo;
static short isValidStreamInfo(PerStreamTags *ppst){
return (ppst->pf != SHELL_INVALID_FILE_PTR);
}
static ConsoleInfo consoleInfo = {
{ /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
{ /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
SAC_NoConsole /* sacSetup */
};
SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
# if CIO_WIN_WC_XLATE
static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
if( pstReachesConsole(ppst) ){
DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
SetConsoleMode(ppst->hx, cm);
}
}
# else
# define maybeSetupAsConsole(ppst,odir)
# endif
SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
# if CIO_WIN_WC_XLATE
int ix = 0;
while( ix < 6 ){
PerStreamTags *ppst = (ix<3)?
&consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3];
maybeSetupAsConsole(ppst, (ix % 3)>0);
++ix;
}
# endif
}
SQLITE_INTERNAL_LINKAGE StreamsAreConsole
consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
StreamsAreConsole rv = SAC_NoConsole;
FILE* apf[3] = { pfIn, pfOut, pfErr };
int ix;
for( ix = 2; ix >= 0; --ix ){
PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
if( streamOfConsole(apf[ix], ppst) ){
rv |= (SAC_InConsole<<ix);
}
consoleInfo.pstDesignated[ix] = *ppst;
if( ix > 0 ) fflush(apf[ix]);
}
consoleInfo.sacSetup = rv;
consoleRenewSetup();
return rv;
}
SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
# if CIO_WIN_WC_XLATE
static ConsoleInfo *pci = &consoleInfo;
if( pci->sacSetup ){
int ix;
for( ix=0; ix<3; ++ix ){
if( pci->sacSetup & (SAC_InConsole<<ix) ){
PerStreamTags *ppst = &pci->pstSetup[ix];
SetConsoleMode(ppst->hx, ppst->consMode);
}
}
}
# endif
}
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
#ifdef SQLITE_CIO_INPUT_REDIR
/* Say whether given FILE* is among those known, via either
** consoleClassifySetup() or set{Output,Error}Stream, as
** readable, and return an associated PerStreamTags pointer
** if so. Otherwise, return 0.
*/
static PerStreamTags * isKnownReadable(FILE *pf){
static PerStreamTags *apst[] = {
&consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0
};
int ix = 0;
do {
if( apst[ix]->pf == pf ) break;
} while( apst[++ix] != 0 );
return apst[ix];
}
#endif
#ifndef SQLITE_CIO_NO_TRANSLATE
/* Say whether given FILE* is among those known, via either
** consoleClassifySetup() or set{Output,Error}Stream, as
** writable, and return an associated PerStreamTags pointer
** if so. Otherwise, return 0.
*/
static PerStreamTags * isKnownWritable(FILE *pf){
static PerStreamTags *apst[] = {
&consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2],
&consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0
};
int ix = 0;
do {
if( apst[ix]->pf == pf ) break;
} while( apst[++ix] != 0 );
return apst[ix];
}
static FILE *designateEmitStream(FILE *pf, unsigned chix){
FILE *rv = consoleInfo.pstDesignated[chix].pf;
if( pf == invalidFileStream ) return rv;
else{
/* Setting a possibly new output stream. */
PerStreamTags *ppst = isKnownWritable(pf);
if( ppst != 0 ){
PerStreamTags pst = *ppst;
consoleInfo.pstDesignated[chix] = pst;
}else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]);
}
return rv;
}
SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){
return designateEmitStream(pf, 1);
}
# ifdef CONSIO_SET_ERROR_STREAM
SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
return designateEmitStream(pf, 2);
}
# endif
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
#ifndef SQLITE_CIO_NO_SETMODE
# if CIO_WIN_WC_XLATE
static void setModeFlushQ(FILE *pf, short bFlush, int mode){
if( bFlush ) fflush(pf);
_setmode(_fileno(pf), mode);
}
# else
# define setModeFlushQ(f, b, m) if(b) fflush(f)
# endif
SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
setModeFlushQ(pf, bFlush, _O_BINARY);
}
SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){
setModeFlushQ(pf, bFlush, _O_TEXT);
}
# undef setModeFlushQ
#else /* defined(SQLITE_CIO_NO_SETMODE) */
# define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
# define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
#endif /* defined(SQLITE_CIO_NO_SETMODE) */
#ifndef SQLITE_CIO_NO_TRANSLATE
# if CIO_WIN_WC_XLATE
/* Write buffer cBuf as output to stream known to reach console,
** limited to ncTake char's. Return ncTake on success, else 0. */
static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){
int rv = 0;
if( z!=NULL ){
int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0);
if( nwc > 0 ){
WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
if( zw!=NULL ){
nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc);
if( nwc > 0 ){
/* Translation from UTF-8 to UTF-16, then WCHARs out. */
if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
rv = ncTake;
}
}
sqlite3_free(zw);
}
}
}
return rv;
}
/* For {f,o,e}PrintfUtf8() when stream is known to reach console. */
static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){
char *z = sqlite3_vmprintf(zFormat, ap);
if( z ){
int rv = conZstrEmit(ppst, z, (int)strlen(z));
sqlite3_free(z);
return rv;
}else return 0;
}
# endif /* CIO_WIN_WC_XLATE */
# ifdef CONSIO_GET_EMIT_STREAM
static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix,
PerStreamTags *ppst){
PerStreamTags *rv = isKnownWritable(pf);
short isValid = (rv!=0)? isValidStreamInfo(rv) : 0;
if( rv != 0 && isValid ) return rv;
streamOfConsole(pf, ppst);
return ppst;
}
# endif
/* Get stream info, either for designated output or error stream when
** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
** In either case, ppst references a caller-owned PerStreamTags
** struct which may be filled in if none of the known writable
** streams is being held by consoleInfo. The ppf parameter is a
** byref output when chix!=0 and a byref input when chix==0.
*/
static PerStreamTags *
getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
/* in/out */ FILE **ppf){
PerStreamTags *ppstTry;
FILE *pfEmit;
if( chix > 0 ){
ppstTry = &consoleInfo.pstDesignated[chix];
if( !isValidStreamInfo(ppstTry) ){
ppstTry = &consoleInfo.pstSetup[chix];
pfEmit = ppst->pf;
}else pfEmit = ppstTry->pf;
if( !isValidStreamInfo(ppstTry) ){
pfEmit = (chix > 1)? stderr : stdout;
ppstTry = ppst;
streamOfConsole(pfEmit, ppstTry);
}
*ppf = pfEmit;
}else{
ppstTry = isKnownWritable(*ppf);
if( ppstTry != 0 ) return ppstTry;
streamOfConsole(*ppf, ppst);
return ppst;
}
return ppstTry;
}
SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){
va_list ap;
int rv;
FILE *pfOut;
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
# if CIO_WIN_WC_XLATE
PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
# else
getEmitStreamInfo(1, &pst, &pfOut);
# endif
assert(zFormat!=0);
va_start(ap, zFormat);
# if CIO_WIN_WC_XLATE
if( pstReachesConsole(ppst) ){
rv = conioVmPrintf(ppst, zFormat, ap);
}else{
# endif
rv = vfprintf(pfOut, zFormat, ap);
# if CIO_WIN_WC_XLATE
}
# endif
va_end(ap);
return rv;
}
SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
va_list ap;
int rv;
FILE *pfErr;
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
# if CIO_WIN_WC_XLATE
PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
# else
getEmitStreamInfo(2, &pst, &pfErr);
# endif
assert(zFormat!=0);
va_start(ap, zFormat);
# if CIO_WIN_WC_XLATE
if( pstReachesConsole(ppst) ){
rv = conioVmPrintf(ppst, zFormat, ap);
}else{
# endif
rv = vfprintf(pfErr, zFormat, ap);
# if CIO_WIN_WC_XLATE
}
# endif
va_end(ap);
return rv;
}
SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
va_list ap;
int rv;
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
# if CIO_WIN_WC_XLATE
PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
# else
getEmitStreamInfo(0, &pst, &pfO);
# endif
assert(zFormat!=0);
va_start(ap, zFormat);
# if CIO_WIN_WC_XLATE
if( pstReachesConsole(ppst) ){
maybeSetupAsConsole(ppst, 1);
rv = conioVmPrintf(ppst, zFormat, ap);
if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
}else{
# endif
rv = vfprintf(pfO, zFormat, ap);
# if CIO_WIN_WC_XLATE
}
# endif
va_end(ap);
return rv;
}
SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
# if CIO_WIN_WC_XLATE
PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
# else
getEmitStreamInfo(0, &pst, &pfO);
# endif
assert(z!=0);
# if CIO_WIN_WC_XLATE
if( pstReachesConsole(ppst) ){
int rv;
maybeSetupAsConsole(ppst, 1);
rv = conZstrEmit(ppst, z, (int)strlen(z));
if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
return rv;
}else {
# endif
return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
# if CIO_WIN_WC_XLATE
}
# endif
}
SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
FILE *pfErr;
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
# if CIO_WIN_WC_XLATE
PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
# else
getEmitStreamInfo(2, &pst, &pfErr);
# endif
assert(z!=0);
# if CIO_WIN_WC_XLATE
if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
else {
# endif
return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
# if CIO_WIN_WC_XLATE
}
# endif
}
SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
FILE *pfOut;
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
# if CIO_WIN_WC_XLATE
PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
# else
getEmitStreamInfo(1, &pst, &pfOut);
# endif
assert(z!=0);
# if CIO_WIN_WC_XLATE
if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
else {
# endif
return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
# if CIO_WIN_WC_XLATE
}
# endif
}
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
#if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE))
/* Skip over as much z[] input char sequence as is valid UTF-8,
** limited per nAccept char's or whole characters and containing
** no char cn such that ((1<<cn) & ccm)!=0. On return, the
** sequence z:return (inclusive:exclusive) is validated UTF-8.
** Limit: nAccept>=0 => char count, nAccept<0 => character
*/
SQLITE_INTERNAL_LINKAGE const char*
zSkipValidUtf8(const char *z, int nAccept, long ccm){
int ng = (nAccept<0)? -nAccept : 0;
const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
assert(z!=0);
while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
char c = *z;
if( (c & 0x80) == 0 ){
if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
++z; /* ASCII */
}else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
else{
const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
do{
if( pcLimit && zt >= pcLimit ) return z;
else{
char ct = *zt++;
if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
/* Trailing bytes are too few, too many, or invalid. */
return z;
}
}
} while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
z = zt;
}
}
return z;
}
#endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
#ifndef SQLITE_CIO_NO_TRANSLATE
# ifdef CONSIO_SPUTB
SQLITE_INTERNAL_LINKAGE int
fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
assert(pfO!=0);
# if CIO_WIN_WC_XLATE
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
if( pstReachesConsole(ppst) ){
int rv;
maybeSetupAsConsole(ppst, 1);
rv = conZstrEmit(ppst, cBuf, nAccept);
if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
return rv;
}else {
# endif
return (int)fwrite(cBuf, 1, nAccept, pfO);
# if CIO_WIN_WC_XLATE
}
# endif
}
# endif
SQLITE_INTERNAL_LINKAGE int
oPutbUtf8(const char *cBuf, int nAccept){
FILE *pfOut;
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
# if CIO_WIN_WC_XLATE
PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
# else
getEmitStreamInfo(1, &pst, &pfOut);
# endif
# if CIO_WIN_WC_XLATE
if( pstReachesConsole(ppst) ){
return conZstrEmit(ppst, cBuf, nAccept);
}else {
# endif
return (int)fwrite(cBuf, 1, nAccept, pfOut);
# if CIO_WIN_WC_XLATE
}
# endif
}
# ifdef CONSIO_EPUTB
SQLITE_INTERNAL_LINKAGE int
ePutbUtf8(const char *cBuf, int nAccept){
FILE *pfErr;
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
# if CIO_WIN_WC_XLATE
if( pstReachesConsole(ppst) ){
return conZstrEmit(ppst, cBuf, nAccept);
}else {
# endif
return (int)fwrite(cBuf, 1, nAccept, pfErr);
# if CIO_WIN_WC_XLATE
}
# endif
}
# endif /* defined(CONSIO_EPUTB) */
SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
if( pfIn==0 ) pfIn = stdin;
# if CIO_WIN_WC_XLATE
if( pfIn == consoleInfo.pstSetup[0].pf
&& (consoleInfo.sacSetup & SAC_InConsole)!=0 ){
# if CIO_WIN_WC_XLATE==1
# define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
WCHAR wcBuf[SHELL_GULP+1];
int lend = 0, noc = 0;
if( ncMax > 0 ) cBuf[0] = 0;
while( noc < ncMax-8-1 && !lend ){
/* There is room for at least 2 more characters and a 0-terminator. */
int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4;
# undef SHELL_GULP
DWORD nbr = 0;
BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0);
if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){
/* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */
DWORD nbrx;
bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0);
if( bRC ) nbr += nbrx;
}
if( !bRC || (noc==0 && nbr==0) ) return 0;
if( nbr > 0 ){
int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0);
if( nmb != 0 && noc+nmb <= ncMax ){
int iseg = noc;
nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0);
noc += nmb;
/* Fixup line-ends as coded by Windows for CR (or "Enter".)
** This is done without regard for any setMode{Text,Binary}()
** call that might have been done on the interactive input.
*/
if( noc > 0 ){
if( cBuf[noc-1]=='\n' ){
lend = 1;
if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n';
}
}
/* Check for ^Z (anywhere in line) too, to act as EOF. */
while( iseg < noc ){
if( cBuf[iseg]=='\x1a' ){
noc = iseg; /* Chop ^Z and anything following. */
lend = 1; /* Counts as end of line too. */
break;
}
++iseg;
}
}else break; /* Drop apparent garbage in. (Could assert.) */
}else break;
}
/* If got nothing, (after ^Z chop), must be at end-of-file. */
if( noc > 0 ){
cBuf[noc] = 0;
return cBuf;
}else return 0;
# endif
}else{
# endif
return fgets(cBuf, ncMax, pfIn);
# if CIO_WIN_WC_XLATE
}
# endif
}
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
#undef SHELL_INVALID_FILE_PTR
-280
View File
@@ -1,280 +0,0 @@
/*
** 2023 November 1
**
** 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 exposes various interfaces used for console and other I/O
** by the SQLite project command-line tools. These interfaces are used
** at either source conglomeration time, compilation time, or run time.
** This source provides for either inclusion into conglomerated,
** "single-source" forms or separate compilation then linking.
**
** Platform dependencies are "hidden" here by various stratagems so
** that, provided certain conditions are met, the programs using this
** source or object code compiled from it need no explicit conditional
** compilation in their source for their console and stream I/O.
**
** The symbols and functionality exposed here are not a public API.
** This code may change in tandem with other project code as needed.
**
** When this .h file and its companion .c are directly incorporated into
** a source conglomeration (such as shell.c), the preprocessor symbol
** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
** translation for Windows is effected for the build.
*/
#ifndef SQLITE_INTERNAL_LINKAGE
# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
# include <stdio.h>
#else
# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */
#endif
#ifndef SQLITE3_H
# include "sqlite3.h"
#endif
#ifndef SQLITE_CIO_NO_CLASSIFY
/* Define enum for use with following function. */
typedef enum StreamsAreConsole {
SAC_NoConsole = 0,
SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4,
SAC_AnyConsole = 0x7
} StreamsAreConsole;
/*
** Classify the three standard I/O streams according to whether
** they are connected to a console attached to the process.
**
** Returns the bit-wise OR of SAC_{In,Out,Err}Console values,
** or SAC_NoConsole if none of the streams reaches a console.
**
** This function should be called before any I/O is done with
** the given streams. As a side-effect, the given inputs are
** recorded so that later I/O operations on them may be done
** differently than the C library FILE* I/O would be done,
** iff the stream is used for the I/O functions that follow,
** and to support the ones that use an implicit stream.
**
** On some platforms, stream or console mode alteration (aka
** "Setup") may be made which is undone by consoleRestore().
*/
SQLITE_INTERNAL_LINKAGE StreamsAreConsole
consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
/* A usual call for convenience: */
#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr)
/*
** After an initial call to consoleClassifySetup(...), renew
** the same setup it effected. (A call not after is an error.)
** This will restore state altered by consoleRestore();
**
** Applications which run an inferior (child) process which
** inherits the same I/O streams may call this function after
** such a process exits to guard against console mode changes.
*/
SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void);
/*
** Undo any side-effects left by consoleClassifySetup(...).
**
** This should be called after consoleClassifySetup() and
** before the process terminates normally. It is suitable
** for use with the atexit() C library procedure. After
** this call, no console I/O should be done until one of
** console{Classify or Renew}Setup(...) is called again.
**
** Applications which run an inferior (child) process that
** inherits the same I/O streams might call this procedure
** before so that said process will have a console setup
** however users have configured it or come to expect.
*/
SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void );
#else /* defined(SQLITE_CIO_NO_CLASSIFY) */
# define consoleClassifySetup(i,o,e)
# define consoleRenewSetup()
# define consoleRestore()
#endif /* defined(SQLITE_CIO_NO_CLASSIFY) */
#ifndef SQLITE_CIO_NO_REDIRECT
/*
** Set stream to be used for the functions below which write
** to "the designated X stream", where X is Output or Error.
** Returns the previous value.
**
** Alternatively, pass the special value, invalidFileStream,
** to get the designated stream value without setting it.
**
** Before the designated streams are set, they default to
** those passed to consoleClassifySetup(...), and before
** that is called they default to stdout and stderr.
**
** It is error to close a stream so designated, then, without
** designating another, use the corresponding {o,e}Emit(...).
*/
SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream;
SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf);
# ifdef CONSIO_SET_ERROR_STREAM
SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf);
# endif
#else
# define setOutputStream(pf)
# define setErrorStream(pf)
#endif /* !defined(SQLITE_CIO_NO_REDIRECT) */
#ifndef SQLITE_CIO_NO_TRANSLATE
/*
** Emit output like fprintf(). If the output is going to the
** console and translation from UTF-8 is necessary, perform
** the needed translation. Otherwise, write formatted output
** to the provided stream almost as-is, possibly with newline
** translation as specified by set{Binary,Text}Mode().
*/
SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...);
/* Like fPrintfUtf8 except stream is always the designated output. */
SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...);
/* Like fPrintfUtf8 except stream is always the designated error. */
SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...);
/*
** Emit output like fputs(). If the output is going to the
** console and translation from UTF-8 is necessary, perform
** the needed translation. Otherwise, write given text to the
** provided stream almost as-is, possibly with newline
** translation as specified by set{Binary,Text}Mode().
*/
SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO);
/* Like fPutsUtf8 except stream is always the designated output. */
SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z);
/* Like fPutsUtf8 except stream is always the designated error. */
SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z);
/*
** Emit output like fPutsUtf8(), except that the length of the
** accepted char or character sequence is limited by nAccept.
**
** Returns the number of accepted char values.
*/
#ifdef CONSIO_SPUTB
SQLITE_INTERNAL_LINKAGE int
fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
/* Like fPutbUtf8 except stream is always the designated output. */
#endif
SQLITE_INTERNAL_LINKAGE int
oPutbUtf8(const char *cBuf, int nAccept);
/* Like fPutbUtf8 except stream is always the designated error. */
#ifdef CONSIO_EPUTB
SQLITE_INTERNAL_LINKAGE int
ePutbUtf8(const char *cBuf, int nAccept);
#endif
/*
** Collect input like fgets(...) with special provisions for input
** from the console on platforms that require same. Defers to the
** C library fgets() when input is not from the console. Newline
** translation may be done as set by set{Binary,Text}Mode(). As a
** convenience, pfIn==NULL is treated as stdin.
*/
SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
/* Like fGetsUtf8 except stream is always the designated input. */
/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
#ifndef SQLITE_CIO_NO_SETMODE
/*
** Set given stream for binary mode, where newline translation is
** not done, or for text mode where, for some platforms, newlines
** are translated to the platform's conventional char sequence.
** If bFlush true, flush the stream.
**
** An additional side-effect is that if the stream is one passed
** to consoleClassifySetup() as an output, it is flushed first.
**
** Note that binary/text mode has no effect on console I/O
** translation. On all platforms, newline to the console starts
** a new line and CR,LF chars from the console become a newline.
*/
SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush);
SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush);
#endif
#ifdef SQLITE_CIO_PROMPTED_IN
typedef struct Prompts {
int numPrompts;
const char **azPrompts;
} Prompts;
/*
** Macros for use of a line editor.
**
** The following macros define operations involving use of a
** line-editing library or simple console interaction.
** A "T" argument is a text (char *) buffer or filename.
** A "N" argument is an integer.
**
** SHELL_ADD_HISTORY(T) // Record text as line(s) of history.
** SHELL_READ_HISTORY(T) // Read history from file named by T.
** SHELL_WRITE_HISTORY(T) // Write history to file named by T.
** SHELL_STIFLE_HISTORY(N) // Limit history to N entries.
**
** A console program which does interactive console input is
** expected to call:
** SHELL_READ_HISTORY(T) before collecting such input;
** SHELL_ADD_HISTORY(T) as record-worthy input is taken;
** SHELL_STIFLE_HISTORY(N) after console input ceases; then
** SHELL_WRITE_HISTORY(T) before the program exits.
*/
/*
** Retrieve a single line of input text from an input stream.
**
** If pfIn is the input stream passed to consoleClassifySetup(),
** and azPrompt is not NULL, then a prompt is issued before the
** line is collected, as selected by the isContinuation flag.
** Array azPrompt[{0,1}] holds the {main,continuation} prompt.
**
** If zBufPrior is not NULL then it is a buffer from a prior
** call to this routine that can be reused, or will be freed.
**
** The result is stored in space obtained from malloc() and
** must either be freed by the caller or else passed back to
** this function as zBufPrior for reuse.
**
** This function may call upon services of a line-editing
** library to interactively collect line edited input.
*/
SQLITE_INTERNAL_LINKAGE char *
shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
short isContinuation, Prompts azPrompt);
#endif /* defined(SQLITE_CIO_PROMPTED_IN) */
/*
** TBD: Define an interface for application(s) to generate
** completion candidates for use by the line-editor.
**
** This may be premature; the CLI is the only application
** that does this. Yet, getting line-editing melded into
** console I/O is desirable because a line-editing library
** may have to establish console operating mode, possibly
** in a way that interferes with the above functionality.
*/
#if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))
/* Skip over as much z[] input char sequence as is valid UTF-8,
** limited per nAccept char's or whole characters and containing
** no char cn such that ((1<<cn) & ccm)!=0. On return, the
** sequence z:return (inclusive:exclusive) is validated UTF-8.
** Limit: nAccept>=0 => char count, nAccept<0 => character
*/
SQLITE_INTERNAL_LINKAGE const char*
zSkipValidUtf8(const char *z, int nAccept, long ccm);
#endif
-19
View File
@@ -464,23 +464,4 @@ do_execsql_test 5.3 {
t2 t2_idx_0001295b {100 20 5}
}
if 0 {
do_test expert1-6.0 {
catchcmd :memory: {
.expert
select base64('');
.expert
select name from pragma_collation_list order by name collate uint;
}
} {0 {(no new indexes)
SCAN CONSTANT ROW
(no new indexes)
SCAN pragma_collation_list VIRTUAL TABLE INDEX 0:
USE TEMP B-TREE FOR ORDER BY
}}
}
finish_test
+2 -103
View File
@@ -32,7 +32,7 @@
#endif /* !defined(SQLITE_AMALGAMATION) */
#ifndef SQLITE_OMIT_VIRTUALTABLE
#ifndef SQLITE_OMIT_VIRTUALTABLE
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
@@ -662,7 +662,6 @@ static int idxRegisterVtab(sqlite3expert *p){
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
0, /* xIntegrity */
};
return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
@@ -1819,88 +1818,6 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
return rc;
}
/*
** Define and possibly pretend to use a useless collation sequence.
** This pretense allows expert to accept SQL using custom collations.
*/
int dummyCompare(void *up1, int up2, const void *up3, int up4, const void *up5){
(void)up1;
(void)up2;
(void)up3;
(void)up4;
(void)up5;
assert(0); /* VDBE should never be run. */
return 0;
}
/* And a callback to register above upon actual need */
void useDummyCS(void *up1, sqlite3 *db, int etr, const char *zName){
(void)up1;
sqlite3_create_collation_v2(db, zName, etr, 0, dummyCompare, 0);
}
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) \
&& !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
/*
** dummy functions for no-op implementation of UDFs during expert's work
*/
void dummyUDF(sqlite3_context *up1, int up2, sqlite3_value **up3){
(void)up1;
(void)up2;
(void)up3;
assert(0); /* VDBE should never be run. */
}
void dummyUDFvalue(sqlite3_context *up1){
(void)up1;
assert(0); /* VDBE should never be run. */
}
/*
** Register UDFs from user database with another.
*/
int registerUDFs(sqlite3 *dbSrc, sqlite3 *dbDst){
sqlite3_stmt *pStmt;
int rc = sqlite3_prepare_v2(dbSrc,
"SELECT name,type,enc,narg,flags "
"FROM pragma_function_list() "
"WHERE builtin==0", -1, &pStmt, 0);
if( rc==SQLITE_OK ){
while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
int nargs = sqlite3_column_int(pStmt,3);
int flags = sqlite3_column_int(pStmt,4);
const char *name = (char*)sqlite3_column_text(pStmt,0);
const char *type = (char*)sqlite3_column_text(pStmt,1);
const char *enc = (char*)sqlite3_column_text(pStmt,2);
if( name==0 || type==0 || enc==0 ){
/* no-op. Only happens on OOM */
}else{
int ienc = SQLITE_UTF8;
int rcf = SQLITE_ERROR;
if( strcmp(enc,"utf16le")==0 ) ienc = SQLITE_UTF16LE;
else if( strcmp(enc,"utf16be")==0 ) ienc = SQLITE_UTF16BE;
ienc |= (flags & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY));
if( strcmp(type,"w")==0 ){
rcf = sqlite3_create_window_function(dbDst,name,nargs,ienc,0,
dummyUDF,dummyUDFvalue,0,0,0);
}else if( strcmp(type,"a")==0 ){
rcf = sqlite3_create_function(dbDst,name,nargs,ienc,0,
0,dummyUDF,dummyUDFvalue);
}else if( strcmp(type,"s")==0 ){
rcf = sqlite3_create_function(dbDst,name,nargs,ienc,0,
dummyUDF,0,0);
}
if( rcf!=SQLITE_OK ){
rc = rcf;
break;
}
}
}
sqlite3_finalize(pStmt);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
return rc;
}
#endif
/*
** Allocate a new sqlite3expert object.
*/
@@ -1927,21 +1844,7 @@ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0);
}
}
/* Allow custom collations to be dealt with through prepare. */
if( rc==SQLITE_OK ) rc = sqlite3_collation_needed(pNew->dbm,0,useDummyCS);
if( rc==SQLITE_OK ) rc = sqlite3_collation_needed(pNew->dbv,0,useDummyCS);
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) \
&& !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
/* Register UDFs from database [db] with [dbm] and [dbv]. */
if( rc==SQLITE_OK ){
rc = registerUDFs(pNew->db, pNew->dbm);
}
if( rc==SQLITE_OK ){
rc = registerUDFs(pNew->db, pNew->dbv);
}
#endif
/* Copy the entire schema of database [db] into [dbm]. */
if( rc==SQLITE_OK ){
@@ -2017,10 +1920,6 @@ int sqlite3_expert_sql(
while( rc==SQLITE_OK && zStmt && zStmt[0] ){
sqlite3_stmt *pStmt = 0;
/* Ensure that the provided statement compiles against user's DB. */
rc = idxPrepareStmt(p->db, &pStmt, pzErr, zStmt);
if( rc!=SQLITE_OK ) break;
sqlite3_finalize(pStmt);
rc = sqlite3_prepare_v2(p->dbv, zStmt, -1, &pStmt, &zStmt);
if( rc==SQLITE_OK ){
if( pStmt ){
+17 -81
View File
@@ -640,7 +640,6 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid");
sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
sqlite3_vtab_config(p->db, SQLITE_VTAB_INNOCUOUS);
/* Create a list of user columns for the virtual table */
zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
@@ -3890,8 +3889,6 @@ static int fts3RenameMethod(
rc = sqlite3Fts3PendingTermsFlush(p);
}
p->bIgnoreSavepoint = 1;
if( p->zContentTbl==0 ){
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
@@ -3919,8 +3916,6 @@ static int fts3RenameMethod(
"ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';",
p->zDb, p->zName, zName
);
p->bIgnoreSavepoint = 0;
return rc;
}
@@ -3931,28 +3926,12 @@ static int fts3RenameMethod(
*/
static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
int rc = SQLITE_OK;
Fts3Table *pTab = (Fts3Table*)pVtab;
assert( pTab->inTransaction );
assert( pTab->mxSavepoint<=iSavepoint );
TESTONLY( pTab->mxSavepoint = iSavepoint );
if( pTab->bIgnoreSavepoint==0 ){
if( fts3HashCount(&pTab->aIndex[0].hPending)>0 ){
char *zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
pTab->zDb, pTab->zName, pTab->zName
);
if( zSql ){
pTab->bIgnoreSavepoint = 1;
rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0);
pTab->bIgnoreSavepoint = 0;
sqlite3_free(zSql);
}else{
rc = SQLITE_NOMEM;
}
}
if( rc==SQLITE_OK ){
pTab->iSavepoint = iSavepoint+1;
}
UNUSED_PARAMETER(iSavepoint);
assert( ((Fts3Table *)pVtab)->inTransaction );
assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint );
TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
rc = fts3SyncMethod(pVtab);
}
return rc;
}
@@ -3963,11 +3942,12 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts3Table *pTab = (Fts3Table*)pVtab;
assert( pTab->inTransaction );
assert( pTab->mxSavepoint >= iSavepoint );
TESTONLY( pTab->mxSavepoint = iSavepoint-1 );
pTab->iSavepoint = iSavepoint;
TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
UNUSED_PARAMETER(iSavepoint);
UNUSED_PARAMETER(pVtab);
assert( p->inTransaction );
assert( p->mxSavepoint >= iSavepoint );
TESTONLY( p->mxSavepoint = iSavepoint-1 );
return SQLITE_OK;
}
@@ -3977,13 +3957,11 @@ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
** Discard the contents of the pending terms table.
*/
static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts3Table *pTab = (Fts3Table*)pVtab;
Fts3Table *p = (Fts3Table*)pVtab;
UNUSED_PARAMETER(iSavepoint);
assert( pTab->inTransaction );
TESTONLY( pTab->mxSavepoint = iSavepoint );
if( (iSavepoint+1)<=pTab->iSavepoint ){
sqlite3Fts3PendingTermsClear(pTab);
}
assert( p->inTransaction );
TESTONLY( p->mxSavepoint = iSavepoint );
sqlite3Fts3PendingTermsClear(p);
return SQLITE_OK;
}
@@ -4002,49 +3980,8 @@ static int fts3ShadowName(const char *zName){
return 0;
}
/*
** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual
** table.
*/
static int fts3Integrity(
sqlite3_vtab *pVtab, /* The virtual table to be checked */
const char *zSchema, /* Name of schema in which pVtab lives */
const char *zTabname, /* Name of the pVTab table */
int isQuick, /* True if this is a quick_check */
char **pzErr /* Write error message here */
){
Fts3Table *p = (Fts3Table*)pVtab;
char *zSql;
int rc;
char *zErr = 0;
assert( pzErr!=0 );
assert( *pzErr==0 );
UNUSED_PARAMETER(isQuick);
zSql = sqlite3_mprintf(
"INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');",
zSchema, zTabname, zTabname);
if( zSql==0 ){
return SQLITE_NOMEM;
}
rc = sqlite3_exec(p->db, zSql, 0, 0, &zErr);
sqlite3_free(zSql);
if( (rc&0xff)==SQLITE_CORRUPT ){
*pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
p->bFts4 ? 4 : 3, zSchema, zTabname);
}else if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("unable to validate the inverted index for"
" FTS%d table %s.%s: %s",
p->bFts4 ? 4 : 3, zSchema, zTabname, zErr);
}
sqlite3_free(zErr);
return SQLITE_OK;
}
static const sqlite3_module fts3Module = {
/* iVersion */ 4,
/* iVersion */ 3,
/* xCreate */ fts3CreateMethod,
/* xConnect */ fts3ConnectMethod,
/* xBestIndex */ fts3BestIndexMethod,
@@ -4068,7 +4005,6 @@ static const sqlite3_module fts3Module = {
/* xRelease */ fts3ReleaseMethod,
/* xRollbackTo */ fts3RollbackToMethod,
/* xShadowName */ fts3ShadowName,
/* xIntegrity */ fts3Integrity,
};
/*
-1
View File
@@ -265,7 +265,6 @@ struct Fts3Table {
int nPgsz; /* Page size for host database */
char *zSegmentsTbl; /* Name of %_segments table */
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
int iSavepoint;
/*
** The following array of hash tables is used to buffer pending index
+1 -2
View File
@@ -545,8 +545,7 @@ int sqlite3Fts3InitAux(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
0 /* xIntegrity */
0 /* xShadowName */
};
int rc; /* Return code */
+1 -2
View File
@@ -362,8 +362,7 @@ int sqlite3Fts3InitTerm(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
0 /* xIntegrity */
0 /* xShadowName */
};
int rc; /* Return code */
+1 -2
View File
@@ -445,8 +445,7 @@ int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestroy)(void*)){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
0 /* xIntegrity */
0 /* xShadowName */
};
int rc; /* Return code */
+7 -19
View File
@@ -3325,6 +3325,7 @@ int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
sqlite3Fts3PendingTermsClear(p);
/* Determine the auto-incr-merge setting if unknown. If enabled,
** estimate the number of leaf blocks of content to be written
@@ -3346,10 +3347,6 @@ int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = sqlite3_reset(pStmt);
}
}
if( rc==SQLITE_OK ){
sqlite3Fts3PendingTermsClear(p);
}
return rc;
}
@@ -3981,8 +3978,6 @@ static int fts3AppendToNode(
blobGrowBuffer(pPrev, nTerm, &rc);
if( rc!=SQLITE_OK ) return rc;
assert( pPrev!=0 );
assert( pPrev->a!=0 );
nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
@@ -4039,13 +4034,9 @@ static int fts3IncrmergeAppend(
nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist;
/* If the current block is not empty, and if adding this term/doclist
** to the current block would make it larger than Fts3Table.nNodeSize bytes,
** and if there is still room for another leaf page, write this block out to
** the database. */
if( pLeaf->block.n>0
&& (pLeaf->block.n + nSpace)>p->nNodeSize
&& pLeaf->iBlock < (pWriter->iStart + pWriter->nLeafEst)
){
** to the current block would make it larger than Fts3Table.nNodeSize
** bytes, write this block out to the database. */
if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){
rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
pWriter->nWork++;
@@ -4377,7 +4368,7 @@ static int fts3IncrmergeLoad(
rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0);
blobGrowBuffer(&pNode->block,
MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc
);
);
if( rc==SQLITE_OK ){
memcpy(pNode->block.a, aBlock, nBlock);
pNode->block.n = nBlock;
@@ -5442,11 +5433,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
rc = fts3DoIncrmerge(p, &zVal[6]);
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
rc = fts3DoAutoincrmerge(p, &zVal[10]);
}else if( nVal==5 && 0==sqlite3_strnicmp(zVal, "flush", 5) ){
rc = sqlite3Fts3PendingTermsFlush(p);
}
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
else{
}else{
int v;
if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
v = atoi(&zVal[9]);
@@ -5464,8 +5452,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
rc = SQLITE_OK;
}
}
#endif
}
return rc;
}
+12 -47
View File
@@ -110,19 +110,15 @@ static int fts5CInstIterInit(
*/
typedef struct HighlightContext HighlightContext;
struct HighlightContext {
/* Constant parameters to fts5HighlightCb() */
CInstIter iter; /* Coalesced Instance Iterator */
int iPos; /* Current token offset in zIn[] */
int iRangeStart; /* First token to include */
int iRangeEnd; /* If non-zero, last token to include */
const char *zOpen; /* Opening highlight */
const char *zClose; /* Closing highlight */
const char *zIn; /* Input text */
int nIn; /* Size of input text in bytes */
/* Variables modified by fts5HighlightCb() */
CInstIter iter; /* Coalesced Instance Iterator */
int iPos; /* Current token offset in zIn[] */
int iOff; /* Have copied up to this offset in zIn[] */
int bOpen; /* True if highlight is open */
int iOff; /* Current offset within zIn[] */
char *zOut; /* Output value */
};
@@ -155,8 +151,8 @@ static int fts5HighlightCb(
int tflags, /* Mask of FTS5_TOKEN_* flags */
const char *pToken, /* Buffer containing token */
int nToken, /* Size of token in bytes */
int iStartOff, /* Start byte offset of token */
int iEndOff /* End byte offset of token */
int iStartOff, /* Start offset of token */
int iEndOff /* End offset of token */
){
HighlightContext *p = (HighlightContext*)pContext;
int rc = SQLITE_OK;
@@ -172,55 +168,30 @@ static int fts5HighlightCb(
if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff;
}
/* If the parenthesis is open, and this token is not part of the current
** phrase, and the starting byte offset of this token is past the point
** that has currently been copied into the output buffer, close the
** parenthesis. */
if( p->bOpen
&& (iPos<=p->iter.iStart || p->iter.iStart<0)
&& iStartOff>p->iOff
){
fts5HighlightAppend(&rc, p, p->zClose, -1);
p->bOpen = 0;
}
/* If this is the start of a new phrase, and the highlight is not open:
**
** * copy text from the input up to the start of the phrase, and
** * open the highlight.
*/
if( iPos==p->iter.iStart && p->bOpen==0 ){
if( iPos==p->iter.iStart ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff);
fts5HighlightAppend(&rc, p, p->zOpen, -1);
p->iOff = iStartOff;
p->bOpen = 1;
}
if( iPos==p->iter.iEnd ){
if( p->bOpen==0 ){
assert( p->iRangeEnd>=0 );
if( p->iRangeEnd>=0 && p->iter.iStart<p->iRangeStart ){
fts5HighlightAppend(&rc, p, p->zOpen, -1);
p->bOpen = 1;
}
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
fts5HighlightAppend(&rc, p, p->zClose, -1);
p->iOff = iEndOff;
if( rc==SQLITE_OK ){
rc = fts5CInstIterNext(&p->iter);
}
}
if( iPos==p->iRangeEnd ){
if( p->bOpen ){
if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
p->iOff = iEndOff;
}
fts5HighlightAppend(&rc, p, p->zClose, -1);
p->bOpen = 0;
}
if( p->iRangeEnd>=0 && iPos==p->iRangeEnd ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
p->iOff = iEndOff;
if( iPos>=p->iter.iStart && iPos<p->iter.iEnd ){
fts5HighlightAppend(&rc, p, p->zClose, -1);
}
}
return rc;
@@ -261,9 +232,6 @@ static void fts5HighlightFunction(
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
if( ctx.bOpen ){
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
}
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
if( rc==SQLITE_OK ){
@@ -542,9 +510,6 @@ static void fts5SnippetFunction(
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
if( ctx.bOpen ){
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
}
if( ctx.iRangeEnd>=(nColSize-1) ){
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
}else{
+4 -2
View File
@@ -432,8 +432,10 @@ static Fts5HashEntry *fts5HashEntryMerge(
}
/*
** Link all tokens from hash table iHash into a list in sorted order. The
** tokens are not removed from the hash table.
** Extract all tokens from hash table iHash and link them into a list
** in sorted order. The hash table is cleared before returning. It is
** the responsibility of the caller to free the elements of the returned
** list.
*/
static int fts5HashEntrySort(
Fts5Hash *pHash,
+33 -102
View File
@@ -2719,14 +2719,6 @@ static void fts5SegIterHashInit(
pLeaf->p = (u8*)pList;
}
}
/* The call to sqlite3Fts5HashScanInit() causes the hash table to
** fill the size field of all existing position lists. This means they
** can no longer be appended to. Since the only scenario in which they
** can be appended to is if the previous operation on this table was
** a DELETE, by clearing the Fts5Index.bDelete flag we can avoid this
** possibility altogether. */
p->bDelete = 0;
}else{
p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data),
(const char*)pTerm, nTerm, (void**)&pLeaf, &nList
@@ -2912,6 +2904,7 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
assert_nc( i2!=0 );
pRes->bTermEq = 1;
if( p1->iRowid==p2->iRowid ){
p1->bDel = p2->bDel;
return i2;
}
res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1;
@@ -3279,7 +3272,7 @@ static Fts5Iter *fts5MultiIterAlloc(
int nSeg
){
Fts5Iter *pNew;
i64 nSlot; /* Power of two >= nSeg */
int nSlot; /* Power of two >= nSeg */
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
pNew = fts5IdxMalloc(p,
@@ -4404,7 +4397,7 @@ static void fts5WriteAppendPoslistData(
const u8 *a = aData;
int n = nData;
assert( p->pConfig->pgsz>0 || p->rc!=SQLITE_OK );
assert( p->pConfig->pgsz>0 );
while( p->rc==SQLITE_OK
&& (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
){
@@ -5055,6 +5048,7 @@ static void fts5DoSecureDelete(
int iPgIdx = pSeg->pLeaf->szLeaf;
u64 iDelta = 0;
u64 iNextDelta = 0;
int iNextOff = 0;
int iOff = 0;
int nIdx = 0;
@@ -5062,6 +5056,7 @@ static void fts5DoSecureDelete(
int bLastInDoclist = 0;
int iIdx = 0;
int iStart = 0;
int iKeyOff = 0;
int iDelKeyOff = 0; /* Offset of deleted key, if any */
nIdx = nPg-iPgIdx;
@@ -5086,21 +5081,10 @@ static void fts5DoSecureDelete(
** This block sets the following variables:
**
** iStart:
** The offset of the first byte of the rowid or delta-rowid
** value for the doclist entry being removed.
**
** iDelta:
** The value of the rowid or delta-rowid value for the doclist
** entry being removed.
**
** iNextOff:
** The offset of the next entry following the position list
** for the one being removed. If the position list for this
** entry overflows onto the next leaf page, this value will be
** greater than pLeaf->szLeaf.
*/
{
int iSOP; /* Start-Of-Position-list */
int iSOP;
if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
iStart = pSeg->iTermLeafOffset;
}else{
@@ -5136,81 +5120,47 @@ static void fts5DoSecureDelete(
}
iOff = iStart;
/* If the position-list for the entry being removed flows over past
** the end of this page, delete the portion of the position-list on the
** next page and beyond.
**
** Set variable bLastInDoclist to true if this entry happens
** to be the last rowid in the doclist for its term. */
if( iNextOff>=iPgIdx ){
int pgno = pSeg->iLeafPgno+1;
fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
iNextOff = iPgIdx;
}
if( pSeg->bDel==0 ){
if( iNextOff!=iPgIdx ){
/* Loop through the page-footer. If iNextOff (offset of the
** entry following the one we are removing) is equal to the
** offset of a key on this page, then the entry is the last
** in its doclist. */
int iKeyOff = 0;
for(iIdx=0; iIdx<nIdx; /* no-op */){
u32 iVal = 0;
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
iKeyOff += iVal;
if( iKeyOff==iNextOff ){
bLastInDoclist = 1;
}
}else{
/* Set bLastInDoclist to true if the entry being removed is the last
** in its doclist. */
for(iIdx=0, iKeyOff=0; iIdx<nIdx; /* no-op */){
u32 iVal = 0;
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
iKeyOff += iVal;
if( iKeyOff==iNextOff ){
bLastInDoclist = 1;
}
}
/* If this is (a) the first rowid on a page and (b) is not followed by
** another position list on the same page, set the "first-rowid" field
** of the header to 0. */
if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist || iNextOff==iPgIdx) ){
fts5PutU16(&aPg[0], 0);
}
}
if( pSeg->bDel ){
iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta);
aPg[iOff++] = 0x01;
}else if( bLastInDoclist==0 ){
if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist||iNextOff==iPgIdx) ){
fts5PutU16(&aPg[0], 0);
}
if( bLastInDoclist==0 ){
if( iNextOff!=iPgIdx ){
u64 iNextDelta = 0;
iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
}
}else if(
pSeg->iLeafPgno==pSeg->iTermLeafPgno
&& iStart==pSeg->iTermLeafOffset
iStart==pSeg->iTermLeafOffset && pSeg->iLeafPgno==pSeg->iTermLeafPgno
){
/* The entry being removed was the only position list in its
** doclist. Therefore the term needs to be removed as well. */
int iKey = 0;
int iKeyOff = 0;
/* Set iKeyOff to the offset of the term that will be removed - the
** last offset in the footer that is not greater than iStart. */
for(iIdx=0; iIdx<nIdx; iKey++){
for(iIdx=0, iKeyOff=0; iIdx<nIdx; iKey++){
u32 iVal = 0;
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
if( (iKeyOff+iVal)>(u32)iStart ) break;
iKeyOff += iVal;
}
assert_nc( iKey>=1 );
/* Set iDelKeyOff to the value of the footer entry to remove from
** the page. */
iDelKeyOff = iOff = iKeyOff;
if( iNextOff!=iPgIdx ){
/* This is the only position-list associated with the term, and there
** is another term following it on this page. So the subsequent term
** needs to be moved to replace the term associated with the entry
** being removed. */
int nPrefix = 0;
int nSuffix = 0;
int nPrefix2 = 0;
@@ -5289,15 +5239,6 @@ static void fts5DoSecureDelete(
}
}
/* Assuming no error has occurred, this block does final edits to the
** leaf page before writing it back to disk. Input variables are:
**
** nPg: Total initial size of leaf page.
** iPgIdx: Initial offset of page footer.
**
** iOff: Offset to move data to
** iNextOff: Offset to move data from
*/
if( p->rc==SQLITE_OK ){
const int nMove = nPg - iNextOff; /* Number of bytes to move */
int nShift = iNextOff - iOff; /* Distance to move them */
@@ -5498,16 +5439,10 @@ static void fts5FlushOneHash(Fts5Index *p){
fts5WriteFlushLeaf(p, &writer);
}
}else{
int bDel = 0;
int nPos = 0;
int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDel);
if( bDel && bSecureDelete ){
fts5BufferAppendVarint(&p->rc, pBuf, nPos*2);
iOff += nCopy;
nCopy = nPos;
}else{
nCopy += nPos;
}
int bDummy;
int nPos;
int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
nCopy += nPos;
if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
/* The entire poslist will fit on the current leaf. So copy
** it in one go. */
@@ -5545,6 +5480,7 @@ static void fts5FlushOneHash(Fts5Index *p){
assert( pBuf->n<=pBuf->nSpace );
if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
}
sqlite3Fts5HashClear(pHash);
fts5WriteFinish(p, &writer, &pgnoLast);
assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 );
@@ -5577,6 +5513,7 @@ static void fts5FlushOneHash(Fts5Index *p){
fts5IndexCrisismerge(p, &pStruct);
fts5StructureWrite(p, pStruct);
fts5StructureRelease(pStruct);
p->nContentlessDelete = 0;
}
/*
@@ -5587,12 +5524,8 @@ static void fts5IndexFlush(Fts5Index *p){
if( p->nPendingData || p->nContentlessDelete ){
assert( p->pHash );
fts5FlushOneHash(p);
if( p->rc==SQLITE_OK ){
sqlite3Fts5HashClear(p->pHash);
p->nPendingData = 0;
p->nPendingRow = 0;
p->nContentlessDelete = 0;
}
p->nPendingData = 0;
p->nPendingRow = 0;
}
}
@@ -5670,9 +5603,8 @@ int sqlite3Fts5IndexOptimize(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
assert( p->rc!=SQLITE_OK || p->nContentlessDelete==0 );
assert( p->nContentlessDelete==0 );
pStruct = fts5StructureRead(p);
assert( p->rc!=SQLITE_OK || pStruct!=0 );
fts5StructureInvalidate(p);
if( pStruct ){
@@ -6219,7 +6151,7 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
/* Flush the hash table to disk if required */
if( iRowid<p->iWriteRowid
|| (iRowid==p->iWriteRowid && p->bDelete==0)
|| (p->nPendingData > p->pConfig->nHashSize)
|| (p->nPendingData > p->pConfig->nHashSize)
){
fts5IndexFlush(p);
}
@@ -8335,8 +8267,7 @@ int sqlite3Fts5IndexInit(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
0 /* xIntegrity */
0 /* xShadowName */
};
rc = sqlite3_create_module(db, "fts5_structure", &fts5structure_module, 0);
}
+16 -108
View File
@@ -117,8 +117,6 @@ struct Fts5FullTable {
Fts5Storage *pStorage; /* Document store */
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
@@ -407,13 +405,6 @@ static int fts5InitVtab(
pConfig->pzErrmsg = 0;
}
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
rc = sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1);
}
if( rc==SQLITE_OK ){
rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
}
if( rc!=SQLITE_OK ){
fts5FreeVtab(pTab);
pTab = 0;
@@ -1363,8 +1354,9 @@ static int fts5FilterMethod(
pCsr->pExpr = pTab->pSortCsr->pExpr;
rc = fts5CursorFirst(pTab, pCsr, bDesc);
}else if( pCsr->pExpr ){
assert( rc==SQLITE_OK );
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
if( rc==SQLITE_OK ){
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
}
if( rc==SQLITE_OK ){
if( bOrderByRank ){
pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
@@ -1535,7 +1527,6 @@ static int fts5SpecialInsert(
Fts5Config *pConfig = pTab->p.pConfig;
int rc = SQLITE_OK;
int bError = 0;
int bLoadConfig = 0;
if( 0==sqlite3_stricmp("delete-all", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
@@ -1547,7 +1538,6 @@ static int fts5SpecialInsert(
}else{
rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
}
bLoadConfig = 1;
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NONE ){
fts5SetVtabError(pTab,
@@ -1557,7 +1547,6 @@ static int fts5SpecialInsert(
}else{
rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
}
bLoadConfig = 1;
}else if( 0==sqlite3_stricmp("optimize", zCmd) ){
rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
}else if( 0==sqlite3_stricmp("merge", zCmd) ){
@@ -1570,8 +1559,6 @@ static int fts5SpecialInsert(
}else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
#endif
}else if( 0==sqlite3_stricmp("flush", zCmd) ){
rc = sqlite3Fts5FlushToDisk(&pTab->p);
}else{
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
if( rc==SQLITE_OK ){
@@ -1585,12 +1572,6 @@ static int fts5SpecialInsert(
}
}
}
if( rc==SQLITE_OK && bLoadConfig ){
pTab->p.pConfig->iCookie--;
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
}
return rc;
}
@@ -1709,7 +1690,7 @@ static int fts5UpdateMethod(
assert( nArg!=1 || eType0==SQLITE_INTEGER );
/* Filter out attempts to run UPDATE or DELETE on contentless tables.
** This is not suported. Except - they are both supported if the CREATE
** This is not suported. Except - DELETE is supported if the CREATE
** VIRTUAL TABLE statement contained "contentless_delete=1". */
if( eType0==SQLITE_INTEGER
&& pConfig->eContent==FTS5_CONTENT_NONE
@@ -1738,8 +1719,7 @@ static int fts5UpdateMethod(
}
else if( eType0!=SQLITE_INTEGER ){
/* An INSERT statement. If the conflict-mode is REPLACE, first remove
** the current entry (if any). */
/* If this is a REPLACE, first remove the current entry (if any) */
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
@@ -2613,12 +2593,8 @@ static int fts5RenameMethod(
sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
int rc;
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
pTab->bInSavepoint = 1;
rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
pTab->bInSavepoint = 0;
return rc;
return sqlite3Fts5StorageRename(pTab->pStorage, zName);
}
int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
@@ -2632,29 +2608,9 @@ int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
** Flush the contents of the pending-terms table to disk.
*/
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;
}
}
return rc;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint);
return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
}
/*
@@ -2663,16 +2619,9 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
int rc = SQLITE_OK;
fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
if( (iSavepoint+1)<pTab->iSavepoint ){
rc = sqlite3Fts5FlushToDisk(&pTab->p);
if( rc==SQLITE_OK ){
pTab->iSavepoint = iSavepoint;
}
}
return rc;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint);
return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
}
/*
@@ -2682,14 +2631,11 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
*/
static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
int rc = SQLITE_OK;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
fts5TripCursors(pTab);
pTab->p.pConfig->pgsz = 0;
if( (iSavepoint+1)<=pTab->iSavepoint ){
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
}
return rc;
return sqlite3Fts5StorageRollback(pTab->pStorage);
}
/*
@@ -2909,46 +2855,9 @@ static int fts5ShadowName(const char *zName){
return 0;
}
/*
** Run an integrity check on the FTS5 data structures. Return a string
** if anything is found amiss. Return a NULL pointer if everything is
** OK.
*/
static int fts5Integrity(
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 */
int isQuick, /* True if this is a quick-check */
char **pzErr /* Write error message here */
){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
Fts5Config *pConfig = pTab->p.pConfig;
char *zSql;
char *zErr = 0;
int rc;
assert( pzErr!=0 && *pzErr==0 );
UNUSED_PARAM(isQuick);
zSql = sqlite3_mprintf(
"INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');",
zSchema, zTabname, pConfig->zName);
if( zSql==0 ) return SQLITE_NOMEM;
rc = sqlite3_exec(pConfig->db, zSql, 0, 0, &zErr);
sqlite3_free(zSql);
if( (rc&0xff)==SQLITE_CORRUPT ){
*pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
zSchema, zTabname);
}else if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("unable to validate the inverted index for"
" FTS5 table %s.%s: %s",
zSchema, zTabname, zErr);
}
sqlite3_free(zErr);
return SQLITE_OK;
}
static int fts5Init(sqlite3 *db){
static const sqlite3_module fts5Mod = {
/* iVersion */ 4,
/* iVersion */ 3,
/* xCreate */ fts5CreateMethod,
/* xConnect */ fts5ConnectMethod,
/* xBestIndex */ fts5BestIndexMethod,
@@ -2971,8 +2880,7 @@ static int fts5Init(sqlite3 *db){
/* xSavepoint */ fts5SavepointMethod,
/* xRelease */ fts5ReleaseMethod,
/* xRollbackTo */ fts5RollbackToMethod,
/* xShadowName */ fts5ShadowName,
/* xIntegrity */ fts5Integrity
/* xShadowName */ fts5ShadowName
};
int rc;
+1 -3
View File
@@ -1184,9 +1184,7 @@ int sqlite3Fts5StorageSync(Fts5Storage *p){
i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
if( p->bTotalsValid ){
rc = fts5StorageSaveTotals(p);
if( rc==SQLITE_OK ){
p->bTotalsValid = 0;
}
p->bTotalsValid = 0;
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexSync(p->pIndex);
+1 -2
View File
@@ -472,8 +472,7 @@ int sqlite3Fts5TestRegisterTok(sqlite3 *db, fts5_api *pApi){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
0 /* xIntegrity */
0 /* xShadowName */
};
int rc; /* Return code */
+26 -69
View File
@@ -229,12 +229,6 @@ static const unsigned char sqlite3Utf8Trans1[] = {
#endif /* ifndef SQLITE_AMALGAMATION */
#define FTS5_SKIP_UTF8(zIn) { \
if( ((unsigned char)(*(zIn++)))>=0xc0 ){ \
while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \
} \
}
typedef struct Unicode61Tokenizer Unicode61Tokenizer;
struct Unicode61Tokenizer {
unsigned char aTokenChar[128]; /* ASCII range token characters */
@@ -1270,7 +1264,6 @@ static int fts5PorterTokenize(
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
int bFold; /* True to fold to lower-case */
int iFoldParam; /* Parameter to pass to Fts5UnicodeFold() */
};
/*
@@ -1297,7 +1290,6 @@ static int fts5TriCreate(
}else{
int i;
pNew->bFold = 1;
pNew->iFoldParam = 0;
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
@@ -1306,21 +1298,10 @@ static int fts5TriCreate(
}else{
pNew->bFold = (zArg[0]=='0');
}
}else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
rc = SQLITE_ERROR;
}else{
pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
}
}else{
rc = SQLITE_ERROR;
}
}
if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
rc = SQLITE_ERROR;
}
if( rc!=SQLITE_OK ){
fts5TriDelete((Fts5Tokenizer*)pNew);
pNew = 0;
@@ -1343,62 +1324,40 @@ static int fts5TriTokenize(
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
int rc = SQLITE_OK;
char aBuf[32];
char *zOut = aBuf;
int ii;
const unsigned char *zIn = (const unsigned char*)pText;
const unsigned char *zEof = &zIn[nText];
u32 iCode;
int aStart[3]; /* Input offset of each character in aBuf[] */
UNUSED_PARAM(unusedFlags);
/* Populate aBuf[] with the characters for the first trigram. */
for(ii=0; ii<3; ii++){
do {
aStart[ii] = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) return SQLITE_OK;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
}while( iCode==0 );
WRITE_UTF8(zOut, iCode);
}
/* At the start of each iteration of this loop:
**
** aBuf: Contains 3 characters. The 3 characters of the next trigram.
** zOut: Points to the byte following the last character in aBuf.
** aStart[3]: Contains the byte offset in the input text corresponding
** to the start of each of the three characters in the buffer.
*/
assert( zIn<=zEof );
while( 1 ){
int iNext; /* Start of character following current tri */
const char *z1;
char *zOut = aBuf;
int iStart = zIn - (const unsigned char*)pText;
const unsigned char *zNext;
/* Read characters from the input up until the first non-diacritic */
do {
iNext = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
zNext = zIn;
if( zIn<zEof ){
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
}while( iCode==0 );
/* Pass the current trigram back to fts5 */
rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
if( iCode==0 || rc!=SQLITE_OK ) break;
/* Remove the first character from buffer aBuf[]. Append the character
** with codepoint iCode. */
z1 = aBuf;
FTS5_SKIP_UTF8(z1);
memmove(aBuf, z1, zOut - z1);
zOut -= (z1 - aBuf);
WRITE_UTF8(zOut, iCode);
/* Update the aStart[] array */
aStart[0] = aStart[1];
aStart[1] = aStart[2];
aStart[2] = iNext;
}else{
break;
}
if( zIn<zEof ){
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
}else{
break;
}
rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
if( rc!=SQLITE_OK ) break;
zIn = zNext;
}
return rc;
@@ -1421,9 +1380,7 @@ int sqlite3Fts5TokenizerPattern(
){
if( xCreate==fts5TriCreate ){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
if( p->iFoldParam==0 ){
return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
}
return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
}
return FTS5_PATTERN_NONE;
}
+1 -2
View File
@@ -783,8 +783,7 @@ int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
/* xShadowName */ 0,
/* xIntegrity */ 0
/* xShadowName */ 0
};
void *p = (void*)pGlobal;
+2 -5
View File
@@ -65,9 +65,7 @@ foreach w {a b c d e f} {
do_execsql_test 2.4 {
INSERT INTO t1(t1) VALUES('integrity-check');
PRAGMA integrity_check;
PRAGMA integrity_check(t1);
} {ok ok}
}
#-------------------------------------------------------------------------
@@ -90,7 +88,6 @@ foreach {i x y} {
} {
do_execsql_test 3.$i.1 { INSERT INTO t1 VALUES($x, $y) }
do_execsql_test 3.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
do_execsql_test 3.$i.3 { PRAGMA integrity_check(t1) } ok
if {[set_test_counter errors]} break
}
@@ -138,7 +135,7 @@ foreach {i x y} {
10 {ddd abcde dddd dd c} {dddd c c d abcde}
} {
do_execsql_test 5.$i.1 { INSERT INTO t1 VALUES($x, $y) }
do_execsql_test 5.$i.2 { PRAGMA integrity_check(t1) } ok
do_execsql_test 5.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
if {[set_test_counter errors]} break
}
+1 -27
View File
@@ -307,31 +307,5 @@ do_catchsql_test 10.1.4 {
SELECT group_concat(firstcol(t1), '.') FROM t1 GROUP BY rowid
} {1 {unable to use function firstcol in the requested context}}
#-------------------------------------------------------------------------
# Test that xInstCount() works from within an xPhraseQuery() callback.
#
reset_db
proc xCallback {cmd} {
incr ::hitcount [$cmd xInstCount]
return SQLITE_OK
}
proc fts5_hitcount {cmd} {
set ::hitcount 0
$cmd xQueryPhrase 0 xCallback
return $::hitcount
}
sqlite3_fts5_create_function db fts5_hitcount fts5_hitcount
do_execsql_test 11.1 {
CREATE VIRTUAL TABLE x1 USING fts5(z);
INSERT INTO x1 VALUES('one two three');
INSERT INTO x1 VALUES('one two one three one');
INSERT INTO x1 VALUES('one two three');
}
do_execsql_test 11.2 {
SELECT fts5_hitcount(x1) FROM x1('one') LIMIT 1;
} {5}
finish_test
-40
View File
@@ -65,44 +65,4 @@ do_execsql_test 2.1 {
INSERT INTO fts_idx(fts_idx) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
# Tests for OR IGNORE conflict handling.
#
reset_db
foreach_detail_mode $::testprefix {
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(xyz, detail=%DETAIL%);
BEGIN;
INSERT INTO t1(rowid, xyz) VALUES(13, 'thirteen documents');
INSERT INTO t1(rowid, xyz) VALUES(14, 'fourteen documents');
INSERT INTO t1(rowid, xyz) VALUES(15, 'fifteen documents');
COMMIT;
}
set db_cksum [cksum]
foreach {tn sql} {
1 {
INSERT OR IGNORE INTO t1(rowid, xyz) VALUES(14, 'new text');
}
2 {
UPDATE OR IGNORE t1 SET rowid=13 WHERE rowid=15;
}
3 {
INSERT OR IGNORE INTO t1(rowid, xyz)
SELECT 13, 'some text'
UNION ALL
SELECT 14, 'some text'
UNION ALL
SELECT 15, 'some text'
}
} {
do_execsql_test 3.1.$tn.1 $sql
do_test 3.1.$tn.2 { cksum } $db_cksum
}
}
finish_test
+1
View File
@@ -294,3 +294,4 @@ do_catchsql_test 7.2.5 {
} {1 {recursively defined fts5 content table}}
finish_test
+1
View File
@@ -268,3 +268,4 @@ do_execsql_test 8.2 {
} {}
finish_test
+1
View File
@@ -205,3 +205,4 @@ foreach {tn step} {
finish_test
+1
View File
@@ -193,3 +193,4 @@ do_execsql_test 3.7 {
finish_test
+1
View File
@@ -245,3 +245,4 @@ do_execsql_test 4.3 {
}
finish_test
+1
View File
@@ -56,3 +56,4 @@ foreach {tn up err} {
}
finish_test
-4
View File
@@ -48,10 +48,6 @@ do_test 1.3 {
}
catchsql { INSERT INTO t1(t1) VALUES('integrity-check') }
} {1 {database disk image is malformed}}
do_execsql_test 1.3b {
PRAGMA integrity_check(t1);
} {{malformed inverted index for FTS5 table main.t1}}
do_test 1.4 {
db_restore_and_reopen
-3
View File
@@ -167,9 +167,6 @@ foreach {tn hdr} {
do_test 3.$tn.$tn2.2 {
catchsql { INSERT INTO x3(x3) VALUES('integrity-check') }
} {1 {database disk image is malformed}}
do_execsql_test 3.$tn.$tn2.3 {
PRAGMA integrity_check(x3);
} {{malformed inverted index for FTS5 table main.x3}}
}
execsql ROLLBACK
-85
View File
@@ -880,91 +880,6 @@ do_catchsql_test 5.4 {
UPDATE t1 SET content=randomblob(500);
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 6.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 32768 pagesize 4096 filename crash-42fa37b694d45a.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 07 .....@ ........
| 96: 00 00 00 00 0d 00 00 00 07 0d d2 00 0f c4 0f 6d ...............m
| 112: 0f 02 0e ab 0e 4e 0d f6 0d d2 00 00 00 00 00 00 .....N..........
| 3536: 00 00 22 07 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
| 3552: 32 74 32 07 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
| 3568: 20 74 32 28 78 29 56 06 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
| 3584: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
| 3600: 6f 6e 66 69 67 06 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
| 3616: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
| 3632: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
| 3648: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 05 WITHOUT ROWID[.
| 3664: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
| 3680: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
| 3696: 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
| 3712: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
| 3728: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
| 3744: 59 2c 20 73 7a 20 42 4c 4f 42 29 55 04 06 17 21 Y, sz BLOB)U...!
| 3760: 21 01 77 74 61 62 6c 65 74 31 5f 63 6f 6e 74 65 !.wtablet1_conte
| 3776: 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 04 43 52 45 ntt1_content.CRE
| 3792: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f ATE TABLE 't1_co
| 3808: 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 45 ntent'(id INTEGE
| 3824: 52 20 50 52 49 4d 41 52 49 20 4b 45 59 2c 20 63 R PRIMARI KEY, c
| 3840: 30 29 69 03 07 17 19 19 01 81 2d 74 61 62 6c 65 0)i.......-table
| 3856: 74 31 5f 69 64 78 74 31 5f 69 64 78 03 43 52 45 t1_idxt1_idx.CRE
| 3872: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 69 64 ATE TABLE 't1_id
| 3888: 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 x'(segid, term,
| 3904: 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 pgno, PRIMARY KE
| 3920: 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29 29 20 Y(segid, term))
| 3936: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55 02 07 WITHOUT ROWIDU..
| 3952: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 64 61 ......tablet1_da
| 3968: 74 61 74 31 5f 64 61 74 61 02 43 52 45 41 54 45 tat1_data.CREATE
| 3984: 20 54 41 42 4c 45 20 27 74 31 5f 64 61 74 61 27 TABLE 't1_data'
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 4016: 41 52 b9 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 AR. KEY, block B
| 4032: 4c 4f 42 29 3a 01 06 17 11 11 08 63 74 61 62 6c LOB):......ctabl
| 4048: 65 74 31 74 31 43 52 45 41 54 45 20 56 49 52 54 et1t1CREATE VIRT
| 4064: 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 49 UAL TABLE t1 USI
| 4080: 4e 47 20 66 74 73 35 28 63 6f 6e 74 65 6e 74 29 NG fts5(content)
| page 2 offset 4096
| 0: 0d 00 00 00 03 0f bd 00 0f e8 0f ef 0f bd f0 00 ................
| 16: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 24 84 80 .............$..
| 4032: 80 80 80 01 03 00 4e 00 10 00 1e 06 30 61 62 61 ......N.....0aba
| 4048: 63 6c 01 02 02 04 02 66 74 02 5f 02 04 04 6e 64 cl.....ft._...nd
| 4064: 6f 6e 02 02 02 04 0a 07 05 01 03 00 10 03 03 0f on..............
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 11 ...$............
| page 3 offset 8192
| 0: 0a 00 00 00 01 0f 00 01 00 00 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 03 0f e0 00 0f f6 0f ec 0f e0 00 00 ................
| 4064: 0a 03 03 00 1b 61 62 61 6e 64 6f 6e 08 02 03 00 .....abandon....
| 4080: 17 61 62 61 66 74 08 01 03 00 17 61 62 61 63 6b .abaft.....aback
| page 5 offset 16384
| 0: 0d 00 00 00 03 0f ee 00 0f fa 0f 00 00 00 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 03 ................
| 4080: 03 00 0e 01 04 02 03 00 0e 01 04 01 03 00 0e 01 ................
| 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 10 03 0f d6 00 0f 00 00 00 00 00 00 00 ................
| 4048: 00 00 00 00 00 00 09 03 02 1b 72 65 62 75 69 6c ..........rebuil
| 4064: 64 11 02 02 2b 69 6e 74 65 67 72 69 74 79 2d 63 d...+integrity-c
| 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 00 00 00 heck....optim...
| page 8 offset 28672
| 0: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| end crash-42fa37b694d45a.db
}]} {}
do_execsql_test 6.1 {
INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
}
do_catchsql_test 6.2 {
UPDATE t1 SET content=randomblob(500) WHERE t1;
} {1 {constraint failed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
-76
View File
@@ -1,76 +0,0 @@
# 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 fts5faultG
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a);
INSERT INTO t1 VALUES('test renaming the table');
INSERT INTO t1 VALUES(' after it has been written');
INSERT INTO t1 VALUES(' actually other stuff instead');
}
faultsim_save_and_close
do_faultsim_test 1 -faults oom* -prep {
faultsim_restore_and_reopen
execsql {
BEGIN;
DELETE FROM t1 WHERE rowid=2;
}
} -body {
execsql {
DELETE FROM t1;
}
} -test {
catchsql { COMMIT }
faultsim_integrity_check
faultsim_test_result {0 {}}
}
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, content=, contentless_delete=1);
BEGIN;
INSERT INTO t1 VALUES('here''s some text');
INSERT INTO t1 VALUES('useful stuff, text');
INSERT INTO t1 VALUES('what would we do without text!');
COMMIT;
}
faultsim_save_and_close
do_faultsim_test 2 -faults oom* -prep {
faultsim_restore_and_reopen
execsql {
BEGIN;
DELETE FROM t1 WHERE rowid=2;
}
} -body {
execsql {
INSERT INTO t1(t1) VALUES('optimize');
}
} -test {
faultsim_integrity_check
faultsim_test_result {0 {}}
}
finish_test
-38
View File
@@ -77,9 +77,6 @@ do_catchsql_test 4.2 {
UPDATE aa_docsize SET sz = X'44' WHERE rowid = 3;
INSERT INTO aa(aa) VALUES('integrity-check');
} {1 {database disk image is malformed}}
do_execsql_test 4.2.1 {
PRAGMA integrity_check(aa);
} {{malformed inverted index for FTS5 table main.aa}}
do_catchsql_test 4.3 {
ROLLBACK;
@@ -320,39 +317,4 @@ do_catchsql_test 10.5.3 {
INSERT INTO vt0(vt0) VALUES('integrity-check');
} {0 {}}
reset_db
proc slang {in} {return [string map {th d e eh} $in]}
db function slang -deterministic -innocuous slang
do_execsql_test 11.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT AS (slang(b)));
INSERT INTO t1(b) VALUES('the quick fox jumps over the lazy brown dog');
SELECT c FROM t1;
} {{deh quick fox jumps ovehr deh lazy brown dog}}
do_execsql_test 11.1 {
CREATE VIRTUAL TABLE t2 USING fts5(content="t1", c);
INSERT INTO t2(t2) VALUES('rebuild');
SELECT rowid FROM t2 WHERE t2 MATCH 'deh';
} {1}
do_execsql_test 11.2 {
PRAGMA integrity_check(t2);
} {ok}
db close
sqlite3 db test.db
# FIX ME?
#
# FTS5 integrity-check does not care if the content table is unreadable or
# does not exist. It only looks for internal inconsistencies in the
# inverted index.
#
do_execsql_test 11.3 {
PRAGMA integrity_check(t2);
} {ok}
do_execsql_test 11.4 {
DROP TABLE t1;
PRAGMA integrity_check(t2);
} {ok}
finish_test
+1 -5
View File
@@ -424,12 +424,10 @@ do_execsql_test -db db2 15.3 {
SAVEPOINT one;
} {}
do_execsql_test 15.4 END
do_test 15.5 {
do_test 15.4 {
list [catch { db2 eval COMMIT } msg] $msg
} {0 {}}
db2 close
#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
@@ -471,8 +469,6 @@ do_execsql_test -db db2 16.6 {
SELECT * FROM x1
} {abc def}
db2 close
#-------------------------------------------------------------------------
reset_db
do_execsql_test 17.1 {
+20 -1
View File
@@ -9,7 +9,7 @@
#
#***********************************************************************
#
# TESTRUNNER: superslow
# TESTRUNNER: slow
#
source [file join [file dirname [info script]] fts5_common.tcl]
@@ -42,4 +42,23 @@ do_execsql_test 1.2 {
SELECT count(*) FROM t1('mno')
} $nLoop
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t2 USING fts5(x);
INSERT INTO t2(t2, rank) VALUES('pgsz', 32);
}
do_test 2.1 {
for {set ii 0} {$ii < $nLoop} {incr ii} {
execsql {
INSERT INTO t2 VALUES('abc def ghi');
INSERT INTO t2 VALUES('jkl mno pqr');
INSERT INTO t2(t2, rank) VALUES('merge', -1);
}
}
} {}
do_execsql_test 2.2 {
SELECT count(*) FROM t2('mno')
} $nLoop
finish_test
-45
View File
@@ -1,45 +0,0 @@
# 2023 Aug 27
#
# 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.
#
#***********************************************************************
#
# TESTRUNNER: superslow
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5optimize2
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
set nLoop 2500
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t2 USING fts5(x);
INSERT INTO t2(t2, rank) VALUES('pgsz', 32);
}
do_test 1.1 {
for {set ii 0} {$ii < $nLoop} {incr ii} {
execsql {
INSERT INTO t2 VALUES('abc def ghi');
INSERT INTO t2 VALUES('jkl mno pqr');
INSERT INTO t2(t2, rank) VALUES('merge', -1);
}
}
} {}
do_execsql_test 1.2 {
SELECT count(*) FROM t2('mno')
} $nLoop
finish_test
-30
View File
@@ -52,36 +52,6 @@ do_execsql_test 2.1 {
SELECT * FROM t2('to*');
} {top to tommy}
#-------------------------------------------------------------------------
foreach {tn newrowid} {
1 122
2 123
3 124
} {
reset_db
do_execsql_test 3.$tn.0 {
CREATE VIRTUAL TABLE t12 USING fts5(x);
INSERT INTO t12(rowid, x) VALUES(123, 'wwww');
}
do_execsql_test 3.$tn.1 {
BEGIN;
DELETE FROM t12 WHERE rowid=123;
SELECT * FROM t12('wwww*');
INSERT INTO t12(rowid, x) VALUES($newrowid, 'wwww');
SELECT * FROM t12('wwww*');
END;
} {wwww}
do_execsql_test 3.$tn.2 {
INSERT INTO t12(t12) VALUES('integrity-check');
}
do_execsql_test 3.$tn.3 {
SELECT rowid FROM t12('wwww*');
} $newrowid
}
finish_test
finish_test
+1 -1
View File
@@ -71,7 +71,7 @@ ifcapable fts3 {
do_catchsql_test 3.2 {
DROP TABLE vt1;
} {0 {}}
} {1 {SQL logic error}}
do_execsql_test 3.3 {
SAVEPOINT x;
+1 -58
View File
@@ -274,9 +274,8 @@ do_execsql_test 5.4 { SELECT rowid FROM t1('abc'); } 2
do_execsql_test 5.5 { SELECT rowid FROM t1('aa'); } 2
#-------------------------------------------------------------------------
# Tests for the bug fixed by https://sqlite.org/src/info/4b60a1c3
#
reset_db
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE fts USING fts5(content);
INSERT INTO fts(fts, rank) VALUES ('secure-delete', 1);
@@ -286,62 +285,6 @@ do_execsql_test 6.0 {
INSERT INTO fts(fts) VALUES ('integrity-check');
}
foreach {tn detail} {
1 full
2 column
3 none
} {
do_execsql_test 6.1.$detail "
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts5(x, detail=$detail);
"
do_execsql_test 6.2.$detail {
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
}
for {set ii 1} {$ii < 100} {incr ii} {
do_execsql_test 6.3.$detail.$ii.1 {
BEGIN;
INSERT INTO t1(rowid, x) VALUES(10, 'word1');
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<CAST($ii AS integer)
)
INSERT INTO t1(x) SELECT 'word3' FROM s;
COMMIT;
INSERT INTO t1(t1) VALUES('optimize');
}
do_execsql_test 6.3.$detail.$ii.2 {
DELETE FROM t1 WHERE rowid=10;
INSERT INTO t1(t1) VALUES ('integrity-check');
}
do_execsql_test 6.3.$detail.$ii.3 {
DELETE FROM t1;
}
do_execsql_test 6.3.$detail.$ii.4 {
BEGIN;
INSERT INTO t1(rowid, x) VALUES(10, 'tokenA');
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<CAST($ii AS integer)
)
INSERT INTO t1(x) SELECT group_concat('tokenB ') FROM s;
COMMIT;
INSERT INTO t1(t1) VALUES('optimize');
}
do_execsql_test 6.3.$detail.$ii.5 {
DELETE FROM t1 WHERE rowid=10;
INSERT INTO t1(t1) VALUES ('integrity-check');
}
do_execsql_test 6.3.$detail.$ii.6 {
DELETE FROM t1;
}
}
}
finish_test
+1 -68
View File
@@ -18,7 +18,7 @@ db progress 1 progress_handler
set ::PHC 0
proc progress_handler {args} {
incr ::PHC
# if {($::PHC % 100000)==0} breakpoint
if {($::PHC % 100000)==0} breakpoint
return 0
}
@@ -70,72 +70,5 @@ do_execsql_test 2.2 {
SELECT rowid FROM t1('def')
} {-100000 -99999 9223372036854775800}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
INSERT INTO t1(t1, rank) VALUES('secure-delete', $sd)
}
do_execsql_test 3.1 {
BEGIN;
INSERT INTO t1(rowid, x)
VALUES(51869, 'when whenever where weress what turn'),
(51871, 'to were');
COMMIT;
}
do_execsql_test 3.2 {
DELETE FROM t1 WHERE rowid=51871;
INSERT INTO t1(t1) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
INSERT INTO t1(rowid, x) VALUES(10, 'one two');
}
do_execsql_test 4.1 {
UPDATE t1 SET x = 'one three' WHERE rowid=10;
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
}
do_execsql_test 4.2 {
DELETE FROM t1 WHERE rowid=10;
}
do_execsql_test 4.3 {
INSERT INTO t1(t1) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
CREATE VIRTUAL TABLE t1 USING fts5(content);
INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
INSERT INTO t1 VALUES('active'),('boomer'),('atom'),('atomic'),
('alpha channel backup abandon test aback boomer atom alpha active');
DELETE FROM t1 WHERE t1 MATCH 'abandon';
}
do_execsql_test 5.1 {
INSERT INTO t1(t1) VALUES('rebuild');
}
do_execsql_test 5.2 {
DELETE FROM t1 WHERE rowid NOTNULL<5;
}
db close
sqlite3 db test.db
do_execsql_test 5.3 {
PRAGMA integrity_check;
} {ok}
finish_test
-116
View File
@@ -1,116 +0,0 @@
# 2023 Feb 17
#
# 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.
#
#*************************************************************************
#
# TESTRUNNER: slow
#
source [file join [file dirname [info script]] fts5_common.tcl]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5secure7
set NVOCAB 500
set NDOC [expr 1000]
set NREP 100
set nDeletePerRep [expr 5]
set VOCAB [list]
proc select_one {list} {
set n [llength $list]
lindex $list [expr {abs(int(rand()*$n))}]
}
proc init_vocab {} {
set L [split "abcdefghijklmnopqrstuvwxyz" {}]
set nL [llength $L]
for {set i 0} {$i < $::NVOCAB} {incr i} {
set n [expr {6 + int(rand()*8)}]
set word ""
for {set j 0} {$j < $n} {incr j} {
append word [select_one $L]
}
lappend ::VOCAB $word
}
}
proc get_word {} {
select_one $::VOCAB
}
proc get_document {nWord} {
set ret [list]
for {set i 0} {$i < $nWord} {incr i} {
lappend ret [get_word]
}
return $ret
}
init_vocab
db func document [list get_document 12]
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(body);
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
}
do_execsql_test 1.1 {
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$NDOC
)
INSERT INTO t1 SELECT document() FROM s;
}
for {set iRep 0} {$iRep < $NREP} {incr iRep} {
set lRowid [db eval {SELECT rowid FROM t1}]
for {set iDel 0} {$iDel < $nDeletePerRep} {incr iDel} {
set idx [select_one $lRowid]
db eval {
DELETE FROM t1 WHERE rowid=$idx
}
}
db eval {
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$nDeletePerRep
)
INSERT INTO t1 SELECT document() FROM s;
}
do_execsql_test 1.2.$iRep {
INSERT INTO t1(t1) VALUES('integrity-check');
}
}
reset_db
db func document [list get_document 12]
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(body);
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
INSERT INTO t1(t1, rank) VALUES('pgsz', 128);
}
do_execsql_test 2.1 {
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$NDOC
)
INSERT INTO t1 SELECT document() FROM s;
}
for {set ii 0} {$ii < $NDOC} {incr ii} {
set lRowid [db eval {SELECT rowid FROM t1}]
set idx [select_one $lRowid]
db eval { DELETE FROM t1 WHERE rowid=$idx }
do_execsql_test 2.2.$ii {
INSERT INTO t1(t1) VALUES('integrity-check');
}
}
finish_test
-51
View File
@@ -1,51 +0,0 @@
# 2023 Nov 23
#
# 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]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5secure8
proc sql_repeat {txt n} {
string repeat $txt $n
}
db func repeat sql_repeat
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE ft USING fts5(x);
INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
INSERT INTO ft(rowid, x) VALUES(100, 'hello world');
INSERT INTO ft(rowid, x) VALUES(200, 'one day');
BEGIN;
INSERT INTO ft(rowid, x) VALUES(45, 'one two three');
UPDATE ft SET x = repeat('hello world ', 500) WHERE rowid=100;
COMMIT
}
do_execsql_test 1.1 {
INSERT INTO ft(ft, rank) VALUES('secure-delete', 1);
DELETE FROM ft WHERE rowid=100;
}
do_execsql_test 1.2 {
PRAGMA integrity_check;
} {ok}
finish_test
-89
View File
@@ -1,89 +0,0 @@
# 2023 Nov 03
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests focusing on the built-in fts5 tokenizers.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5tokenizer2
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
sqlite3_fts5_create_tokenizer db tst get_tst_tokenizer
proc get_tst_tokenizer {args} {
return "tst_tokenizer"
}
proc tst_tokenizer {flags txt} {
set token ""
set lTok [list]
foreach c [split $txt {}] {
if {$token==""} {
append token $c
} else {
set t1 [string is upper $token]
set t2 [string is upper $c]
if {$t1!=$t2} {
lappend lTok $token
set token ""
}
append token $c
}
}
if {$token!=""} { lappend lTok $token }
set iOff 0
foreach t $lTok {
set n [string length $t]
sqlite3_fts5_token $t $iOff [expr $iOff+$n]
incr iOff $n
}
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(t, tokenize=tst);
}
do_execsql_test 1.1 {
INSERT INTO t1 VALUES('AAdontBBmess');
}
do_execsql_test 1.2 {
SELECT snippet(t1, 0, '>', '<', '...', 4) FROM t1('BB');
} {AAdont>BB<mess}
do_execsql_test 1.3 {
SELECT highlight(t1, 0, '>', '<') FROM t1('BB');
} {AAdont>BB<mess}
do_execsql_test 1.4 {
SELECT highlight(t1, 0, '>', '<') FROM t1('AA');
} {>AA<dontBBmess}
do_execsql_test 1.5 {
SELECT highlight(t1, 0, '>', '<') FROM t1('dont');
} {AA>dont<BBmess}
do_execsql_test 1.6 {
SELECT highlight(t1, 0, '>', '<') FROM t1('mess');
} {AAdontBB>mess<}
do_execsql_test 1.7 {
SELECT highlight(t1, 0, '>', '<') FROM t1('BB mess');
} {AAdont>BBmess<}
finish_test
-38
View File
@@ -215,42 +215,4 @@ do_execsql_test 7.2 {
SELECT rowid FROM f WHERE filename GLOB '*ир*';
} {20}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 8.0 {
CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize=trigram);
INSERT INTO t1 VALUES('abcdefghijklm');
}
foreach {tn match res} {
1 "abc ghi" "(abc)def(ghi)jklm"
2 "def ghi" "abc(defghi)jklm"
3 "efg ghi" "abcd(efghi)jklm"
4 "efghi" "abcd(efghi)jklm"
5 "abcd jklm" "(abcd)efghi(jklm)"
6 "ijkl jklm" "abcdefgh(ijklm)"
7 "ijk ijkl hijk" "abcdefg(hijkl)m"
} {
do_execsql_test 8.1.$tn {
SELECT highlight(t1, 0, '(', ')') FROM t1($match)
} $res
}
do_execsql_test 8.2 {
CREATE VIRTUAL TABLE ft2 USING fts5(a, tokenize="trigram");
INSERT INTO ft2 VALUES('abc x cde');
INSERT INTO ft2 VALUES('abc cde');
INSERT INTO ft2 VALUES('abcde');
}
do_execsql_test 8.3 {
SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'abc AND cde';
} {
{[abc] x [cde]}
{[abc] [cde]}
{[abcde]}
}
finish_test
-109
View File
@@ -1,109 +0,0 @@
# 2023 October 24
#
# 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 the fts5 "trigram" tokenizer.
#
source [file join [file dirname [info script]] fts5_common.tcl]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5trigram2
do_execsql_test 1.0 "
CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize='trigram remove_diacritics 1');
INSERT INTO t1 VALUES('abc\u0303defghijklm');
INSERT INTO t1 VALUES('a\u0303b\u0303c\u0303defghijklm');
"
do_execsql_test 1.1 {
SELECT highlight(t1, 0, '(', ')') FROM t1('abc');
} [list \
"(abc\u0303)defghijklm" \
"(a\u0303b\u0303c\u0303)defghijklm" \
]
do_execsql_test 1.2 {
SELECT highlight(t1, 0, '(', ')') FROM t1('bcde');
} [list \
"a(bc\u0303de)fghijklm" \
"a\u0303(b\u0303c\u0303de)fghijklm" \
]
do_execsql_test 1.3 {
SELECT highlight(t1, 0, '(', ')') FROM t1('cdef');
} [list \
"ab(c\u0303def)ghijklm" \
"a\u0303b\u0303(c\u0303def)ghijklm" \
]
do_execsql_test 1.4 {
SELECT highlight(t1, 0, '(', ')') FROM t1('def');
} [list \
"abc\u0303(def)ghijklm" \
"a\u0303b\u0303c\u0303(def)ghijklm" \
]
#-------------------------------------------------------------------------
do_catchsql_test 2.0 {
CREATE VIRTUAL TABLE t2 USING fts5(
z, tokenize='trigram case_sensitive 1 remove_diacritics 1'
);
} {1 {error in tokenizer constructor}}
do_execsql_test 2.1 {
CREATE VIRTUAL TABLE t2 USING fts5(
z, tokenize='trigram case_sensitive 0 remove_diacritics 1'
);
}
do_execsql_test 2.2 "
INSERT INTO t2 VALUES('\u00E3bcdef');
INSERT INTO t2 VALUES('b\u00E3cdef');
INSERT INTO t2 VALUES('bc\u00E3def');
INSERT INTO t2 VALUES('bcd\u00E3ef');
"
do_execsql_test 2.3 {
SELECT highlight(t2, 0, '(', ')') FROM t2('abc');
} "(\u00E3bc)def"
do_execsql_test 2.4 {
SELECT highlight(t2, 0, '(', ')') FROM t2('bac');
} "(b\u00E3c)def"
do_execsql_test 2.5 {
SELECT highlight(t2, 0, '(', ')') FROM t2('bca');
} "(bc\u00E3)def"
do_execsql_test 2.6 "
SELECT highlight(t2, 0, '(', ')') FROM t2('\u00E3bc');
" "(\u00E3bc)def"
#-------------------------------------------------------------------------
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t3 USING fts5(
z, tokenize='trigram remove_diacritics 1'
);
} {}
do_execsql_test 3.1 "
INSERT INTO t3 VALUES ('\u0303abc\u0303');
"
do_execsql_test 3.2 {
SELECT highlight(t3, 0, '(', ')') FROM t3('abc');
} "\u0303(abc\u0303)"
#-------------------------------------------------------------------------
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t4 USING fts5(z, tokenize=trigram);
} {}
breakpoint
do_execsql_test 4.1 {
INSERT INTO t4 VALUES('ABCD');
} {}
finish_test
+103 -262
View File
@@ -6,10 +6,9 @@ JAVA_HOME ?= $(HOME)/jdk/current
# e.g. /usr/lib/jvm/default-javajava-19-openjdk-amd64
JDK_HOME ?= $(JAVA_HOME)
# ^^^ JDK_HOME is not as widely used as JAVA_HOME
bin.jar := $(JDK_HOME)/bin/jar
bin.java := $(JDK_HOME)/bin/java
bin.javac := $(JDK_HOME)/bin/javac
bin.javadoc := $(JDK_HOME)/bin/javadoc
bin.javac := $(JDK_HOME)/bin/javac
bin.java := $(JDK_HOME)/bin/java
bin.jar := $(JDK_HOME)/bin/jar
ifeq (,$(wildcard $(JDK_HOME)))
$(error set JDK_HOME to the top-most dir of your JDK installation.)
endif
@@ -18,29 +17,18 @@ $(MAKEFILE):
package.jar := sqlite3-jni.jar
dir.top := ../..
dir.tool := ../../tool
dir.jni := $(patsubst %/,%,$(dir $(MAKEFILE)))
dir.top := ../..
dir.tool := ../../tool
dir.jni := $(patsubst %/,%,$(dir $(MAKEFILE)))
dir.src := $(dir.jni)/src
dir.src.c := $(dir.src)/c
dir.bld := $(dir.jni)/bld
dir.bld.c := $(dir.bld)
dir.src.jni := $(dir.src)/org/sqlite/jni
dir.src.capi := $(dir.src.jni)/capi
dir.src.fts5 := $(dir.src.jni)/fts5
dir.tests := $(dir.src)/tests
mkdir ?= mkdir -p
dir.src.jni.tester := $(dir.src.jni)/tester
$(dir.bld.c):
$(mkdir) $@
javac.flags ?= -Xlint:unchecked -Xlint:deprecation
java.flags ?=
javac.flags += -encoding utf8
# -------------^^^^^^^^^^^^^^ required for Windows builds
jnicheck ?= 1
ifeq (1,$(jnicheck))
java.flags += -Xcheck:jni
endif
mkdir -p $@
classpath := $(dir.src)
CLEAN_FILES := $(package.jar)
@@ -48,28 +36,17 @@ DISTCLEAN_FILES := $(dir.jni)/*~ $(dir.src.c)/*~ $(dir.src.jni)/*~
sqlite3-jni.h := $(dir.src.c)/sqlite3-jni.h
.NOTPARALLEL: $(sqlite3-jni.h)
CApi.java := $(dir.src.capi)/CApi.java
SQLTester.java := $(dir.src.capi)/SQLTester.java
CApi.class := $(CApi.java:.java=.class)
SQLite3Jni.java := src/org/sqlite/jni/SQLite3Jni.java
SQLTester.java := src/org/sqlite/jni/tester/SQLTester.java
SQLite3Jni.class := $(SQLite3Jni.java:.java=.class)
SQLTester.class := $(SQLTester.java:.java=.class)
########################################################################
# The future of FTS5 customization in this API is as yet unclear.
# The pieces are all in place, and are all thin proxies so not much
# complexity, but some semantic changes were required in porting
# which are largely untested.
#
# Reminder: this flag influences the contents of $(sqlite3-jni.h),
# which is checked in. Please do not check in changes to that file in
# which the fts5 APIs have been stripped unless that feature is
# intended to be stripped for good.
# It would be a real doozy to bind to JNI.
enable.fts5 ?= 1
ifeq (,$(wildcard $(dir.tests)/*))
enable.tester := 0
else
enable.tester := 1
endif
# If enable.tester is 0, the org/sqlite/jni/tester/* bits are elided.
enable.tester ?= 1
# bin.version-info = binary to output various sqlite3 version info
# building the distribution zip file.
@@ -80,99 +57,68 @@ $(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
# Be explicit about which Java files to compile so that we can work on
# in-progress files without requiring them to be in a compilable statae.
JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
Experimental.java \
NotNull.java \
Nullable.java \
) $(patsubst %,$(dir.src.capi)/%,\
AbstractCollationCallback.java \
AggregateFunction.java \
AuthorizerCallback.java \
AutoExtensionCallback.java \
BusyHandlerCallback.java \
CollationCallback.java \
CollationNeededCallback.java \
CommitHookCallback.java \
ConfigLogCallback.java \
ConfigSqlLogCallback.java \
JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\
BusyHandler.java \
Collation.java \
CollationNeeded.java \
CommitHook.java \
NativePointerHolder.java \
OutputPointer.java \
PrepareMultiCallback.java \
PreupdateHookCallback.java \
ProgressHandlerCallback.java \
ProgressHandler.java \
ResultCode.java \
RollbackHookCallback.java \
ScalarFunction.java \
RollbackHook.java \
SQLFunction.java \
CallbackProxy.java \
CApi.java \
TableColumnMetadata.java \
TraceV2Callback.java \
UpdateHookCallback.java \
ValueHolder.java \
WindowFunction.java \
XDestroyCallback.java \
sqlite3.java \
sqlite3_blob.java \
sqlite3_context.java \
sqlite3.java \
SQLite3Jni.java \
sqlite3_stmt.java \
sqlite3_value.java \
) $(patsubst %,$(dir.src.jni)/wrapper1/%,\
AggregateFunction.java \
ScalarFunction.java \
SqlFunction.java \
Sqlite.java \
SqliteException.java \
Tester1.java \
Tracer.java \
UpdateHook.java \
ValueHolder.java \
WindowFunction.java \
)
JAVA_FILES.unittest := $(patsubst %,$(dir.src.jni)/%,\
capi/Tester1.java \
wrapper1/Tester2.java \
)
ifeq (1,$(enable.fts5))
JAVA_FILES.unittest += $(patsubst %,$(dir.src.fts5)/%,\
TesterFts5.java \
)
JAVA_FILES.main += $(patsubst %,$(dir.src.fts5)/%,\
JAVA_FILES.main += $(patsubst %,$(dir.src.jni)/%,\
fts5_api.java \
fts5_extension_function.java \
fts5_tokenizer.java \
Fts5.java \
Fts5Context.java \
Fts5ExtensionApi.java \
Fts5Function.java \
Fts5PhraseIter.java \
Fts5Tokenizer.java \
XTokenizeCallback.java \
TesterFts5.java \
)
endif
JAVA_FILES.tester := $(SQLTester.java)
JAVA_FILES.package.info := \
$(dir.src.jni)/package-info.java \
$(dir.src.jni)/annotation/package-info.java
JAVA_FILES.tester := $(dir.src.jni.tester)/SQLTester.java
CLASS_FILES.main := $(JAVA_FILES.main:.java=.class)
CLASS_FILES.unittest := $(JAVA_FILES.unittest:.java=.class)
CLASS_FILES.tester := $(JAVA_FILES.tester:.java=.class)
JAVA_FILES += $(JAVA_FILES.main) $(JAVA_FILES.unittest)
JAVA_FILES += $(JAVA_FILES.main)
ifeq (1,$(enable.tester))
JAVA_FILES += $(JAVA_FILES.tester)
endif
CLASS_FILES :=
define CLASSFILE_DEPS
define DOTCLASS_DEPS
$(1).class: $(1).java $(MAKEFILE)
all: $(1).class
$(1).class: $(1).java
CLASS_FILES += $(1).class
endef
$(foreach B,$(basename \
$(JAVA_FILES.main) $(JAVA_FILES.unittest) $(JAVA_FILES.tester)),\
$(eval $(call CLASSFILE_DEPS,$(B))))
$(CLASS_FILES): $(MAKEFILE)
$(foreach B,$(basename $(JAVA_FILES)),$(eval $(call DOTCLASS_DEPS,$(B))))
$(CLASS_FILES.tester): $(CLASS_FILES.main)
javac.flags ?= -Xlint:unchecked -Xlint:deprecation
java.flags ?=
jnicheck ?= 1
ifeq (1,$(jnicheck))
java.flags += -Xcheck:jni
endif
$(SQLite3Jni.class): $(JAVA_FILES)
$(bin.javac) $(javac.flags) -h $(dir.bld.c) -cp $(classpath) $(JAVA_FILES)
all: $(SQLite3Jni.class)
#.PHONY: classfiles
########################################################################
@@ -206,41 +152,27 @@ $(sqlite3.h):
$(MAKE) -C $(dir.top) sqlite3.c
$(sqlite3.c): $(sqlite3.h)
opt.threadsafe ?= 1
opt.fatal-oom ?= 1
opt.debug ?= 1
opt.metrics ?= 1
SQLITE_OPT = \
-DSQLITE_THREADSAFE=$(opt.threadsafe) \
-DSQLITE_TEMP_STORE=2 \
-DSQLITE_USE_URI=1 \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_OMIT_DEPRECATED \
-DSQLITE_OMIT_SHARED_CACHE \
-DSQLITE_C=$(sqlite3.c) \
-DSQLITE_JNI_FATAL_OOM=$(opt.fatal-oom) \
-DSQLITE_JNI_ENABLE_METRICS=$(opt.metrics)
opt.extras ?= 1
ifeq (1,$(opt.extras))
SQLITE_OPT += -DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_BYTECODE_VTAB \
-DSQLITE_ENABLE_OFFSET_SQL_FUNC \
-DSQLITE_ENABLE_PREUPDATE_HOOK \
-DSQLITE_ENABLE_NORMALIZE \
-DSQLITE_ENABLE_SQLLOG \
-DSQLITE_ENABLE_COLUMN_METADATA
endif
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_OMIT_DEPRECATED \
-DSQLITE_OMIT_SHARED_CACHE \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_TEMP_STORE=2 \
-DSQLITE_USE_URI=1 \
-DSQLITE_C=$(sqlite3.c)
# -DSQLITE_DEBUG
# -DSQLITE_DEBUG is just to work around a -Wall warning
# for a var which gets set in all builds but only read
# via assert().
ifeq (1,$(opt.debug))
SQLITE_OPT += -DSQLITE_DEBUG -g -DDEBUG -UNDEBUG
else
SQLITE_OPT += -Os
endif
SQLITE_OPT += -g -DDEBUG -UNDEBUG
ifeq (1,$(enable.fts5))
SQLITE_OPT += -DSQLITE_ENABLE_FTS5
@@ -249,30 +181,25 @@ endif
sqlite3-jni.c := $(dir.src.c)/sqlite3-jni.c
sqlite3-jni.o := $(dir.bld.c)/sqlite3-jni.o
sqlite3-jni.h := $(dir.src.c)/sqlite3-jni.h
package.dll := $(dir.bld.c)/libsqlite3-jni.so
sqlite3-jni.dll := $(dir.bld.c)/libsqlite3-jni.so
# All javac-generated .h files must be listed in $(sqlite3-jni.h.in):
sqlite3-jni.h.in :=
# $(java.with.jni) lists all Java files which contain JNI decls:
java.with.jni :=
define ADD_JNI_H
sqlite3-jni.h.in += $$(dir.bld.c)/org_sqlite_jni$(3)_$(2).h
java.with.jni += $(1)/$(2).java
$$(dir.bld.c)/org_sqlite_jni$(3)_$(2).h: $(1)/$(2).java
sqlite3-jni.h.in += $$(dir.bld.c)/org_sqlite_jni_$(1).h
$$(dir.bld.c)/org_sqlite_jni_$(1).h: $$(dir.src.jni)/$(1).java
endef
# Invoke ADD_JNI_H once for each Java file which includes JNI
# declarations:
$(eval $(call ADD_JNI_H,$(dir.src.capi),CApi,_capi))
$(eval $(call ADD_JNI_H,$(dir.src.capi),SQLTester,_capi))
$(eval $(call ADD_JNI_H,SQLite3Jni))
ifeq (1,$(enable.fts5))
$(eval $(call ADD_JNI_H,$(dir.src.fts5),Fts5ExtensionApi,_fts5))
$(eval $(call ADD_JNI_H,$(dir.src.fts5),fts5_api,_fts5))
$(eval $(call ADD_JNI_H,$(dir.src.fts5),fts5_tokenizer,_fts5))
$(eval $(call ADD_JNI_H,Fts5ExtensionApi))
$(eval $(call ADD_JNI_H,fts5_api))
$(eval $(call ADD_JNI_H,fts5_tokenizer))
endif
$(sqlite3-jni.h.in): $(dir.bld.c)
#package.dll.cfiles :=
package.dll.cflags = \
-std=c99 \
ifeq (1,$(enable.tester))
sqlite3-jni.h.in += $(dir.bld.c)/org_sqlite_jni_tester_SQLTester.h
$(dir.bld.c)/org_sqlite_jni_tester_SQLTester.h: $(dir.src.jni.tester)/SQLTester.java
endif
#sqlite3-jni.dll.cfiles := $(dir.src.c)
sqlite3-jni.dll.cflags = \
-fPIC \
-I. \
-I$(dir $(sqlite3.h)) \
@@ -280,82 +207,54 @@ package.dll.cflags = \
-I$(JDK_HOME)/include \
$(patsubst %,-I%,$(patsubst %.h,,$(wildcard $(JDK_HOME)/include/*))) \
-Wall
# The gross $(patsubst...) above is to include the platform-specific
# subdir which lives under $(JDK_HOME)/include and is a required
# include path for client-level code.
#
# Using (-Wall -Wextra) triggers an untennable number of
# gcc warnings from sqlite3.c for mundane things like
# unused parameters.
#
# The gross $(patsubst...) above is to include the platform-specific
# subdir which lives under $(JDK_HOME)/include and is a required
# include path for client-level code.
########################################################################
ifeq (1,$(enable.tester))
package.dll.cflags += -DSQLITE_JNI_ENABLE_SQLTester
sqlite3-jni.dll.cflags += -DS3JNI_ENABLE_SQLTester
endif
$(sqlite3-jni.h): $(sqlite3-jni.h.in) $(MAKEFILE)
@cat $(sqlite3-jni.h.in) > $@.tmp
@if cmp $@ $@.tmp >/dev/null; then \
rm -f $@.tmp; \
echo "$@ not modified"; \
else \
mv $@.tmp $@; \
echo "Updated $@"; \
fi
@if [ x1 != x$(enable.fts5) ]; then \
echo "*** REMINDER:"; \
echo "*** enable.fts5=0, so please do not check in changes to $@."; \
fi
$(package.dll): $(sqlite3-jni.h) $(sqlite3.c) $(sqlite3.h)
$(package.dll): $(sqlite3-jni.c) $(MAKEFILE)
$(CC) $(package.dll.cflags) $(SQLITE_OPT) \
cat $(sqlite3-jni.h.in) > $@
$(sqlite3-jni.dll): $(sqlite3-jni.h) $(sqlite3.c) $(sqlite3.h)
$(sqlite3-jni.dll): $(dir.bld.c) $(sqlite3-jni.c) $(SQLite3Jni.java) $(MAKEFILE)
$(CC) $(sqlite3-jni.dll.cflags) $(SQLITE_OPT) \
$(sqlite3-jni.c) -shared -o $@
all: $(package.dll)
all: $(sqlite3-jni.dll)
.PHONY: test test-one
Tester1.flags ?=
Tester2.flags ?=
test.flags.jvm = -ea -Djava.library.path=$(dir.bld.c) \
$(java.flags) -cp $(classpath)
test.deps := $(CLASS_FILES) $(package.dll)
test-one: $(test.deps)
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 $(Tester1.flags)
$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 $(Tester2.flags)
test-sqllog: $(test.deps)
@echo "Testing with -sqllog..."
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 $(Tester1.flags) -sqllog
test-mt: $(test.deps)
@echo "Testing in multi-threaded mode:";
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 \
-t 7 -r 50 -shuffle $(Tester1.flags)
$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 \
-t 7 -r 50 -shuffle $(Tester2.flags)
test: test-one test-mt
tests: test test-sqllog
.PHONY: test
test.flags ?= -v
test: $(SQLite3Jni.class) $(sqlite3-jni.dll)
$(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
$(java.flags) -cp $(classpath) \
org.sqlite.jni.Tester1 $(if $(test.flags),-- $(test.flags),)
tester.scripts := $(sort $(wildcard $(dir.src)/tests/*.test))
tester.flags ?= # --verbose
.PHONY: tester tester-local tester-ext
ifeq (1,$(enable.tester))
tester-local: $(CLASS_FILES.tester) $(package.dll)
tester-local: $(CLASS_FILES.tester) $(sqlite3-jni.dll)
$(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
$(java.flags) -cp $(classpath) \
org.sqlite.jni.capi.SQLTester $(tester.flags) $(tester.scripts)
org.sqlite.jni.tester.SQLTester $(tester.flags) $(tester.scripts)
tester: tester-local
else
tester:
@echo "SQLTester support is disabled."
@echo "SQLTester support is disabled. Build with enable.tester=1 to enable it."
endif
tester.extdir.default := $(dir.tests)/ext
tester.extdir.default := src/tests/ext
tester.extdir ?= $(tester.extdir.default)
tester.extern-scripts := $(wildcard $(tester.extdir)/*.test)
ifneq (,$(tester.extern-scripts))
tester-ext:
$(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
$(java.flags) -cp $(classpath) \
org.sqlite.jni.capi.SQLTester $(tester.flags) $(tester.extern-scripts)
org.sqlite.jni.tester.SQLTester $(tester.flags) $(tester.extern-scripts)
else
tester-ext:
@echo "******************************************************"; \
@@ -368,79 +267,25 @@ endif
tester-ext: tester-local
tester: tester-ext
tests: tester
########################################################################
# Build each SQLITE_THREADMODE variant and run all tests against them.
multitest: clean
define MULTIOPT
multitest: multitest-$(1)
multitest-$(1):
$$(MAKE) opt.debug=$$(opt.debug) $(patsubst %,opt.%,$(2)) \
tests clean enable.fts5=1
endef
$(eval $(call MULTIOPT,01,threadsafe=0 oom=1))
$(eval $(call MULTIOPT,00,threadsafe=0 oom=0))
$(eval $(call MULTIOPT,11,threadsafe=1 oom=1))
$(eval $(call MULTIOPT,10,threadsafe=1 oom=0))
$(eval $(call MULTIOPT,21,threadsafe=2 oom=1))
$(eval $(call MULTIOPT,20,threadsafe=2 oom=0))
########################################################################
# jar bundle...
tests: test tester
package.jar.in := $(abspath $(dir.src)/jar.in)
CLEAN_FILES += $(package.jar.in)
JAVA_FILES.jar := $(JAVA_FILES.main) $(JAVA_FILES.unittest) $(JAVA_FILES.package.info)
CLASS_FILES.jar := $(filter-out %/package-info.class,$(JAVA_FILES.jar:.java=.class))
$(package.jar.in): $(package.dll) $(MAKEFILE)
ls -1 \
$(dir.src.jni)/*/*.java $(dir.src.jni)/*/*.class \
| sed -e 's,^$(dir.src)/,,' | sort > $@
$(package.jar): $(CLASS_FILES.jar) $(MAKEFILE) $(package.jar.in)
@rm -f $(dir.src)/c/*~ $(dir.src.jni)/*~
cd $(dir.src); $(bin.jar) -cfe ../$@ org.sqlite.jni.capi.Tester1 @$(package.jar.in)
$(package.jar.in): $(MAKEFILE) $(CLASS_FILES.main)
cd $(dir.src); ls -1 org/sqlite/jni/*.java org/sqlite/jni/*.class > $@
@ls -la $@
@echo "To use this jar you will need the -Djava.library.path=DIR/CONTAINING/libsqlite3-jni.so flag."
@echo "e.g. java -Djava.library.path=bld -jar $@"
@echo "To use this jar you will need the -Djava.library.path=DIR/WITH/libsqlite3-jni.so flag."
@echo "e.g. java -jar $@ -Djava.library.path=bld"
$(package.jar): $(CLASS_FILES) $(MAKEFILE) $(package.jar.in)
rm -f $(dir.src)/c/*~ $(dir.src.jni)/*~
cd $(dir.src); $(bin.jar) -cfe ../$@ org.sqlite.jni.Tester1 @$(package.jar.in)
jar: $(package.jar)
run-jar: $(package.jar) $(package.dll)
$(bin.java) -Djava.library.path=$(dir.bld) -jar $(package.jar) $(run-jar.flags)
########################################################################
# javadoc...
dir.doc := $(dir.jni)/javadoc
doc.index := $(dir.doc)/index.html
javadoc.exclude := -exclude org.sqlite.jni.fts5
# ^^^^ 2023-09-13: elide the fts5 parts from the public docs for
# the time being, as it's not clear where the Java bindings for
# those bits are going.
# javadoc.exclude += -exclude org.sqlite.jni.capi
# ^^^^ exclude the capi API only for certain builds (TBD)
$(doc.index): $(JAVA_FILES.main) $(MAKEFILE)
@if [ -d $(dir.doc) ]; then rm -fr $(dir.doc)/*; fi
$(bin.javadoc) -cp $(classpath) -d $(dir.doc) -quiet \
-subpackages org.sqlite.jni $(javadoc.exclude)
@echo "javadoc output is in $@"
.PHONY: doc javadoc docserve
.FORCE: doc
doc: $(doc.index)
javadoc: $(doc.index)
# Force rebild of docs
redoc:
@rm -f $(doc.index)
@$(MAKE) doc
docserve: $(doc.index)
cd $(dir.doc) && althttpd -max-age 1 -page index.html
########################################################################
# Clean up...
CLEAN_FILES += $(dir.bld.c)/* \
$(dir.src.jni)/*.class \
$(dir.src.jni)/*/*.class \
$(package.dll) \
$(dir.src.jni.tester)/*.class \
$(sqlite3-jni.dll) \
hs_err_pid*.log
.PHONY: clean distclean
@@ -448,7 +293,7 @@ clean:
-rm -f $(CLEAN_FILES)
distclean: clean
-rm -f $(DISTCLEAN_FILES)
-rm -fr $(dir.bld.c) $(dir.doc)
-rm -fr $(dir.bld.c)
########################################################################
# disttribution bundle rules...
@@ -472,10 +317,6 @@ dist: \
$(bin.version-info) $(sqlite3.canonical.c) \
$(package.jar) $(MAKEFILE)
@echo "Making end-user deliverables..."
@echo "****************************************************************************"; \
echo "*** WARNING: be sure to build this with JDK8 (javac 1.8) for compatibility."; \
echo "*** reasons!"; $$($(bin.javac) -version); \
echo "****************************************************************************"
@rm -fr $(dist-dir.top)
@mkdir -p $(dist-dir.src)
@cp -p $(dist.top.extras) $(dist-dir.top)/.
+52 -134
View File
@@ -15,9 +15,7 @@ Technical support is available in the forum:
> **FOREWARNING:** this subproject is very much in development and
subject to any number of changes. Please do not rely on any
information about its API until this disclaimer is removed. The JNI
bindings released with version 3.43 are a "tech preview." Once
finalized, strong backward compatibility guarantees will apply.
information about its API until this disclaimer is removed.
Project goals/requirements:
@@ -42,43 +40,13 @@ Non-goals:
- Creation of high-level OO wrapper APIs. Clients are free to create
them off of the C-style API.
- Virtual tables are unlikely to be supported due to the amount of
glue code needed to fit them into Java.
- Support for mixed-mode operation, where client code accesses SQLite
both via the Java-side API and the C API via their own native
code. Such cases would be a minefield of potential mis-interactions
between this project's JNI bindings and mixed-mode client code.
Significant TODOs
========================================================================
Hello World
-----------------------------------------------------------------------
```java
import org.sqlite.jni.*;
import static org.sqlite.jni.CApi.*;
...
final sqlite3 db = sqlite3_open(":memory:");
try {
final int rc = sqlite3_errcode(db);
if( 0 != rc ){
if( null != db ){
System.out.print("Error opening db: "+sqlite3_errmsg(db));
}else{
System.out.print("Error opening db: rc="+rc);
}
... handle error ...
}
// ... else use the db ...
}finally{
// ALWAYS close databases using sqlite3_close() or sqlite3_close_v2()
// when done with them. All of their active statement handles must
// first have been passed to sqlite3_finalize().
sqlite3_close_v2(db);
}
```
- The initial beta release with version 3.43 has severe threading
limitations. Namely, two threads cannot call into the JNI-bound API
at once. This limitation will be remove in a subsequent release.
Building
@@ -92,99 +60,55 @@ The canonical builds assumes a Linux-like environment and requires:
Put simply:
```console
```
$ export JAVA_HOME=/path/to/jdk/root
$ make
$ make test
$ make clean
```
The jar distribution can be created with `make jar`, but note that it
does not contain the binary DLL file. A different DLL is needed for
each target platform.
<a id='1to1ish'></a>
One-to-One(-ish) Mapping to C
========================================================================
This JNI binding aims to provide as close to a 1-to-1 experience with
the C API as cross-language semantics allow. Interface changes are
the C API as cross-language semantics allow. Exceptions are
necessarily made where cross-language semantics do not allow a 1-to-1,
and judiciously made where a 1-to-1 mapping would be unduly cumbersome
to use in Java. In all cases, this binding makes every effort to
provide semantics compatible with the C API documentation even if the
interface to those semantics is slightly different. Any cases which
deviate from those semantics (either removing or adding semantics) are
clearly documented.
to use in Java.
Where it makes sense to do so for usability, Java-side overloads are
provided which accept or return data in alternative forms or provide
sensible default argument values. In all such cases they are thin
proxies around the corresponding C APIs and do not introduce new
semantics.
In a few cases, Java-specific capabilities have been added in
new APIs, all of which have "_java" somewhere in their names.
Examples include:
- `sqlite3_result_java_object()`
- `sqlite3_column_java_object()`
- `sqlite3_value_java_object()`
which, as one might surmise, collectively enable the passing of
arbitrary Java objects from user-defined SQL functions through to the
caller.
Golden Rule: Garbage Collection Cannot Free SQLite Resources
Golden Rule: _Never_ Throw from Callbacks
------------------------------------------------------------------------
It is important that all databases and prepared statement handles get
cleaned up by client code. A database cannot be closed if it has open
statement handles. `sqlite3_close()` fails if the db cannot be closed
whereas `sqlite3_close_v2()` recognizes that case and marks the db as
a "zombie," pending finalization when the library detects that all
pending statements have been closed. Be aware that Java garbage
collection _cannot_ close a database or finalize a prepared statement.
Those things require explicit API calls.
JNI bindings which accept client-defined functions _must never throw
exceptions_ unless _very explicitly documented_ as being
throw-safe. Exceptions are generally reserved for higher-level
bindings which are constructed to specifically deal with them and
ensure that they do not leak C-level resources. Some of the JNI
bindings are provided as Java functions which expect this rule to
always hold.
Classes for which it is sensible support Java's `AutoCloseable`
interface so can be used with try-with-resources constructs.
Golden Rule #2: _Never_ Throw from Callbacks (Unless...)
UTF-8(-ish)
------------------------------------------------------------------------
All routines in this API, barring explicitly documented exceptions,
retain C-like semantics. For example, they are not permitted to throw
or propagate exceptions and must return error information (if any) via
result codes or `null`. The only cases where the C-style APIs may
throw is through client-side misuse, e.g. passing in a null where it
may cause a `NullPointerException`. The APIs clearly mark function
parameters which should not be null, but does not generally actively
defend itself against such misuse. Some C-style APIs explicitly accept
`null` as a no-op for usability's sake, and some of the JNI APIs
deliberately return an error code, instead of segfaulting, when passed
a `null`.
SQLite internally uses UTF-8 encoding, whereas Java natively uses
UTF-16. Java JNI has routines for converting to and from UTF-8, _but_
Java uses what its docs call "[modified UTF-8][modutf8]." Care must be
taken when converting Java strings to UTF-8 to ensure that the proper
conversion is performed. In short,
`String.getBytes(StandardCharsets.UTF_8)` performs the proper
conversion in Java, and there is no JNI C API for that conversion
(JNI's `NewStringUTF()` returns MUTF-8).
Client-defined callbacks _must never throw exceptions_ unless _very
explitly documented_ as being throw-safe. Exceptions are generally
reserved for higher-level bindings which are constructed to
specifically deal with them and ensure that they do not leak C-level
resources. In some cases, callback handlers are permitted to throw, in
which cases they get translated to C-level result codes and/or
messages. If a callback which is not permitted to throw throws, its
exception may trigger debug output but will otherwise be suppressed.
Known consequences and limitations of this discrepancy include:
The reason some callbacks are permitted to throw and others not is
because all such callbacks act as proxies for C function callback
interfaces and some of those interfaces have no error-reporting
mechanism. Those which are capable of propagating errors back through
the library convert exceptions from callbacks into corresponding
C-level error information. Those which cannot propagate errors
necessarily suppress any exceptions in order to maintain the C-style
semantics of the APIs.
- Names of databases, tables, and collations must not contain
characters which differ in MUTF-8 and UTF-8, or certain APIs will
mis-translate them on their way between languages. APIs which
transfer other client-side data to Java take extra care to
convert the data at the cost of performance.
[modutf8]: https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8
Unwieldy Constructs are Re-mapped
@@ -202,7 +126,7 @@ A prime example of where interface changes for Java are necessary for
usability is [registration of a custom
collation](https://sqlite.org/c3ref/create_collation.html):
```c
```
// C:
int sqlite3_create_collation(sqlite3 * db, const char * name, int eTextRep,
void *pUserData,
@@ -221,7 +145,7 @@ passed that object as their first argument. That data is passed around
bind that part as-is to Java, the result would be awkward to use (^Yes,
we tried this.):
```java
```
// Java:
int sqlite3_create_collation(sqlite3 db, String name, int eTextRep,
Object pUserData, xCompareType xCompare);
@@ -236,20 +160,20 @@ for callbacks and (B) having their internal state provided separately,
which is ill-fitting in Java. For the sake of usability, C APIs which
follow that pattern use a slightly different Java interface:
```java
```
int sqlite3_create_collation(sqlite3 db, String name, int eTextRep,
SomeCallbackType collation);
Collation collation);
```
Where the `Collation` class has an abstract `call()` method and
Where the `Collation` class has an abstract `xCompare()` method and
no-op `xDestroy()` method which can be overridden if needed, leading to
a much more Java-esque usage:
```java
int rc = sqlite3_create_collation(db, "mycollation", SQLITE_UTF8, new SomeCallbackType(){
```
int rc = sqlite3_create_collation(db, "mycollation", SQLITE_UTF8, new Collation(){
// Required comparison function:
@Override public int call(byte[] lhs, byte[] rhs){ ... }
@Override public int xCompare(byte[] lhs, byte[] rhs){ ... }
// Optional finalizer function:
@Override public void xDestroy(){ ... }
@@ -264,8 +188,8 @@ int rc = sqlite3_create_collation(db, "mycollation", SQLITE_UTF8, new SomeCallba
Noting that:
- It is possible to bind in call-scope-local state via closures, if
desired, as opposed to packing it into the Collation object.
- It is still possible to bind in call-scope-local state via closures,
if desired.
- No capabilities of the C API are lost or unduly obscured via the
above API reshaping, so power users need not make any compromises.
@@ -276,7 +200,6 @@ Noting that:
overriding the `xDestroy()` method effectively gives it v2
semantics.
### User-defined SQL Functions (a.k.a. UDFs)
The [`sqlite3_create_function()`](https://sqlite.org/c3ref/create_function.html)
@@ -284,33 +207,28 @@ family of APIs make heavy use of function pointers to provide
client-defined callbacks, necessitating interface changes in the JNI
binding. The Java API has only one core function-registration function:
```java
```
int sqlite3_create_function(sqlite3 db, String funcName, int nArgs,
int encoding, SQLFunction func);
```
> Design question: does the encoding argument serve any purpose in
Java? That's as-yet undetermined. If not, it will be removed.
> Design question: does the encoding argument serve any purpose in JS?
`SQLFunction` is not used directly, but is instead instantiated via
one of its three subclasses:
- `ScalarFunction` implements simple scalar functions using but a
- `SQLFunction.Scalar` implements simple scalar functions using but a
single callback.
- `AggregateFunction` implements aggregate functions using two
- `SQLFunction.Aggregate` implements aggregate functions using two
callbacks.
- `WindowFunction` implements window functions using four
- `SQLFunction.Window` implements window functions using four
callbacks.
Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/capi/Tester1.java) for
Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/Tester1.java) for
`SQLFunction` for how it's used.
Reminder: see the disclaimer at the top of this document regarding the
in-flux nature of this API.
### And so on...
Various APIs which accept callbacks, e.g. `sqlite3_trace_v2()` and
`sqlite3_update_hook()`, use interfaces similar to those shown above.
Despite the changes in signature, the JNI layer makes every effort to
provide the same semantics as the C API documentation suggests.
[jsrc]: /file/
[www]: https://sqlite.org
+4 -9
View File
@@ -6,9 +6,7 @@
# proper top-level JDK directory and, depending on the platform, add a
# platform-specific -I directory. It should build as-is with any
# 2020s-era version of gcc or clang. It requires JDK version 8 or
# higher and that JAVA_HOME points to the top-most installation
# directory of that JDK. On Ubuntu-style systems the JDK is typically
# installed under /usr/lib/jvm/java-VERSION-PLATFORM.
# higher.
default: all
@@ -33,11 +31,10 @@ SQLITE_OPT = \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_OMIT_DEPRECATED \
-DSQLITE_OMIT_SHARED_CACHE \
-DSQLITE_THREADSAFE=1 \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_TEMP_STORE=2 \
-DSQLITE_USE_URI=1 \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_DEBUG
-DSQLITE_ENABLE_FTS5
sqlite3-jni.dll = libsqlite3-jni.so
$(sqlite3-jni.dll):
@@ -49,10 +46,8 @@ $(sqlite3-jni.dll):
src/sqlite3-jni.c -shared -o $@
@echo "Now try running it with: make test"
test.flags = -Djava.library.path=. sqlite3-jni-*.jar
test: $(sqlite3-jni.dll)
java -jar $(test.flags)
java -jar $(test.flags) -t 7 -r 10 -shuffle
java -jar -Djava.library.path=. sqlite3-jni-*.jar
clean:
-rm -f $(sqlite3-jni.dll)
+2748 -4665
View File
File diff suppressed because it is too large Load Diff
+1825 -2297
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,32 @@
/*
** 2023-08-05
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
A callback for use with sqlite3_set_authorizer().
*/
public interface Authorizer {
/**
Must functions as described for the sqlite3_set_authorizer()
callback, with one caveat: the string values passed here were
initially (at the C level) encoded in standard UTF-8. If they
contained any constructs which are not compatible with MUTF-8,
these strings will not have the expected values. For further
details, see the documentation for the SQLite3Jni class.
Must not throw.
*/
int xAuth(int opId, @Nullable String s1, @Nullable String s2,
@Nullable String s3, @Nullable String s4);
}
@@ -0,0 +1,31 @@
/*
** 2023-08-05
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
A callback for use with sqlite3_auto_extension().
*/
public interface AutoExtension {
/**
Must function as described for the sqlite3_auto_extension(),
with the caveat that the signature is more limited.
As an exception (as it were) to the callbacks-must-not-throw
rule, AutoExtensions may do so and the exception's error message
will be set as the db's error string.
Results are undefined if db is closed by an auto-extension.
*/
int xEntryPoint(sqlite3 db);
}
@@ -0,0 +1,45 @@
/*
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
Callback proxy for use with sqlite3_busy_handler().
*/
public abstract class BusyHandler {
/**
Must function as documented for the sqlite3_busy_handler()
callback argument, minus the (void*) argument the C-level
function requires.
Any exceptions thrown by this callback are suppressed in order to
retain the C-style API semantics of the JNI bindings.
*/
public abstract int xCallback(int n);
/**
Optionally override to perform any cleanup when this busy
handler is destroyed. It is destroyed when:
- The associated db is passed to sqlite3_close() or
sqlite3_close_v2().
- sqlite3_busy_handler() is called to replace the handler,
whether it's passed a null handler or any other instance of
this class.
- sqlite3_busy_timeout() is called, which implicitly installs
a busy handler.
*/
public void xDestroy(){}
}
@@ -1,5 +1,5 @@
/*
** 2023-08-23
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -11,15 +11,18 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
package org.sqlite.jni;
/**
A callback for use with sqlite3_config().
*/
public interface ConfigSqlLogCallback {
public abstract class Collation {
/**
Must function as described for a C-level callback for
{@link CApi#sqlite3_config(ConfigSqlLogCallback)}, with the slight signature change.
Must compare the given byte arrays using memcmp() semantics.
*/
void call(sqlite3 db, String msg, int msgType );
public abstract int xCompare(byte[] lhs, byte[] rhs);
/**
Called by SQLite when the collation is destroyed. If a Collation
requires custom cleanup, override this method.
*/
public void xDestroy() {}
}
@@ -1,5 +1,5 @@
/*
** 2023-08-25
** 2023-07-30
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -11,19 +11,18 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
package org.sqlite.jni;
/**
Callback for use with {@link CApi#sqlite3_collation_needed}.
Callback proxy for use with sqlite3_collation_needed().
*/
public interface CollationNeededCallback extends CallbackProxy {
public interface CollationNeeded {
/**
Has the same semantics as the C-level sqlite3_create_collation()
callback.
<p>Because the C API has no mechanism for reporting errors
from this callbacks, any exceptions thrown by this callback
are suppressed.
If it throws, the exception message is passed on to the db and
the exception is suppressed.
*/
void call(sqlite3 db, int eTextRep, String collationName);
int xCollationNeeded(sqlite3 db, int eTextRep, String collationName);
}
@@ -1,5 +1,5 @@
/*
** 2023-08-04
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -11,12 +11,15 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.fts5;
package org.sqlite.jni;
/**
Callback type for use with xTokenize() variants.
Callback proxy for use with sqlite3_commit_hook().
*/
public interface XTokenizeCallback {
int call(int tFlags, byte[] txt, int iStart, int iEnd);
public interface CommitHook {
/**
Works as documented for the sqlite3_commit_hook() callback.
Must not throw.
*/
int xCommitHook();
}
@@ -11,18 +11,24 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.fts5;
package org.sqlite.jni;
/**
INCOMPLETE AND COMPLETELY UNTESTED.
A utility object for holding FTS5-specific types and constants
which are used by multiple FTS5 classes.
A wrapper for communicating C-level (fts5_api*) instances with
Java. These wrappers do not own their associated pointer, they
simply provide a type-safe way to communicate it between Java and C
via JNI.
*/
public final class Fts5 {
/* Not used */
private Fts5(){}
//! Callback type for use with xTokenize() variants
public static interface xTokenizeCallback {
int xToken(int tFlags, byte txt[], int iStart, int iEnd);
}
public static final int FTS5_TOKENIZE_QUERY = 0x0001;
public static final int FTS5_TOKENIZE_PREFIX = 0x0002;
@@ -11,8 +11,7 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.fts5;
import org.sqlite.jni.capi.*;
package org.sqlite.jni;
/**
A wrapper for communicating C-level (Fts5Context*) instances with
@@ -11,87 +11,76 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.fts5;
package org.sqlite.jni;
import java.nio.charset.StandardCharsets;
import org.sqlite.jni.capi.*;
import org.sqlite.jni.annotation.*;
/**
ALMOST COMPLETELY UNTESTED.
FAR FROM COMPLETE and the feasibility of binding this to Java
is still undetermined. This might be removed.
*/
public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi> {
//! Only called from JNI
private Fts5ExtensionApi(){}
private final int iVersion = 2;
private int iVersion = 2;
/* Callback type for used by xQueryPhrase(). */
public static interface XQueryPhraseCallback {
int call(Fts5ExtensionApi fapi, Fts5Context cx);
public static interface xQueryPhraseCallback {
int xCallback(Fts5ExtensionApi fapi, Fts5Context cx);
}
/**
Returns the singleton instance of this class.
*/
public static native Fts5ExtensionApi getInstance();
public static synchronized native Fts5ExtensionApi getInstance();
public native int xColumnCount(@NotNull Fts5Context fcx);
public native int xColumnSize(@NotNull Fts5Context cx, int iCol,
public synchronized native int xColumnCount(@NotNull Fts5Context fcx);
public synchronized native int xColumnSize(@NotNull Fts5Context cx, int iCol,
@NotNull OutputPointer.Int32 pnToken);
public native int xColumnText(@NotNull Fts5Context cx, int iCol,
public synchronized native int xColumnText(@NotNull Fts5Context cx, int iCol,
@NotNull OutputPointer.String txt);
public native int xColumnTotalSize(@NotNull Fts5Context fcx, int iCol,
public synchronized native int xColumnTotalSize(@NotNull Fts5Context fcx, int iCol,
@NotNull OutputPointer.Int64 pnToken);
public native Object xGetAuxdata(@NotNull Fts5Context cx, boolean clearIt);
public native int xInst(@NotNull Fts5Context cx, int iIdx,
public synchronized native Object xGetAuxdata(@NotNull Fts5Context cx, boolean clearIt);
public synchronized native int xInst(@NotNull Fts5Context cx, int iIdx,
@NotNull OutputPointer.Int32 piPhrase,
@NotNull OutputPointer.Int32 piCol,
@NotNull OutputPointer.Int32 piOff);
public native int xInstCount(@NotNull Fts5Context fcx,
public synchronized native int xInstCount(@NotNull Fts5Context fcx,
@NotNull OutputPointer.Int32 pnInst);
public native int xPhraseCount(@NotNull Fts5Context fcx);
public native int xPhraseFirst(@NotNull Fts5Context cx, int iPhrase,
public synchronized native int xPhraseCount(@NotNull Fts5Context fcx);
public synchronized native int xPhraseFirst(@NotNull Fts5Context cx, int iPhrase,
@NotNull Fts5PhraseIter iter,
@NotNull OutputPointer.Int32 iCol,
@NotNull OutputPointer.Int32 iOff);
public native int xPhraseFirstColumn(@NotNull Fts5Context cx, int iPhrase,
public synchronized native int xPhraseFirstColumn(@NotNull Fts5Context cx, int iPhrase,
@NotNull Fts5PhraseIter iter,
@NotNull OutputPointer.Int32 iCol);
public native void xPhraseNext(@NotNull Fts5Context cx,
public synchronized native void xPhraseNext(@NotNull Fts5Context cx,
@NotNull Fts5PhraseIter iter,
@NotNull OutputPointer.Int32 iCol,
@NotNull OutputPointer.Int32 iOff);
public native void xPhraseNextColumn(@NotNull Fts5Context cx,
public synchronized native void xPhraseNextColumn(@NotNull Fts5Context cx,
@NotNull Fts5PhraseIter iter,
@NotNull OutputPointer.Int32 iCol);
public native int xPhraseSize(@NotNull Fts5Context fcx, int iPhrase);
public native int xQueryPhrase(@NotNull Fts5Context cx, int iPhrase,
@NotNull XQueryPhraseCallback callback);
public native int xRowCount(@NotNull Fts5Context fcx,
public synchronized native int xPhraseSize(@NotNull Fts5Context fcx, int iPhrase);
public synchronized native int xQueryPhrase(@NotNull Fts5Context cx, int iPhrase,
@NotNull xQueryPhraseCallback callback);
public synchronized native int xRowCount(@NotNull Fts5Context fcx,
@NotNull OutputPointer.Int64 nRow);
public native long xRowid(@NotNull Fts5Context cx);
public synchronized native long xRowid(@NotNull Fts5Context cx);
/* Note that the JNI binding lacks the C version's xDelete()
callback argument. Instead, if pAux has an xDestroy() method, it
is called if the FTS5 API finalizes the aux state (including if
allocation of storage for the auxdata fails). Any reference to
pAux held by the JNI layer will be relinquished regardless of
whether pAux has an xDestroy() method. */
public synchronized native int xSetAuxdata(@NotNull Fts5Context cx, @Nullable Object pAux);
public synchronized native int xTokenize(@NotNull Fts5Context cx, @NotNull byte pText[],
@NotNull Fts5.xTokenizeCallback callback);
public native int xSetAuxdata(@NotNull Fts5Context cx, @Nullable Object pAux);
public native int xTokenize(@NotNull Fts5Context cx, @NotNull byte[] pText,
@NotNull XTokenizeCallback callback);
public native Object xUserData(Fts5Context cx);
public synchronized native Object xUserData(Fts5Context cx);
//^^^ returns the pointer passed as the 3rd arg to the C-level
// fts5_api::xCreateFunction().
// fts5_api::xCreateFunction.
}
@@ -0,0 +1,27 @@
/*
** 2023-08-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.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
Fts5Function is used in conjunction with the
sqlite3_create_fts_function() JNI-bound API to give that native code
access to the callback functions needed in order to implement
FTS5 auxiliary functions in Java.
*/
public abstract class Fts5Function {
public abstract void xFunction(Fts5ExtensionApi pApi, Fts5Context pFts,
sqlite3_context pCtx, sqlite3_value argv[]);
public void xDestroy() {}
}
@@ -11,8 +11,7 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.fts5;
import org.sqlite.jni.capi.NativePointerHolder;
package org.sqlite.jni;
/**
A wrapper for C-level Fts5PhraseIter. They are only modified and
@@ -11,8 +11,7 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.fts5;
import org.sqlite.jni.capi.NativePointerHolder;
package org.sqlite.jni;
/**
INCOMPLETE AND COMPLETELY UNTESTED.
@@ -11,7 +11,7 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
package org.sqlite.jni;
/**
A helper for passing pointers between JNI C code and Java, in
@@ -23,24 +23,11 @@ package org.sqlite.jni.capi;
NativePointerHolder is not inadvertently passed to an incompatible
function signature.
These objects do not own the pointer they refer to. They are
These objects do not _own_ the pointer they refer to. They are
intended simply to communicate that pointer between C and Java.
*/
public class NativePointerHolder<ContextType> {
//! Only set from JNI, where access permissions don't matter.
private volatile long nativePointer = 0;
/**
For use ONLY by package-level APIs which act as proxies for
close/finalize operations. Such ops must call this to zero out
the pointer so that this object is not carrying a stale
pointer. This function returns the prior value of the pointer and
sets it to 0.
*/
final long clearNativePointer() {
final long rv = nativePointer;
nativePointer= 0;
return rv;
}
private long nativePointer = 0;
public final long getNativePointer(){ return nativePointer; }
}
@@ -0,0 +1,165 @@
/*
** 2023-07-21
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
Helper classes for handling JNI output pointers.
We do not use a generic OutputPointer<T> because working with those
from the native JNI code is unduly quirky due to a lack of
autoboxing at that level.
The usage is similar for all of thes types:
```
OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
assert( null==out.get() );
int rc = sqlite3_open(":memory:", out);
if( 0!=rc ) ... error;
assert( null!=out.get() );
sqlite3 db = out.take();
assert( null==out.get() );
```
With the minor exception that the primitive types permit direct
access to the object's value via the `value` property, whereas the
JNI-level opaque types do not permit client-level code to set that
property.
*/
public final class OutputPointer {
/**
Output pointer for use with routines, such as sqlite3_open(),
which return a database handle via an output pointer. These
pointers can only be set by the JNI layer, not by client-level
code.
*/
public static final class sqlite3 {
private org.sqlite.jni.sqlite3 value;
//! Initializes with a null value.
public sqlite3(){value = null;}
//! Sets the current value to null.
public void clear(){value = null;}
//! Returns the current value.
public final org.sqlite.jni.sqlite3 get(){return value;}
//! Equivalent to calling get() then clear().
public final org.sqlite.jni.sqlite3 take(){
final org.sqlite.jni.sqlite3 v = value;
value = null;
return v;
}
}
/**
Output pointer for use with routines, such as sqlite3_prepare(),
which return a statement handle via an output pointer. These
pointers can only be set by the JNI layer, not by client-level
code.
*/
public static final class sqlite3_stmt {
private org.sqlite.jni.sqlite3_stmt value;
//! Initializes with a null value.
public sqlite3_stmt(){value = null;}
//! Sets the current value to null.
public void clear(){value = null;}
//! Returns the current value.
public final org.sqlite.jni.sqlite3_stmt get(){return value;}
//! Equivalent to calling get() then clear().
public final org.sqlite.jni.sqlite3_stmt take(){
final org.sqlite.jni.sqlite3_stmt v = value;
value = null;
return v;
}
}
/**
Output pointer for use with native routines which return integers via
output pointers.
*/
public static final class Int32 {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public int value;
//! Initializes with the value 0.
public Int32(){this(0);}
//! Initializes with the value v.
public Int32(int v){value = v;}
//! Returns the current value.
public final int get(){return value;}
//! Sets the current value to v.
public final void set(int v){value = v;}
}
/**
Output pointer for use with native routines which return 64-bit integers
via output pointers.
*/
public static final class Int64 {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public long value;
//! Initializes with the value 0.
public Int64(){this(0);}
//! Initializes with the value v.
public Int64(long v){value = v;}
//! Returns the current value.
public final long get(){return value;}
//! Sets the current value.
public final void set(long v){value = v;}
}
/**
Output pointer for use with native routines which return strings via
output pointers.
*/
public static final class String {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public java.lang.String value;
//! Initializes with a null value.
public String(){this(null);}
//! Initializes with the value v.
public String(java.lang.String v){value = v;}
//! Returns the current value.
public final java.lang.String get(){return value;}
//! Sets the current value.
public final void set(java.lang.String v){value = v;}
}
/**
Output pointer for use with native routines which return byte
arrays via output pointers.
*/
public static final class ByteArray {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public byte[] value;
//! Initializes with the value null.
public ByteArray(){this(null);}
//! Initializes with the value v.
public ByteArray(byte[] v){value = v;}
//! Returns the current value.
public final byte[] get(){return value;}
//! Sets the current value.
public final void set(byte[] v){value = v;}
}
}
@@ -1,5 +1,5 @@
/*
** 2023-08-25
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -11,17 +11,17 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
package org.sqlite.jni;
/**
Callback for use with {@link CApi#sqlite3_progress_handler}.
Callback proxy for use with sqlite3_progress_handler().
*/
public interface ProgressHandlerCallback extends CallbackProxy {
public interface ProgressHandler {
/**
Works as documented for the C-level sqlite3_progress_handler() callback.
Works as documented for the sqlite3_progress_handler() callback.
<p>If it throws, the exception message is passed on to the db and
If it throws, the exception message is passed on to the db and
the exception is suppressed.
*/
int call();
int xCallback();
}
+155
View File
@@ -0,0 +1,155 @@
/*
** 2023-07-21
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
This enum contains all of the core and "extended" result codes used
by the sqlite3 library. It is provided not for use with the C-style
API (with which it won't work) but for higher-level code which may
find it useful to map SQLite result codes to human-readable names.
*/
public enum ResultCode {
SQLITE_OK(SQLite3Jni.SQLITE_OK),
SQLITE_ERROR(SQLite3Jni.SQLITE_ERROR),
SQLITE_INTERNAL(SQLite3Jni.SQLITE_INTERNAL),
SQLITE_PERM(SQLite3Jni.SQLITE_PERM),
SQLITE_ABORT(SQLite3Jni.SQLITE_ABORT),
SQLITE_BUSY(SQLite3Jni.SQLITE_BUSY),
SQLITE_LOCKED(SQLite3Jni.SQLITE_LOCKED),
SQLITE_NOMEM(SQLite3Jni.SQLITE_NOMEM),
SQLITE_READONLY(SQLite3Jni.SQLITE_READONLY),
SQLITE_INTERRUPT(SQLite3Jni.SQLITE_INTERRUPT),
SQLITE_IOERR(SQLite3Jni.SQLITE_IOERR),
SQLITE_CORRUPT(SQLite3Jni.SQLITE_CORRUPT),
SQLITE_NOTFOUND(SQLite3Jni.SQLITE_NOTFOUND),
SQLITE_FULL(SQLite3Jni.SQLITE_FULL),
SQLITE_CANTOPEN(SQLite3Jni.SQLITE_CANTOPEN),
SQLITE_PROTOCOL(SQLite3Jni.SQLITE_PROTOCOL),
SQLITE_EMPTY(SQLite3Jni.SQLITE_EMPTY),
SQLITE_SCHEMA(SQLite3Jni.SQLITE_SCHEMA),
SQLITE_TOOBIG(SQLite3Jni.SQLITE_TOOBIG),
SQLITE_CONSTRAINT(SQLite3Jni.SQLITE_CONSTRAINT),
SQLITE_MISMATCH(SQLite3Jni.SQLITE_MISMATCH),
SQLITE_MISUSE(SQLite3Jni.SQLITE_MISUSE),
SQLITE_NOLFS(SQLite3Jni.SQLITE_NOLFS),
SQLITE_AUTH(SQLite3Jni.SQLITE_AUTH),
SQLITE_FORMAT(SQLite3Jni.SQLITE_FORMAT),
SQLITE_RANGE(SQLite3Jni.SQLITE_RANGE),
SQLITE_NOTADB(SQLite3Jni.SQLITE_NOTADB),
SQLITE_NOTICE(SQLite3Jni.SQLITE_NOTICE),
SQLITE_WARNING(SQLite3Jni.SQLITE_WARNING),
SQLITE_ROW(SQLite3Jni.SQLITE_ROW),
SQLITE_DONE(SQLite3Jni.SQLITE_DONE),
SQLITE_ERROR_MISSING_COLLSEQ(SQLite3Jni.SQLITE_ERROR_MISSING_COLLSEQ),
SQLITE_ERROR_RETRY(SQLite3Jni.SQLITE_ERROR_RETRY),
SQLITE_ERROR_SNAPSHOT(SQLite3Jni.SQLITE_ERROR_SNAPSHOT),
SQLITE_IOERR_READ(SQLite3Jni.SQLITE_IOERR_READ),
SQLITE_IOERR_SHORT_READ(SQLite3Jni.SQLITE_IOERR_SHORT_READ),
SQLITE_IOERR_WRITE(SQLite3Jni.SQLITE_IOERR_WRITE),
SQLITE_IOERR_FSYNC(SQLite3Jni.SQLITE_IOERR_FSYNC),
SQLITE_IOERR_DIR_FSYNC(SQLite3Jni.SQLITE_IOERR_DIR_FSYNC),
SQLITE_IOERR_TRUNCATE(SQLite3Jni.SQLITE_IOERR_TRUNCATE),
SQLITE_IOERR_FSTAT(SQLite3Jni.SQLITE_IOERR_FSTAT),
SQLITE_IOERR_UNLOCK(SQLite3Jni.SQLITE_IOERR_UNLOCK),
SQLITE_IOERR_RDLOCK(SQLite3Jni.SQLITE_IOERR_RDLOCK),
SQLITE_IOERR_DELETE(SQLite3Jni.SQLITE_IOERR_DELETE),
SQLITE_IOERR_BLOCKED(SQLite3Jni.SQLITE_IOERR_BLOCKED),
SQLITE_IOERR_NOMEM(SQLite3Jni.SQLITE_IOERR_NOMEM),
SQLITE_IOERR_ACCESS(SQLite3Jni.SQLITE_IOERR_ACCESS),
SQLITE_IOERR_CHECKRESERVEDLOCK(SQLite3Jni.SQLITE_IOERR_CHECKRESERVEDLOCK),
SQLITE_IOERR_LOCK(SQLite3Jni.SQLITE_IOERR_LOCK),
SQLITE_IOERR_CLOSE(SQLite3Jni.SQLITE_IOERR_CLOSE),
SQLITE_IOERR_DIR_CLOSE(SQLite3Jni.SQLITE_IOERR_DIR_CLOSE),
SQLITE_IOERR_SHMOPEN(SQLite3Jni.SQLITE_IOERR_SHMOPEN),
SQLITE_IOERR_SHMSIZE(SQLite3Jni.SQLITE_IOERR_SHMSIZE),
SQLITE_IOERR_SHMLOCK(SQLite3Jni.SQLITE_IOERR_SHMLOCK),
SQLITE_IOERR_SHMMAP(SQLite3Jni.SQLITE_IOERR_SHMMAP),
SQLITE_IOERR_SEEK(SQLite3Jni.SQLITE_IOERR_SEEK),
SQLITE_IOERR_DELETE_NOENT(SQLite3Jni.SQLITE_IOERR_DELETE_NOENT),
SQLITE_IOERR_MMAP(SQLite3Jni.SQLITE_IOERR_MMAP),
SQLITE_IOERR_GETTEMPPATH(SQLite3Jni.SQLITE_IOERR_GETTEMPPATH),
SQLITE_IOERR_CONVPATH(SQLite3Jni.SQLITE_IOERR_CONVPATH),
SQLITE_IOERR_VNODE(SQLite3Jni.SQLITE_IOERR_VNODE),
SQLITE_IOERR_AUTH(SQLite3Jni.SQLITE_IOERR_AUTH),
SQLITE_IOERR_BEGIN_ATOMIC(SQLite3Jni.SQLITE_IOERR_BEGIN_ATOMIC),
SQLITE_IOERR_COMMIT_ATOMIC(SQLite3Jni.SQLITE_IOERR_COMMIT_ATOMIC),
SQLITE_IOERR_ROLLBACK_ATOMIC(SQLite3Jni.SQLITE_IOERR_ROLLBACK_ATOMIC),
SQLITE_IOERR_DATA(SQLite3Jni.SQLITE_IOERR_DATA),
SQLITE_IOERR_CORRUPTFS(SQLite3Jni.SQLITE_IOERR_CORRUPTFS),
SQLITE_LOCKED_SHAREDCACHE(SQLite3Jni.SQLITE_LOCKED_SHAREDCACHE),
SQLITE_LOCKED_VTAB(SQLite3Jni.SQLITE_LOCKED_VTAB),
SQLITE_BUSY_RECOVERY(SQLite3Jni.SQLITE_BUSY_RECOVERY),
SQLITE_BUSY_SNAPSHOT(SQLite3Jni.SQLITE_BUSY_SNAPSHOT),
SQLITE_BUSY_TIMEOUT(SQLite3Jni.SQLITE_BUSY_TIMEOUT),
SQLITE_CANTOPEN_NOTEMPDIR(SQLite3Jni.SQLITE_CANTOPEN_NOTEMPDIR),
SQLITE_CANTOPEN_ISDIR(SQLite3Jni.SQLITE_CANTOPEN_ISDIR),
SQLITE_CANTOPEN_FULLPATH(SQLite3Jni.SQLITE_CANTOPEN_FULLPATH),
SQLITE_CANTOPEN_CONVPATH(SQLite3Jni.SQLITE_CANTOPEN_CONVPATH),
SQLITE_CANTOPEN_SYMLINK(SQLite3Jni.SQLITE_CANTOPEN_SYMLINK),
SQLITE_CORRUPT_VTAB(SQLite3Jni.SQLITE_CORRUPT_VTAB),
SQLITE_CORRUPT_SEQUENCE(SQLite3Jni.SQLITE_CORRUPT_SEQUENCE),
SQLITE_CORRUPT_INDEX(SQLite3Jni.SQLITE_CORRUPT_INDEX),
SQLITE_READONLY_RECOVERY(SQLite3Jni.SQLITE_READONLY_RECOVERY),
SQLITE_READONLY_CANTLOCK(SQLite3Jni.SQLITE_READONLY_CANTLOCK),
SQLITE_READONLY_ROLLBACK(SQLite3Jni.SQLITE_READONLY_ROLLBACK),
SQLITE_READONLY_DBMOVED(SQLite3Jni.SQLITE_READONLY_DBMOVED),
SQLITE_READONLY_CANTINIT(SQLite3Jni.SQLITE_READONLY_CANTINIT),
SQLITE_READONLY_DIRECTORY(SQLite3Jni.SQLITE_READONLY_DIRECTORY),
SQLITE_ABORT_ROLLBACK(SQLite3Jni.SQLITE_ABORT_ROLLBACK),
SQLITE_CONSTRAINT_CHECK(SQLite3Jni.SQLITE_CONSTRAINT_CHECK),
SQLITE_CONSTRAINT_COMMITHOOK(SQLite3Jni.SQLITE_CONSTRAINT_COMMITHOOK),
SQLITE_CONSTRAINT_FOREIGNKEY(SQLite3Jni.SQLITE_CONSTRAINT_FOREIGNKEY),
SQLITE_CONSTRAINT_FUNCTION(SQLite3Jni.SQLITE_CONSTRAINT_FUNCTION),
SQLITE_CONSTRAINT_NOTNULL(SQLite3Jni.SQLITE_CONSTRAINT_NOTNULL),
SQLITE_CONSTRAINT_PRIMARYKEY(SQLite3Jni.SQLITE_CONSTRAINT_PRIMARYKEY),
SQLITE_CONSTRAINT_TRIGGER(SQLite3Jni.SQLITE_CONSTRAINT_TRIGGER),
SQLITE_CONSTRAINT_UNIQUE(SQLite3Jni.SQLITE_CONSTRAINT_UNIQUE),
SQLITE_CONSTRAINT_VTAB(SQLite3Jni.SQLITE_CONSTRAINT_VTAB),
SQLITE_CONSTRAINT_ROWID(SQLite3Jni.SQLITE_CONSTRAINT_ROWID),
SQLITE_CONSTRAINT_PINNED(SQLite3Jni.SQLITE_CONSTRAINT_PINNED),
SQLITE_CONSTRAINT_DATATYPE(SQLite3Jni.SQLITE_CONSTRAINT_DATATYPE),
SQLITE_NOTICE_RECOVER_WAL(SQLite3Jni.SQLITE_NOTICE_RECOVER_WAL),
SQLITE_NOTICE_RECOVER_ROLLBACK(SQLite3Jni.SQLITE_NOTICE_RECOVER_ROLLBACK),
SQLITE_WARNING_AUTOINDEX(SQLite3Jni.SQLITE_WARNING_AUTOINDEX),
SQLITE_AUTH_USER(SQLite3Jni.SQLITE_AUTH_USER),
SQLITE_OK_LOAD_PERMANENTLY(SQLite3Jni.SQLITE_OK_LOAD_PERMANENTLY);
public final int value;
ResultCode(int rc){
value = rc;
ResultCodeMap.set(rc, this);
}
/**
Returns the entry from this enum for the given result code, or
null if no match is found.
*/
public static ResultCode getEntryForInt(int rc){
return ResultCodeMap.get(rc);
}
/**
Internal level of indirection required because we cannot initialize
static enum members in an enum before the enum constructor is
invoked.
*/
private static final class ResultCodeMap {
private static final java.util.Map<Integer,ResultCode> i2e
= new java.util.HashMap<>();
private static void set(int rc, ResultCode e){ i2e.put(rc, e); }
private static ResultCode get(int rc){ return i2e.get(rc); }
}
}
@@ -1,5 +1,5 @@
/*
** 2023-08-23
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -11,15 +11,15 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
package org.sqlite.jni;
/**
A callback for use with sqlite3_config().
Callback proxy for use with sqlite3_rollback_hook().
*/
public interface ConfigLogCallback {
public interface RollbackHook {
/**
Must function as described for a C-level callback for
{@link CApi#sqlite3_config(ConfigLogCallback)}, with the slight signature change.
Works as documented for the sqlite3_rollback_hook() callback.
Must not throw.
*/
void call(int errCode, String msg);
void xRollbackHook();
}
+172
View File
@@ -0,0 +1,172 @@
/*
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
SQLFunction is used in conjunction with the
sqlite3_create_function() JNI-bound API to give that native code
access to the callback functions needed in order to implement SQL
functions in Java.
This class is not used by itself, but is a marker base class. The
three UDF types are modelled by the inner classes Scalar,
Aggregate<T>, and Window<T>. Most simply, clients may create
anonymous classes from those to implement UDFs. Clients are free to
create their own classes for use with UDFs, so long as they conform
to the public interfaces defined by those three classes. The JNI
layer only actively relies on the SQLFunction base class.
*/
public abstract class SQLFunction {
/**
PerContextState assists aggregate and window functions in
managinga their accumulator state across calls to the UDF's
callbacks.
If a given aggregate or window function is called multiple times
in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
then the clients need some way of knowing which call is which so
that they can map their state between their various UDF callbacks
and reset it via xFinal(). This class takes care of such
mappings.
This class works by mapping
sqlite3_context.getAggregateContext() to a single piece of
state, of a client-defined type (the T part of this class), which
persists across a "matching set" of the UDF's callbacks.
This class is a helper providing commonly-needed functionality -
it is not required for use with aggregate or window functions.
Client UDFs are free to perform such mappings using custom
approaches. The provided Aggregate<T> and Window<T> classes
use this.
*/
public static final class PerContextState<T> {
private final java.util.Map<Long,ValueHolder<T>> map
= new java.util.HashMap<>();
/**
Should be called from a UDF's xStep(), xValue(), and xInverse()
methods, passing it that method's first argument and an initial
value for the persistent state. If there is currently no
mapping for cx.getAggregateContext() within the map, one is
created using the given initial value, else the existing one is
used and the 2nd argument is ignored. It returns a
ValueHolder<T> which can be used to modify that state directly
without requiring that the client update the underlying map's
entry.
T must be of a type which can be legally stored as a value in
java.util.HashMap<KeyType,T>.
*/
public ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
ValueHolder<T> rc = map.get(cx.getAggregateContext());
if(null == rc){
map.put(cx.getAggregateContext(), rc = new ValueHolder<>(initialValue));
}
return rc;
}
/**
Should be called from a UDF's xFinal() method and passed that
method's first argument. This function removes the value
associated with cx.getAggregateContext() from the map and
returns it, returning null if no other UDF method has been
called to set up such a mapping. The latter condition will be
the case if a UDF is used in a statement which has no result
rows.
*/
public T takeAggregateState(sqlite3_context cx){
final ValueHolder<T> h = map.remove(cx.getAggregateContext());
return null==h ? null : h.value;
}
}
//! Subclass for creating scalar functions.
public static abstract class Scalar extends SQLFunction {
//! As for the xFunc() argument of the C API's sqlite3_create_function()
public abstract void xFunc(sqlite3_context cx, sqlite3_value[] args);
/**
Optionally override to be notified when the UDF is finalized by
SQLite.
*/
public void xDestroy() {}
}
/**
SQLFunction Subclass for creating aggregate functions. Its T is
the data type of its "accumulator" state, an instance of which is
intended to be be managed using the getAggregateState() and
takeAggregateState() methods.
*/
public static abstract class Aggregate<T> extends SQLFunction {
//! As for the xStep() argument of the C API's sqlite3_create_function()
public abstract void xStep(sqlite3_context cx, sqlite3_value[] args);
//! As for the xFinal() argument of the C API's sqlite3_create_function()
public abstract void xFinal(sqlite3_context cx);
/**
Optionally override to be notified when the UDF is finalized by
SQLite.
*/
public void xDestroy() {}
//! Per-invocation state for the UDF.
private final PerContextState<T> map = new PerContextState<>();
/**
To be called from the implementation's xStep() method, as well
as the xValue() and xInverse() methods of the Window<T>
subclass, to fetch the current per-call UDF state. On the
first call to this method for any given sqlite3_context
argument, the context is set to the given initial value. On all other
calls, the 2nd argument is ignored.
@see PerContextState<T>#takeAggregateState()
*/
protected final ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
return map.getAggregateState(cx, initialValue);
}
/**
To be called from the implementation's xFinal() method to fetch
the final state of the UDF and remove its mapping.
@see PerContextState<T>#takeAggregateState()
*/
protected final T takeAggregateState(sqlite3_context cx){
return map.takeAggregateState(cx);
}
}
/**
An SQLFunction subclass for creating window functions. Note that
Window<T> inherits from Aggregate<T> and each instance is
required to implement the inherited abstract methods from that
class. See Aggregate<T> for information on managing the UDF's
invocation-specific state.
*/
public static abstract class Window<T> extends Aggregate<T> {
//! As for the xInverse() argument of the C API's sqlite3_create_window_function()
public abstract void xInverse(sqlite3_context cx, sqlite3_value[] args);
//! As for the xValue() argument of the C API's sqlite3_create_window_function()
public abstract void xValue(sqlite3_context cx);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,87 @@
/*
** 2023-08-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.
**
*************************************************************************
** This file contains a set of tests for the sqlite3 JNI bindings.
*/
package org.sqlite.jni;
import static org.sqlite.jni.SQLite3Jni.*;
import static org.sqlite.jni.Tester1.*;
public class TesterFts5 {
private static void test1(){
Fts5ExtensionApi fea = Fts5ExtensionApi.getInstance();
affirm( null != fea );
affirm( fea.getNativePointer() != 0 );
affirm( fea == Fts5ExtensionApi.getInstance() )/*singleton*/;
sqlite3 db = createNewDb();
fts5_api fApi = fts5_api.getInstanceForDb(db);
affirm( fApi != null );
affirm( fApi == fts5_api.getInstanceForDb(db) /* singleton per db */ );
execSql(db, new String[] {
"CREATE VIRTUAL TABLE ft USING fts5(a, b);",
"INSERT INTO ft(rowid, a, b) VALUES(1, 'X Y', 'Y Z');",
"INSERT INTO ft(rowid, a, b) VALUES(2, 'A Z', 'Y Y');"
});
final String pUserData = "This is pUserData";
ValueHolder<Boolean> xDestroyCalled = new ValueHolder<>(false);
ValueHolder<Integer> xFuncCount = new ValueHolder<>(0);
final fts5_extension_function func = new fts5_extension_function(){
public void xFunction(Fts5ExtensionApi ext, Fts5Context fCx,
sqlite3_context pCx, sqlite3_value argv[]){
int nCols = ext.xColumnCount(fCx);
affirm( 2 == nCols );
affirm( nCols == argv.length );
affirm( ext.xUserData(fCx) == pUserData );
if(true){
OutputPointer.String op = new OutputPointer.String();
for(int i = 0; i < nCols; ++i ){
int rc = ext.xColumnText(fCx, i, op);
affirm( 0 == rc );
final String val = op.value;
affirm( val.equals(sqlite3_value_text(argv[i])) );
//outln("xFunction col "+i+": "+val);
}
}
++xFuncCount.value;
}
public void xDestroy(){
xDestroyCalled.value = true;
}
};
int rc = fApi.xCreateFunction("myaux", pUserData, func);
affirm( 0==rc );
affirm( 0==xFuncCount.value );
execSql(db, "select myaux(ft,a,b) from ft;");
affirm( 2==xFuncCount.value );
affirm( !xDestroyCalled.value );
sqlite3_close_v2(db);
affirm( xDestroyCalled.value );
}
public TesterFts5(){
int oldAffirmCount = Tester1.affirmCount;
Tester1.affirmCount = 0;
final long timeStart = System.nanoTime();
test1();
final long timeEnd = System.nanoTime();
outln("FTS5 Tests done. Metrics:");
outln("\tAssertions checked: "+Tester1.affirmCount);
outln("\tTotal time = "
+((timeEnd - timeStart)/1000000.0)+"ms");
Tester1.affirmCount = oldAffirmCount;
}
}
+62
View File
@@ -0,0 +1,62 @@
/*
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
Callback proxy for use with sqlite3_trace_v2().
*/
public interface Tracer {
/**
Achtung: this interface is subject to change because the current
approach to mapping the passed-in natives back to Java is
uncomfortably quirky.
Called by sqlite3 for various tracing operations, as per
sqlite3_trace_v2(). Note that this interface elides the 2nd
argument to the native trace callback, as that role is better
filled by instance-local state.
The 2nd argument to this function, if non-0, will be a native
pointer to either an sqlite3 or sqlite3_stmt object, depending on
the first argument (see below). Client code can pass it to the
sqlite3 resp. sqlite3_stmt constructor to create a wrapping
object, if necessary. This API does not do so by default because
tracing can be called frequently, creating such a wrapper for
each call is comparatively expensive, and the objects are
probably only seldom useful.
The final argument to this function is the "X" argument
documented for sqlite3_trace() and sqlite3_trace_v2(). Its type
depends on value of the first argument:
- SQLITE_TRACE_STMT: pNative is a sqlite3_stmt. pX is a string
containing the prepared SQL, with one caveat: JNI only provides
us with the ability to convert that string to MUTF-8, as
opposed to standard UTF-8, and is cannot be ruled out that that
difference may be significant for certain inputs. The
alternative would be that we first convert it to UTF-16 before
passing it on, but there's no readily-available way to do that
without calling back into the db to peform the conversion
(which would lead to further tracing).
- SQLITE_TRACE_PROFILE: pNative is a sqlite3_stmt. pX is a Long
holding an approximate number of nanoseconds the statement took
to run.
- SQLITE_TRACE_ROW: pNative is a sqlite3_stmt. pX is null.
- SQLITE_TRACE_CLOSE: pNative is a sqlite3. pX is null.
*/
int xCallback(int traceFlag, Object pNative, Object pX);
}
@@ -1,5 +1,5 @@
/*
** 2023-08-25
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -11,16 +11,15 @@
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
package org.sqlite.jni;
/**
Callback for use with {@link CApi#sqlite3_commit_hook}.
Callback proxy for use with sqlite3_update_hook().
*/
public interface CommitHookCallback extends CallbackProxy {
public interface UpdateHook {
/**
Works as documented for the C-level sqlite3_commit_hook()
callback. If it throws, the exception is translated into
a db-level error.
Works as documented for the sqlite3_update_hook() callback.
Must not throw.
*/
int call();
void xUpdateHook(int opId, String dbName, String tableName, long rowId);
}
@@ -1,5 +1,5 @@
/*
** 2023-10-16
** 2023-07-21
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -9,13 +9,13 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the ValueHolder utility class.
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.wrapper1;
package org.sqlite.jni;
/**
A helper class which simply holds a single value. Its primary use
is for communicating values out of anonymous callbacks, as doing so
A helper class which simply holds a single value. Its current use
is for communicating values out of anonymous classes, as doing so
requires a "final" reference.
*/
public class ValueHolder<T> {
@@ -1,30 +0,0 @@
/*
** 2023-09-27
**
** 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 houses the Experimental annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;
/**
This annotation is for flagging methods, constructors, and types
which are expressly experimental and subject to any amount of
change or outright removal. Client code should not rely on such
features.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({
ElementType.METHOD,
ElementType.CONSTRUCTOR,
ElementType.TYPE
})
public @interface Experimental{}
@@ -1,71 +0,0 @@
/*
** 2023-09-27
**
** 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 houses the NotNull annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;
/**
This annotation is for flagging parameters which may not legally be
null or point to closed/finalized C-side resources.
<p>In the case of Java types which map directly to C struct types
(e.g. {@link org.sqlite.jni.capi.sqlite3}, {@link
org.sqlite.jni.capi.sqlite3_stmt}, and {@link
org.sqlite.jni.capi.sqlite3_context}), a closed/finalized resource
is also considered to be null for purposes this annotation because
the C-side effect of passing such a handle is the same as if null
is passed.</p>
<p>When used in the context of Java interfaces which are called
from the C APIs, this annotation communicates that the C API will
never pass a null value to the callback for that parameter.</p>
<p>Passing a null, for this annotation's definition of null, for
any parameter marked with this annoation specifically invokes
undefined behavior (see below).</p>
<p>Passing 0 (i.e. C NULL) or a negative value for any long-type
parameter marked with this annoation specifically invokes undefined
behavior (see below). Such values are treated as C pointers in the
JNI layer.</p>
<p><b>Undefined behaviour:</b> the JNI build uses the {@code
SQLITE_ENABLE_API_ARMOR} build flag, meaning that the C code
invoked with invalid NULL pointers and the like will not invoke
undefined behavior in the conventional C sense, but may, for
example, return result codes which are not documented for the
affected APIs or may otherwise behave unpredictably. In no known
cases will such arguments result in C-level code dereferencing a
NULL pointer or accessing out-of-bounds (or otherwise invalid)
memory. In other words, they may cause unexpected behavior but
should never cause an outright crash or security issue.</p>
<p>Note that the C-style API does not throw any exceptions on its
own because it has a no-throw policy in order to retain its C-style
semantics, but it may trigger NullPointerExceptions (or similar) if
passed a null for a parameter flagged with this annotation.</p>
<p>This annotation is informational only. No policy is in place to
programmatically ensure that NotNull is conformed to in client
code.</p>
<p>This annotation is solely for the use by the classes in the
org.sqlite.jni package and subpackages, but is made public so that
javadoc will link to it from the annotated functions. It is not
part of the public API and client-level code must not rely on
it.</p>
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.PARAMETER)
public @interface NotNull{}
@@ -1,33 +0,0 @@
/*
** 2023-09-27
**
** 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 houses the Nullable annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;
/**
This annotation is for flagging parameters which may legally be
null, noting that they may behave differently if passed null but
are prepared to expect null as a value. When used in the context of
callback methods which are called into from the C APIs, this
annotation communicates that the C API may pass a null value to the
callback.
<p>This annotation is solely for the use by the classes in this
package but is made public so that javadoc will link to it from the
annotated functions. It is not part of the public API and
client-level code must not rely on it.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.PARAMETER)
public @interface Nullable{}
@@ -1,17 +0,0 @@
/*
** 2023-09-27
**
** 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 package houses annotations specific to the JNI bindings of the
SQLite3 C API.
*/
package org.sqlite.jni.annotation;
@@ -1,34 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
import org.sqlite.jni.annotation.NotNull;
/**
An implementation of {@link CollationCallback} which provides a
no-op xDestroy() method.
*/
public abstract class AbstractCollationCallback
implements CollationCallback, XDestroyCallback {
/**
Must compare the given byte arrays and return the result using
{@code memcmp()} semantics.
*/
public abstract int call(@NotNull byte[] lhs, @NotNull byte[] rhs);
/**
Optionally override to be notified when the UDF is finalized by
SQLite. This implementation does nothing.
*/
public void xDestroy(){}
}
@@ -1,138 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
A SQLFunction implementation for aggregate functions. Its T is the
data type of its "accumulator" state, an instance of which is
intended to be be managed using the getAggregateState() and
takeAggregateState() methods.
*/
public abstract class AggregateFunction<T> implements SQLFunction {
/**
As for the xStep() argument of the C API's
sqlite3_create_function(). If this function throws, the
exception is not propagated and a warning might be emitted to a
debugging channel.
*/
public abstract void xStep(sqlite3_context cx, sqlite3_value[] args);
/**
As for the xFinal() argument of the C API's sqlite3_create_function().
If this function throws, it is translated into an sqlite3_result_error().
*/
public abstract void xFinal(sqlite3_context cx);
/**
Optionally override to be notified when the UDF is finalized by
SQLite.
*/
public void xDestroy() {}
/**
PerContextState assists aggregate and window functions in
managing their accumulator state across calls to the UDF's
callbacks.
<p>T must be of a type which can be legally stored as a value in
java.util.HashMap<KeyType,T>.
<p>If a given aggregate or window function is called multiple times
in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
then the clients need some way of knowing which call is which so
that they can map their state between their various UDF callbacks
and reset it via xFinal(). This class takes care of such
mappings.
<p>This class works by mapping
sqlite3_context.getAggregateContext() to a single piece of
state, of a client-defined type (the T part of this class), which
persists across a "matching set" of the UDF's callbacks.
<p>This class is a helper providing commonly-needed functionality
- it is not required for use with aggregate or window functions.
Client UDFs are free to perform such mappings using custom
approaches. The provided {@link AggregateFunction} and {@link
WindowFunction} classes use this.
*/
public static final class PerContextState<T> {
private final java.util.Map<Long,ValueHolder<T>> map
= new java.util.HashMap<>();
/**
Should be called from a UDF's xStep(), xValue(), and xInverse()
methods, passing it that method's first argument and an initial
value for the persistent state. If there is currently no
mapping for the given context within the map, one is created
using the given initial value, else the existing one is used
and the 2nd argument is ignored. It returns a ValueHolder<T>
which can be used to modify that state directly without
requiring that the client update the underlying map's entry.
<p>The caller is obligated to eventually call
takeAggregateState() to clear the mapping.
*/
public ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
final Long key = cx.getAggregateContext(true);
ValueHolder<T> rc = null==key ? null : map.get(key);
if( null==rc ){
map.put(key, rc = new ValueHolder<>(initialValue));
}
return rc;
}
/**
Should be called from a UDF's xFinal() method and passed that
method's first argument. This function removes the value
associated with cx.getAggregateContext() from the map and
returns it, returning null if no other UDF method has been
called to set up such a mapping. The latter condition will be
the case if a UDF is used in a statement which has no result
rows.
*/
public T takeAggregateState(sqlite3_context cx){
final ValueHolder<T> h = map.remove(cx.getAggregateContext(false));
return null==h ? null : h.value;
}
}
/** Per-invocation state for the UDF. */
private final PerContextState<T> map = new PerContextState<>();
/**
To be called from the implementation's xStep() method, as well
as the xValue() and xInverse() methods of the {@link WindowFunction}
subclass, to fetch the current per-call UDF state. On the
first call to this method for any given sqlite3_context
argument, the context is set to the given initial value. On all other
calls, the 2nd argument is ignored.
@see SQLFunction.PerContextState#getAggregateState
*/
protected final ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
return map.getAggregateState(cx, initialValue);
}
/**
To be called from the implementation's xFinal() method to fetch
the final state of the UDF and remove its mapping.
see SQLFunction.PerContextState#takeAggregateState
*/
protected final T takeAggregateState(sqlite3_context cx){
return map.takeAggregateState(cx);
}
}
@@ -1,29 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
import org.sqlite.jni.annotation.*;
/**
Callback for use with {@link CApi#sqlite3_set_authorizer}.
*/
public interface AuthorizerCallback extends CallbackProxy {
/**
Must function as described for the C-level
sqlite3_set_authorizer() callback. If it throws, the error is
converted to a db-level error and the exception is suppressed.
*/
int call(int opId, @Nullable String s1, @Nullable String s2,
@Nullable String s3, @Nullable String s4);
}
@@ -1,40 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
Callback for use with the {@link CApi#sqlite3_auto_extension}
family of APIs.
*/
public interface AutoExtensionCallback extends CallbackProxy {
/**
Must function as described for a C-level
sqlite3_auto_extension() callback.
<p>This callback may throw and the exception's error message will
be set as the db's error string.
<p>Tips for implementations:
<p>- Opening a database from an auto-extension handler will lead to
an endless recursion of the auto-handler triggering itself
indirectly for each newly-opened database.
<p>- If this routine is stateful, it may be useful to make the
overridden method synchronized.
<p>- Results are undefined if the given db is closed by an auto-extension.
*/
int call(sqlite3 db);
}
@@ -1,26 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
Callback for use with {@link CApi#sqlite3_busy_handler}.
*/
public interface BusyHandlerCallback extends CallbackProxy {
/**
Must function as documented for the C-level
sqlite3_busy_handler() callback argument, minus the (void*)
argument the C-level function requires.
*/
int call(int n);
}
File diff suppressed because it is too large Load Diff
@@ -1,45 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
This marker interface exists soley for use as a documentation and
class-grouping tool. It should be applied to interfaces or
classes which have a call() method implementing some specific
callback interface on behalf of the C library.
<p>Unless very explicitely documented otherwise, callbacks must
never throw. Any which do throw but should not might trigger debug
output regarding the error, but the exception will not be
propagated. For callback interfaces which support returning error
info to the core, the JNI binding will convert any exceptions to
C-level error information. For callback interfaces which do not
support returning error information, all exceptions will
necessarily be suppressed in order to retain the C-style no-throw
semantics and avoid invoking undefined behavior in the C layer.
<p>Callbacks of this style follow a common naming convention:
<p>1) They use the UpperCamelCase form of the C function they're
proxying for, minus the {@code sqlite3_} prefix, plus a {@code
Callback} suffix. e.g. {@code sqlite3_busy_handler()}'s callback is
named {@code BusyHandlerCallback}. Exceptions are made where that
would potentially be ambiguous, e.g. {@link ConfigSqllogCallback}
instead of {@code ConfigCallback} because the {@code
sqlite3_config()} interface may need to support more callback types
in the future.
<p>2) They all have a {@code call()} method but its signature is
callback-specific.
*/
public interface CallbackProxy {}
@@ -1,35 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
import org.sqlite.jni.annotation.NotNull;
/**
Callback for use with {@link CApi#sqlite3_create_collation}.
@see AbstractCollationCallback
*/
public interface CollationCallback
extends CallbackProxy, XDestroyCallback {
/**
Must compare the given byte arrays and return the result using
{@code memcmp()} semantics.
*/
int call(@NotNull byte[] lhs, @NotNull byte[] rhs);
/**
Called by SQLite when the collation is destroyed. If a collation
requires custom cleanup, override this method.
*/
void xDestroy();
}
@@ -1,253 +0,0 @@
/*
** 2023-07-21
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
Helper classes for handling JNI output pointers.
<p>We do not use a generic OutputPointer<T> because working with those
from the native JNI code is unduly quirky due to a lack of
autoboxing at that level.
<p>The usage is similar for all of thes types:
<pre>{@code
OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
assert( null==out.get() );
int rc = sqlite3_open(":memory:", out);
if( 0!=rc ) ... error;
assert( null!=out.get() );
sqlite3 db = out.take();
assert( null==out.get() );
}</pre>
<p>With the minor exception that the primitive types permit direct
access to the object's value via the `value` property, whereas the
JNI-level opaque types do not permit client-level code to set that
property.
<p>Warning: do not share instances of these classes across
threads. Doing so may lead to corrupting sqlite3-internal state.
*/
public final class OutputPointer {
/**
Output pointer for use with routines, such as sqlite3_open(),
which return a database handle via an output pointer. These
pointers can only be set by the JNI layer, not by client-level
code.
*/
public static final class sqlite3 {
private org.sqlite.jni.capi.sqlite3 value;
/** Initializes with a null value. */
public sqlite3(){value = null;}
/** Sets the current value to null. */
public void clear(){value = null;}
/** Returns the current value. */
public final org.sqlite.jni.capi.sqlite3 get(){return value;}
/** Equivalent to calling get() then clear(). */
public final org.sqlite.jni.capi.sqlite3 take(){
final org.sqlite.jni.capi.sqlite3 v = value;
value = null;
return v;
}
}
/**
Output pointer for sqlite3_blob_open(). These
pointers can only be set by the JNI layer, not by client-level
code.
*/
public static final class sqlite3_blob {
private org.sqlite.jni.capi.sqlite3_blob value;
/** Initializes with a null value. */
public sqlite3_blob(){value = null;}
/** Sets the current value to null. */
public void clear(){value = null;}
/** Returns the current value. */
public final org.sqlite.jni.capi.sqlite3_blob get(){return value;}
/** Equivalent to calling get() then clear(). */
public final org.sqlite.jni.capi.sqlite3_blob take(){
final org.sqlite.jni.capi.sqlite3_blob v = value;
value = null;
return v;
}
}
/**
Output pointer for use with routines, such as sqlite3_prepare(),
which return a statement handle via an output pointer. These
pointers can only be set by the JNI layer, not by client-level
code.
*/
public static final class sqlite3_stmt {
private org.sqlite.jni.capi.sqlite3_stmt value;
/** Initializes with a null value. */
public sqlite3_stmt(){value = null;}
/** Sets the current value to null. */
public void clear(){value = null;}
/** Returns the current value. */
public final org.sqlite.jni.capi.sqlite3_stmt get(){return value;}
/** Equivalent to calling get() then clear(). */
public final org.sqlite.jni.capi.sqlite3_stmt take(){
final org.sqlite.jni.capi.sqlite3_stmt v = value;
value = null;
return v;
}
}
/**
Output pointer for use with routines, such as sqlite3_prepupdate_new(),
which return a sqlite3_value handle via an output pointer. These
pointers can only be set by the JNI layer, not by client-level
code.
*/
public static final class sqlite3_value {
private org.sqlite.jni.capi.sqlite3_value value;
/** Initializes with a null value. */
public sqlite3_value(){value = null;}
/** Sets the current value to null. */
public void clear(){value = null;}
/** Returns the current value. */
public final org.sqlite.jni.capi.sqlite3_value get(){return value;}
/** Equivalent to calling get() then clear(). */
public final org.sqlite.jni.capi.sqlite3_value take(){
final org.sqlite.jni.capi.sqlite3_value v = value;
value = null;
return v;
}
}
/**
Output pointer for use with native routines which return booleans
via integer output pointers.
*/
public static final class Bool {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public boolean value;
/** Initializes with the value 0. */
public Bool(){this(false);}
/** Initializes with the value v. */
public Bool(boolean v){value = v;}
/** Returns the current value. */
public final boolean get(){return value;}
/** Sets the current value to v. */
public final void set(boolean v){value = v;}
}
/**
Output pointer for use with native routines which return integers via
output pointers.
*/
public static final class Int32 {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public int value;
/** Initializes with the value 0. */
public Int32(){this(0);}
/** Initializes with the value v. */
public Int32(int v){value = v;}
/** Returns the current value. */
public final int get(){return value;}
/** Sets the current value to v. */
public final void set(int v){value = v;}
}
/**
Output pointer for use with native routines which return 64-bit integers
via output pointers.
*/
public static final class Int64 {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public long value;
/** Initializes with the value 0. */
public Int64(){this(0);}
/** Initializes with the value v. */
public Int64(long v){value = v;}
/** Returns the current value. */
public final long get(){return value;}
/** Sets the current value. */
public final void set(long v){value = v;}
}
/**
Output pointer for use with native routines which return strings via
output pointers.
*/
public static final class String {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public java.lang.String value;
/** Initializes with a null value. */
public String(){this(null);}
/** Initializes with the value v. */
public String(java.lang.String v){value = v;}
/** Returns the current value. */
public final java.lang.String get(){return value;}
/** Sets the current value. */
public final void set(java.lang.String v){value = v;}
}
/**
Output pointer for use with native routines which return byte
arrays via output pointers.
*/
public static final class ByteArray {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public byte[] value;
/** Initializes with the value null. */
public ByteArray(){this(null);}
/** Initializes with the value v. */
public ByteArray(byte[] v){value = v;}
/** Returns the current value. */
public final byte[] get(){return value;}
/** Sets the current value. */
public final void set(byte[] v){value = v;}
}
/**
Output pointer for use with native routines which return
blobs via java.nio.ByteBuffer.
See {@link org.sqlite.jni.capi.CApi#sqlite3_jni_supports_nio}
*/
public static final class ByteBuffer {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public java.nio.ByteBuffer value;
/** Initializes with the value null. */
public ByteBuffer(){this(null);}
/** Initializes with the value v. */
public ByteBuffer(java.nio.ByteBuffer v){value = v;}
/** Returns the current value. */
public final java.nio.ByteBuffer get(){return value;}
/** Sets the current value. */
public final void set(java.nio.ByteBuffer v){value = v;}
}
}
@@ -1,81 +0,0 @@
/*
** 2023-09-13
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
Callback for use with {@link CApi#sqlite3_prepare_multi}.
*/
public interface PrepareMultiCallback extends CallbackProxy {
/**
Gets passed a sqlite3_stmt which it may handle in arbitrary ways,
transfering ownership of it to this function.
sqlite3_prepare_multi() will _not_ finalize st - it is up
to the call() implementation how st is handled.
Must return 0 on success or an SQLITE_... code on error. If it
throws, sqlite3_prepare_multi() will transform the exception into
a db-level error in order to retain the C-style error semantics
of the API.
See the {@link Finalize} class for a wrapper which finalizes the
statement after calling a proxy PrepareMultiCallback.
*/
int call(sqlite3_stmt st);
/**
A PrepareMultiCallback impl which wraps a separate impl and finalizes
any sqlite3_stmt passed to its callback.
*/
public static final class Finalize implements PrepareMultiCallback {
private final PrepareMultiCallback p;
/**
p is the proxy to call() when this.call() is called.
*/
public Finalize( PrepareMultiCallback p ){
this.p = p;
}
/**
Calls the call() method of the proxied callback and either returns its
result or propagates an exception. Either way, it passes its argument to
sqlite3_finalize() before returning.
*/
@Override public int call(sqlite3_stmt st){
try {
return this.p.call(st);
}finally{
CApi.sqlite3_finalize(st);
}
}
}
/**
A PrepareMultiCallback impl which steps entirely through a result set,
ignoring all non-error results.
*/
public static final class StepAll implements PrepareMultiCallback {
public StepAll(){}
/**
Calls sqlite3_step() on st until it returns something other than
SQLITE_ROW. If the final result is SQLITE_DONE then 0 is returned,
else the result of the final step is returned.
*/
@Override public int call(sqlite3_stmt st){
int rc = CApi.SQLITE_DONE;
while( CApi.SQLITE_ROW == (rc = CApi.sqlite3_step(st)) ){}
return CApi.SQLITE_DONE==rc ? 0 : rc;
}
}
}
@@ -1,27 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
Callback for use with {@link CApi#sqlite3_preupdate_hook}.
*/
public interface PreupdateHookCallback extends CallbackProxy {
/**
Must function as described for the C-level sqlite3_preupdate_hook()
callback. If it throws, the exception is translated to a
db-level error and the exception is suppressed.
*/
void call(sqlite3 db, int op, String dbName, String dbTable,
long iKey1, long iKey2 );
}
@@ -1,155 +0,0 @@
/*
** 2023-07-21
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
This enum contains all of the core and "extended" result codes used
by the sqlite3 library. It is provided not for use with the C-style
API (with which it won't work) but for higher-level code which may
find it useful to map SQLite result codes to human-readable names.
*/
public enum ResultCode {
SQLITE_OK(CApi.SQLITE_OK),
SQLITE_ERROR(CApi.SQLITE_ERROR),
SQLITE_INTERNAL(CApi.SQLITE_INTERNAL),
SQLITE_PERM(CApi.SQLITE_PERM),
SQLITE_ABORT(CApi.SQLITE_ABORT),
SQLITE_BUSY(CApi.SQLITE_BUSY),
SQLITE_LOCKED(CApi.SQLITE_LOCKED),
SQLITE_NOMEM(CApi.SQLITE_NOMEM),
SQLITE_READONLY(CApi.SQLITE_READONLY),
SQLITE_INTERRUPT(CApi.SQLITE_INTERRUPT),
SQLITE_IOERR(CApi.SQLITE_IOERR),
SQLITE_CORRUPT(CApi.SQLITE_CORRUPT),
SQLITE_NOTFOUND(CApi.SQLITE_NOTFOUND),
SQLITE_FULL(CApi.SQLITE_FULL),
SQLITE_CANTOPEN(CApi.SQLITE_CANTOPEN),
SQLITE_PROTOCOL(CApi.SQLITE_PROTOCOL),
SQLITE_EMPTY(CApi.SQLITE_EMPTY),
SQLITE_SCHEMA(CApi.SQLITE_SCHEMA),
SQLITE_TOOBIG(CApi.SQLITE_TOOBIG),
SQLITE_CONSTRAINT(CApi.SQLITE_CONSTRAINT),
SQLITE_MISMATCH(CApi.SQLITE_MISMATCH),
SQLITE_MISUSE(CApi.SQLITE_MISUSE),
SQLITE_NOLFS(CApi.SQLITE_NOLFS),
SQLITE_AUTH(CApi.SQLITE_AUTH),
SQLITE_FORMAT(CApi.SQLITE_FORMAT),
SQLITE_RANGE(CApi.SQLITE_RANGE),
SQLITE_NOTADB(CApi.SQLITE_NOTADB),
SQLITE_NOTICE(CApi.SQLITE_NOTICE),
SQLITE_WARNING(CApi.SQLITE_WARNING),
SQLITE_ROW(CApi.SQLITE_ROW),
SQLITE_DONE(CApi.SQLITE_DONE),
SQLITE_ERROR_MISSING_COLLSEQ(CApi.SQLITE_ERROR_MISSING_COLLSEQ),
SQLITE_ERROR_RETRY(CApi.SQLITE_ERROR_RETRY),
SQLITE_ERROR_SNAPSHOT(CApi.SQLITE_ERROR_SNAPSHOT),
SQLITE_IOERR_READ(CApi.SQLITE_IOERR_READ),
SQLITE_IOERR_SHORT_READ(CApi.SQLITE_IOERR_SHORT_READ),
SQLITE_IOERR_WRITE(CApi.SQLITE_IOERR_WRITE),
SQLITE_IOERR_FSYNC(CApi.SQLITE_IOERR_FSYNC),
SQLITE_IOERR_DIR_FSYNC(CApi.SQLITE_IOERR_DIR_FSYNC),
SQLITE_IOERR_TRUNCATE(CApi.SQLITE_IOERR_TRUNCATE),
SQLITE_IOERR_FSTAT(CApi.SQLITE_IOERR_FSTAT),
SQLITE_IOERR_UNLOCK(CApi.SQLITE_IOERR_UNLOCK),
SQLITE_IOERR_RDLOCK(CApi.SQLITE_IOERR_RDLOCK),
SQLITE_IOERR_DELETE(CApi.SQLITE_IOERR_DELETE),
SQLITE_IOERR_BLOCKED(CApi.SQLITE_IOERR_BLOCKED),
SQLITE_IOERR_NOMEM(CApi.SQLITE_IOERR_NOMEM),
SQLITE_IOERR_ACCESS(CApi.SQLITE_IOERR_ACCESS),
SQLITE_IOERR_CHECKRESERVEDLOCK(CApi.SQLITE_IOERR_CHECKRESERVEDLOCK),
SQLITE_IOERR_LOCK(CApi.SQLITE_IOERR_LOCK),
SQLITE_IOERR_CLOSE(CApi.SQLITE_IOERR_CLOSE),
SQLITE_IOERR_DIR_CLOSE(CApi.SQLITE_IOERR_DIR_CLOSE),
SQLITE_IOERR_SHMOPEN(CApi.SQLITE_IOERR_SHMOPEN),
SQLITE_IOERR_SHMSIZE(CApi.SQLITE_IOERR_SHMSIZE),
SQLITE_IOERR_SHMLOCK(CApi.SQLITE_IOERR_SHMLOCK),
SQLITE_IOERR_SHMMAP(CApi.SQLITE_IOERR_SHMMAP),
SQLITE_IOERR_SEEK(CApi.SQLITE_IOERR_SEEK),
SQLITE_IOERR_DELETE_NOENT(CApi.SQLITE_IOERR_DELETE_NOENT),
SQLITE_IOERR_MMAP(CApi.SQLITE_IOERR_MMAP),
SQLITE_IOERR_GETTEMPPATH(CApi.SQLITE_IOERR_GETTEMPPATH),
SQLITE_IOERR_CONVPATH(CApi.SQLITE_IOERR_CONVPATH),
SQLITE_IOERR_VNODE(CApi.SQLITE_IOERR_VNODE),
SQLITE_IOERR_AUTH(CApi.SQLITE_IOERR_AUTH),
SQLITE_IOERR_BEGIN_ATOMIC(CApi.SQLITE_IOERR_BEGIN_ATOMIC),
SQLITE_IOERR_COMMIT_ATOMIC(CApi.SQLITE_IOERR_COMMIT_ATOMIC),
SQLITE_IOERR_ROLLBACK_ATOMIC(CApi.SQLITE_IOERR_ROLLBACK_ATOMIC),
SQLITE_IOERR_DATA(CApi.SQLITE_IOERR_DATA),
SQLITE_IOERR_CORRUPTFS(CApi.SQLITE_IOERR_CORRUPTFS),
SQLITE_LOCKED_SHAREDCACHE(CApi.SQLITE_LOCKED_SHAREDCACHE),
SQLITE_LOCKED_VTAB(CApi.SQLITE_LOCKED_VTAB),
SQLITE_BUSY_RECOVERY(CApi.SQLITE_BUSY_RECOVERY),
SQLITE_BUSY_SNAPSHOT(CApi.SQLITE_BUSY_SNAPSHOT),
SQLITE_BUSY_TIMEOUT(CApi.SQLITE_BUSY_TIMEOUT),
SQLITE_CANTOPEN_NOTEMPDIR(CApi.SQLITE_CANTOPEN_NOTEMPDIR),
SQLITE_CANTOPEN_ISDIR(CApi.SQLITE_CANTOPEN_ISDIR),
SQLITE_CANTOPEN_FULLPATH(CApi.SQLITE_CANTOPEN_FULLPATH),
SQLITE_CANTOPEN_CONVPATH(CApi.SQLITE_CANTOPEN_CONVPATH),
SQLITE_CANTOPEN_SYMLINK(CApi.SQLITE_CANTOPEN_SYMLINK),
SQLITE_CORRUPT_VTAB(CApi.SQLITE_CORRUPT_VTAB),
SQLITE_CORRUPT_SEQUENCE(CApi.SQLITE_CORRUPT_SEQUENCE),
SQLITE_CORRUPT_INDEX(CApi.SQLITE_CORRUPT_INDEX),
SQLITE_READONLY_RECOVERY(CApi.SQLITE_READONLY_RECOVERY),
SQLITE_READONLY_CANTLOCK(CApi.SQLITE_READONLY_CANTLOCK),
SQLITE_READONLY_ROLLBACK(CApi.SQLITE_READONLY_ROLLBACK),
SQLITE_READONLY_DBMOVED(CApi.SQLITE_READONLY_DBMOVED),
SQLITE_READONLY_CANTINIT(CApi.SQLITE_READONLY_CANTINIT),
SQLITE_READONLY_DIRECTORY(CApi.SQLITE_READONLY_DIRECTORY),
SQLITE_ABORT_ROLLBACK(CApi.SQLITE_ABORT_ROLLBACK),
SQLITE_CONSTRAINT_CHECK(CApi.SQLITE_CONSTRAINT_CHECK),
SQLITE_CONSTRAINT_COMMITHOOK(CApi.SQLITE_CONSTRAINT_COMMITHOOK),
SQLITE_CONSTRAINT_FOREIGNKEY(CApi.SQLITE_CONSTRAINT_FOREIGNKEY),
SQLITE_CONSTRAINT_FUNCTION(CApi.SQLITE_CONSTRAINT_FUNCTION),
SQLITE_CONSTRAINT_NOTNULL(CApi.SQLITE_CONSTRAINT_NOTNULL),
SQLITE_CONSTRAINT_PRIMARYKEY(CApi.SQLITE_CONSTRAINT_PRIMARYKEY),
SQLITE_CONSTRAINT_TRIGGER(CApi.SQLITE_CONSTRAINT_TRIGGER),
SQLITE_CONSTRAINT_UNIQUE(CApi.SQLITE_CONSTRAINT_UNIQUE),
SQLITE_CONSTRAINT_VTAB(CApi.SQLITE_CONSTRAINT_VTAB),
SQLITE_CONSTRAINT_ROWID(CApi.SQLITE_CONSTRAINT_ROWID),
SQLITE_CONSTRAINT_PINNED(CApi.SQLITE_CONSTRAINT_PINNED),
SQLITE_CONSTRAINT_DATATYPE(CApi.SQLITE_CONSTRAINT_DATATYPE),
SQLITE_NOTICE_RECOVER_WAL(CApi.SQLITE_NOTICE_RECOVER_WAL),
SQLITE_NOTICE_RECOVER_ROLLBACK(CApi.SQLITE_NOTICE_RECOVER_ROLLBACK),
SQLITE_WARNING_AUTOINDEX(CApi.SQLITE_WARNING_AUTOINDEX),
SQLITE_AUTH_USER(CApi.SQLITE_AUTH_USER),
SQLITE_OK_LOAD_PERMANENTLY(CApi.SQLITE_OK_LOAD_PERMANENTLY);
public final int value;
ResultCode(int rc){
value = rc;
ResultCodeMap.set(rc, this);
}
/**
Returns the entry from this enum for the given result code, or
null if no match is found.
*/
public static ResultCode getEntryForInt(int rc){
return ResultCodeMap.get(rc);
}
/**
Internal level of indirection required because we cannot initialize
static enum members in an enum before the enum constructor is
invoked.
*/
private static final class ResultCodeMap {
private static final java.util.Map<Integer,ResultCode> i2e
= new java.util.HashMap<>();
private static void set(int rc, ResultCode e){ i2e.put(rc, e); }
private static ResultCode get(int rc){ return i2e.get(rc); }
}
}
@@ -1,26 +0,0 @@
/*
** 2023-08-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
Callback for use with {@link CApi#sqlite3_rollback_hook}.
*/
public interface RollbackHookCallback extends CallbackProxy {
/**
Must function as documented for the C-level sqlite3_rollback_hook()
callback. If it throws, the exception is translated into
a db-level error.
*/
void call();
}
@@ -1,36 +0,0 @@
/*
** 2023-07-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
/**
SQLFunction is used in conjunction with the
sqlite3_create_function() JNI-bound API to give that native code
access to the callback functions needed in order to implement SQL
functions in Java.
<p>
This class is not used by itself, but is a marker base class. The
three UDF types are modelled by the inner classes Scalar,
Aggregate<T>, and Window<T>. Most simply, clients may subclass
those, or create anonymous classes from them, to implement
UDFs. Clients are free to create their own classes for use with
UDFs, so long as they conform to the public interfaces defined by
those three classes. The JNI layer only actively relies on the
SQLFunction base class and the method names and signatures used by
the UDF callback interfaces.
*/
public interface SQLFunction {
}

Some files were not shown because too many files have changed in this diff Show More