Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bfe2964c5d | |||
| bb0afc2818 | |||
| 48b12598cb | |||
| e25813cd12 | |||
| 015830dced | |||
| 81a18232ed | |||
| d01c7c421d | |||
| 177479fb16 | |||
| 1549472fb9 | |||
| db7f2f8b5f | |||
| cfa35c0c2d | |||
| 8c3ea529fd | |||
| 575d823095 | |||
| f7d02ca6fa | |||
| 38657ffcad | |||
| 6e0d6e0cc1 | |||
| 1409791d96 | |||
| 51aa802a4a | |||
| eeec597f9b | |||
| 303ba6ca1b | |||
| 1c1dfc1d46 | |||
| 10f6cdd308 | |||
| f1343a7532 | |||
| 7a68f807d4 | |||
| 2997f03826 | |||
| 09d3f5df07 | |||
| 27052c3e6f |
+31
-120
@@ -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.
|
||||
#
|
||||
@@ -600,7 +599,7 @@ SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
FUZZERSHELL_OPT =
|
||||
FUZZERSHELL_OPT =
|
||||
FUZZCHECK_OPT += -I$(TOP)/test
|
||||
FUZZCHECK_OPT += -I$(TOP)/ext/recover
|
||||
FUZZCHECK_OPT += \
|
||||
@@ -691,12 +690,6 @@ srcck1$(BEXE): $(TOP)/tool/srcck1.c
|
||||
sourcetest: srcck1$(BEXE) sqlite3.c
|
||||
./srcck1 sqlite3.c
|
||||
|
||||
src-verify: $(TOP)/tool/src-verify.c
|
||||
$(BCC) -o src-verify$(BEXE) $(TOP)/tool/src-verify.c
|
||||
|
||||
verify-source: ./src-verify
|
||||
./src-verify $(TOP)
|
||||
|
||||
fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(FUZZERSHELL_OPT) \
|
||||
$(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS)
|
||||
@@ -707,24 +700,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 +759,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 +775,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
|
||||
$(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 +798,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 +1086,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 +1100,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,32 +1116,29 @@ 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 \
|
||||
$(TOP)/ext/misc/memtrace.c \
|
||||
$(TOP)/ext/misc/pcachetrace.c \
|
||||
$(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 +1226,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 +1260,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 +1284,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
|
||||
|
||||
@@ -1348,23 +1305,11 @@ testrunner: testfixture$(TEXE)
|
||||
|
||||
# Runs both fuzztest and testrunner, consecutively.
|
||||
#
|
||||
devtest: srctree-check testfixture$(TEXE) fuzztest testrunner
|
||||
|
||||
mdevtest: srctree-check has_tclsh85
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl mdevtest
|
||||
|
||||
sdevtest: has_tclsh85
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl sdevtest
|
||||
|
||||
# Validate that various generated files in the source tree
|
||||
# are up-to-date.
|
||||
#
|
||||
srctree-check: $(TOP)/tool/srctree-check.tcl
|
||||
$(TCLSH_CMD) $(TOP)/tool/srctree-check.tcl
|
||||
devtest: testfixture$(TEXE) fuzztest testrunner
|
||||
|
||||
# Testing for a release
|
||||
#
|
||||
releasetest: srctree-check testfixture$(TEXE)
|
||||
releasetest: testfixture$(TEXE)
|
||||
./testfixture$(TEXE) $(TOP)/test/testrunner.tcl release
|
||||
|
||||
# Minimal testing that runs in less than 3 minutes
|
||||
@@ -1375,7 +1320,7 @@ quicktest: ./testfixture$(TEXE)
|
||||
# This is the common case. Run many tests that do not take too long,
|
||||
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
|
||||
#
|
||||
test: srctree-check fuzztest sourcetest $(TESTPROGS) tcltest
|
||||
test: fuzztest sourcetest $(TESTPROGS) tcltest
|
||||
|
||||
# Run a test using valgrind. This can take a really long time
|
||||
# because valgrind is so much slower than a native machine.
|
||||
@@ -1393,13 +1338,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 +1363,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 +1449,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.
|
||||
@@ -1566,7 +1506,6 @@ clean:
|
||||
rm -f LogEst$(TEXE) fts3view$(TEXE) rollback-test$(TEXE) showdb$(TEXE)
|
||||
rm -f showjournal$(TEXE) showstat4$(TEXE) showwal$(TEXE) speedtest1$(TEXE)
|
||||
rm -f wordcount$(TEXE) changeset$(TEXE)
|
||||
rm -f version-info$(TEXT)
|
||||
rm -f sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def
|
||||
rm -f sqlite3.c
|
||||
rm -f sqlite3rc.h
|
||||
@@ -1582,9 +1521,6 @@ clean:
|
||||
rm -f dbhash dbhash.exe
|
||||
rm -f fts5.* fts5parse.*
|
||||
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 \
|
||||
@@ -1613,28 +1549,3 @@ sqlite3.dll: $(REAL_LIBOBJ) sqlite3.def
|
||||
#
|
||||
fiddle: sqlite3.c shell.c
|
||||
make -C ext/wasm fiddle emcc_opt=-Os
|
||||
|
||||
#
|
||||
# Spell-checking for source comments
|
||||
# The sources checked are either C sources or C source templates.
|
||||
# Their comments are extracted and processed through aspell using
|
||||
# a custom dictionary that contains scads of odd identifiers that
|
||||
# find their way into the comments.
|
||||
#
|
||||
# Currently, this target is setup to be "made" in-tree only.
|
||||
# The output is ephemeral. Redirect it to guide spelling fixups,
|
||||
# either to correct spelling or add words to tool/custom.txt.
|
||||
#
|
||||
./custom.rws: ./tool/custom.txt
|
||||
@echo 'Updating custom dictionary from tool/custom.txt'
|
||||
aspell --lang=en create master ./custom.rws < $<
|
||||
|
||||
misspell: ./custom.rws has_tclsh84
|
||||
$(TCLSH_CMD) ./tool/spellsift.tcl ./src/*.c ./src/*.h ./src/*.in
|
||||
|
||||
#
|
||||
# tool/version-info: a utility for emitting sqlite3 version info
|
||||
# in various forms.
|
||||
#
|
||||
version-info$(TEXE): $(TOP)/tool/version-info.c Makefile sqlite3.h
|
||||
$(LTLINK) $(ST_OPT) -o $@ $(TOP)/tool/version-info.c
|
||||
|
||||
@@ -22,6 +22,12 @@ TOP = ../sqlite
|
||||
BCC = gcc -g -O0
|
||||
#BCC = /opt/ancic/bin/c89 -0
|
||||
|
||||
#### If the target operating system supports the "usleep()" system
|
||||
# call, then define the HAVE_USLEEP macro for all C modules.
|
||||
#
|
||||
#USLEEP =
|
||||
USLEEP = -DHAVE_USLEEP=1
|
||||
|
||||
#### If you want the SQLite library to be safe for use within a
|
||||
# multi-threaded program, then define the following macro
|
||||
# appropriately:
|
||||
|
||||
+19
-66
@@ -52,13 +52,6 @@ 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.
|
||||
#
|
||||
!IFNDEF USE_SEH
|
||||
USE_SEH = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to have the shell executable link against the core dynamic
|
||||
# link library.
|
||||
#
|
||||
@@ -225,12 +218,6 @@ WIN32HEAP = 0
|
||||
OSTRACE = 0
|
||||
!ENDIF
|
||||
|
||||
# enable address sanitizer using ASAN=1 on the command-line.
|
||||
#
|
||||
!IFNDEF ASAN
|
||||
ASAN = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this to one of the following values to enable various debugging
|
||||
# features. Each level includes the debugging options from the previous
|
||||
# levels. Currently, the recognized values for DEBUG are:
|
||||
@@ -374,7 +361,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
|
||||
@@ -403,14 +389,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
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.
|
||||
#
|
||||
!IF $(USE_SEH)==0
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_OMIT_SEH=1
|
||||
!ENDIF
|
||||
|
||||
# These are the "extended" SQLite compilation options used when compiling for
|
||||
# the Windows 10 platform.
|
||||
#
|
||||
@@ -899,13 +877,6 @@ RCC = $(RCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
|
||||
# Address sanitizer if ASAN=1
|
||||
#
|
||||
!IF $(ASAN)>0
|
||||
TCC = $(TCC) /fsanitize=address
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# The locations of the Tcl header and library files. Also, the library that
|
||||
# non-stubs enabled programs using Tcl must link against. These variables
|
||||
@@ -1594,7 +1565,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 +1582,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 +1661,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 +1792,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)
|
||||
@@ -1838,12 +1807,6 @@ srcck1.exe: $(TOP)\tool\srcck1.c
|
||||
sourcetest: srcck1.exe $(SQLITE3C)
|
||||
srcck1.exe $(SQLITE3C)
|
||||
|
||||
src-verify.exe: $(TOP)\tool\src-verify.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\src-verify.c
|
||||
|
||||
verify-source: src-verify.exe
|
||||
src-verify.exe $(TOP)
|
||||
|
||||
fuzzershell.exe: $(TOP)\tool\fuzzershell.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) $(TOP)\tool\fuzzershell.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
@@ -1907,7 +1870,7 @@ mptest: mptester.exe
|
||||
move vdbe.new tsrc\vdbe.c
|
||||
echo > .target_source
|
||||
|
||||
sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-verify.exe
|
||||
sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL)
|
||||
$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS)
|
||||
|
||||
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
|
||||
@@ -2261,12 +2224,10 @@ 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 \
|
||||
$(TOP)\ext\misc\base85.c \
|
||||
$(TOP)\ext\misc\base64.c \
|
||||
$(TOP)\ext\misc\base85.c \
|
||||
$(TOP)\ext\misc\decimal.c \
|
||||
$(TOP)\ext\misc\fileio.c \
|
||||
$(TOP)\ext\misc\ieee754.c \
|
||||
@@ -2277,10 +2238,9 @@ SHELL_SRC = \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.h \
|
||||
$(TOP)\ext\misc\memtrace.c \
|
||||
$(TOP)\ext\misc\pcachetrace.c \
|
||||
$(TOP)\ext\recover\dbdata.c \
|
||||
$(TOP)\ext\recover\sqlite3recover.c \
|
||||
$(TOP)\ext\recover\sqlite3recover.h \
|
||||
$(TOP)/ext/recover/dbdata.c \
|
||||
$(TOP)/ext/recover/sqlite3recover.c \
|
||||
$(TOP)/ext/recover/sqlite3recover.h \
|
||||
$(TOP)\src\test_windirent.c
|
||||
|
||||
# If use of zlib is enabled, add the "zipfile.c" source file.
|
||||
@@ -2472,9 +2432,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
|
||||
@@ -2527,13 +2484,10 @@ testrunner: testfixture.exe
|
||||
#
|
||||
devtest: testfixture.exe fuzztest testrunner
|
||||
|
||||
mdevtest:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest
|
||||
|
||||
# Testing for a release
|
||||
#
|
||||
releasetest: testfixture.exe fuzztest
|
||||
testfixture.exe $(TOP)\test\testrunner.tcl release
|
||||
testfixture.exe $(TOP)/test/testrunner.tcl release
|
||||
|
||||
|
||||
smoketest: $(TESTPROGS)
|
||||
@@ -2561,14 +2515,14 @@ sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\exp
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(SQLITE3C) $(TLIBS)
|
||||
|
||||
CHECKER_DEPS =\
|
||||
$(TOP)\tool\mkccode.tcl \
|
||||
$(TOP)/tool/mkccode.tcl \
|
||||
sqlite3.c \
|
||||
$(TOP)\src\tclsqlite.c \
|
||||
$(TOP)\ext\repair\sqlite3_checker.tcl \
|
||||
$(TOP)\ext\repair\checkindex.c \
|
||||
$(TOP)\ext\repair\checkfreelist.c \
|
||||
$(TOP)\ext\misc\btreeinfo.c \
|
||||
$(TOP)\ext\repair\sqlite3_checker.c.in
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
$(TOP)/ext/repair/sqlite3_checker.tcl \
|
||||
$(TOP)/ext/repair/checkindex.c \
|
||||
$(TOP)/ext/repair/checkfreelist.c \
|
||||
$(TOP)/ext/misc/btreeinfo.c \
|
||||
$(TOP)/ext/repair/sqlite3_checker.c.in
|
||||
|
||||
sqlite3_checker.c: $(CHECKER_DEPS)
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\ext\repair\sqlite3_checker.c.in > $@
|
||||
@@ -2707,5 +2661,4 @@ clean:
|
||||
del /Q showshm.exe sqlite3_checker.* sqlite3_expert.exe 2>NUL
|
||||
del /Q fts5.* fts5parse.* 2>NUL
|
||||
del /Q lsm.h lsm1.c 2>NUL
|
||||
del /q src-verify.exe 2>NUL
|
||||
# <</mark>>
|
||||
|
||||
@@ -25,28 +25,7 @@ If you pulled your SQLite source code from a secondary source and want to
|
||||
verify its integrity, there are hints on how to do that in the
|
||||
[Verifying Code Authenticity](#vauth) section below.
|
||||
|
||||
## Contacting The SQLite Developers
|
||||
|
||||
The preferred way to ask questions or make comments about SQLite or to
|
||||
report bugs against SQLite is to visit the
|
||||
[SQLite Forum](https://sqlite.org/forum) at <https://sqlite.org/forum/>.
|
||||
Anonymous postings are permitted.
|
||||
|
||||
If you think you have found a bug that has security implications and
|
||||
you do not want to report it on the public forum, you can send a private
|
||||
email to drh at sqlite dot org.
|
||||
|
||||
## Public Domain
|
||||
|
||||
The SQLite source code is in the public domain. See
|
||||
<https://sqlite.org/copyright.html> for details.
|
||||
|
||||
Because SQLite is in the public domain, we do not normally accept pull
|
||||
requests, because if we did take a pull request, the changes in that
|
||||
pull request might carry a copyright and the SQLite source code would
|
||||
then no longer be fully in the public domain.
|
||||
|
||||
## Obtaining The SQLite Source Code
|
||||
## Obtaining The Code
|
||||
|
||||
If you do not want to use Fossil, you can download tarballs or ZIP
|
||||
archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
|
||||
@@ -103,9 +82,9 @@ For example:
|
||||
mkdir bld ;# Build will occur in a sibling directory
|
||||
cd bld ;# Change to the build directory
|
||||
../sqlite/configure ;# Run the configure script
|
||||
make ;# Builds the "sqlite3" command-line tool
|
||||
make ;# Run the makefile.
|
||||
make sqlite3.c ;# Build the "amalgamation" source file
|
||||
make devtest ;# Run some tests (requires Tcl)
|
||||
make test ;# Run some tests (requires Tcl)
|
||||
|
||||
See the makefile for additional targets.
|
||||
|
||||
@@ -115,33 +94,32 @@ script does not work out for you, there is a generic makefile named
|
||||
can copy and edit to suit your needs. Comments on the generic makefile
|
||||
show what changes are needed.
|
||||
|
||||
## Compiling for Windows Using MSVC
|
||||
## Using MSVC for Windows systems
|
||||
|
||||
On Windows, all applicable build products can be compiled with MSVC.
|
||||
You will also need a working installation of TCL.
|
||||
See the [compile-for-windows.md](doc/compile-for-windows.md) document for
|
||||
additional information about how to install MSVC and TCL and configure your
|
||||
build environment.
|
||||
First open the command prompt window associated with the desired compiler
|
||||
version (e.g. "Developer Command Prompt for VS2013"). Next, use NMAKE
|
||||
with the provided "Makefile.msc" to build one of the supported targets.
|
||||
|
||||
If you want to run tests, you need to let SQLite know the location of your
|
||||
TCL library, using a command like this:
|
||||
For example, from the parent directory of the source subtree named "sqlite":
|
||||
|
||||
set TCLDIR=c:\Tcl
|
||||
mkdir bld
|
||||
cd bld
|
||||
nmake /f ..\sqlite\Makefile.msc TOP=..\sqlite
|
||||
nmake /f ..\sqlite\Makefile.msc sqlite3.c TOP=..\sqlite
|
||||
nmake /f ..\sqlite\Makefile.msc sqlite3.dll TOP=..\sqlite
|
||||
nmake /f ..\sqlite\Makefile.msc sqlite3.exe TOP=..\sqlite
|
||||
nmake /f ..\sqlite\Makefile.msc test TOP=..\sqlite
|
||||
|
||||
SQLite uses "tclsh.exe" as part of the build process, and so that utility
|
||||
program will need to be somewhere on your %PATH%. The finished SQLite library
|
||||
does not contain any TCL code, but it does use TCL to help with the build process
|
||||
and to run tests.
|
||||
There are several build options that can be set via the NMAKE command
|
||||
line. For example, to build for WinRT, simply add "FOR_WINRT=1" argument
|
||||
to the "sqlite3.dll" command line above. When debugging into the SQLite
|
||||
code, adding the "DEBUG=1" argument to one of the above command lines is
|
||||
recommended.
|
||||
|
||||
Build using Makefile.msc. Example:
|
||||
|
||||
nmake /f Makefile.msc
|
||||
nmake /f Makefile.msc sqlite3.c
|
||||
nmake /f Makefile.msc devtest
|
||||
nmake /f Makefile.msc releasetest
|
||||
|
||||
There are many other makefile targets. See comments in Makefile.msc for
|
||||
details.
|
||||
SQLite does not require [Tcl](http://www.tcl.tk/) to run, but a Tcl installation
|
||||
is required by the makefiles (including those for MSVC). SQLite contains
|
||||
a lot of generated code and Tcl is used to do much of that code generation.
|
||||
|
||||
## Source Code Tour
|
||||
|
||||
@@ -312,13 +290,16 @@ Key files:
|
||||
is not part of the core SQLite library. But as most of the tests in this
|
||||
repository are written in Tcl, the Tcl language bindings are important.
|
||||
|
||||
* **test\*.c** - Files in the src/ folder that begin with "test" go into
|
||||
* **test*.c** - Files in the src/ folder that begin with "test" go into
|
||||
building the "testfixture.exe" program. The testfixture.exe program is
|
||||
an enhanced Tcl shell. The testfixture.exe program runs scripts in the
|
||||
test/ folder to validate the core SQLite code. The testfixture program
|
||||
(and some other test programs too) is built and run when you type
|
||||
"make test".
|
||||
|
||||
* **ext/misc/json1.c** - This file implements the various JSON functions
|
||||
that are built into SQLite.
|
||||
|
||||
There are many other source files. Each has a succinct header comment that
|
||||
describes its purpose and role within the larger system.
|
||||
|
||||
@@ -326,8 +307,8 @@ describes its purpose and role within the larger system.
|
||||
## Verifying Code Authenticity
|
||||
|
||||
The `manifest` file at the root directory of the source tree
|
||||
contains either a SHA3-256 hash or a SHA1 hash
|
||||
for every source file in the repository.
|
||||
contains either a SHA3-256 hash (for newer files) or a SHA1 hash (for
|
||||
older files) for every source file in the repository.
|
||||
The name of the version of the entire source tree is just the
|
||||
SHA3-256 hash of the `manifest` file itself, possibly with the
|
||||
last line of that file omitted if the last line begins with
|
||||
@@ -335,25 +316,14 @@ last line of that file omitted if the last line begins with
|
||||
The `manifest.uuid` file should contain the SHA3-256 hash of the
|
||||
`manifest` file. If all of the above hash comparisons are correct, then
|
||||
you can be confident that your source tree is authentic and unadulterated.
|
||||
Details on the format for the `manifest` files are available
|
||||
[on the Fossil website](https://fossil-scm.org/fossil/doc/trunk/www/fileformat.wiki#manifest).
|
||||
|
||||
The process of checking source code authenticity is automated by the
|
||||
makefile:
|
||||
|
||||
> make verify-source
|
||||
|
||||
Or on windows:
|
||||
|
||||
> nmake /f Makefile.msc verify-source
|
||||
|
||||
Using the makefile to verify source integrity is good for detecting
|
||||
accidental changes to the source tree, but malicious changes could be
|
||||
hidden by also modifying the makefiles.
|
||||
The format of the `manifest` file should be mostly self-explanatory, but
|
||||
if you want details, they are available
|
||||
[here](https://fossil-scm.org/fossil/doc/trunk/www/fileformat.wiki#manifest).
|
||||
|
||||
## Contacts
|
||||
|
||||
The main SQLite website is [http:/sqlite.org/](http://sqlite.org/)
|
||||
The main SQLite website is [http://www.sqlite.org/](http://www.sqlite.org/)
|
||||
with geographically distributed backups at
|
||||
[http://www2.sqlite.org/](http://www2.sqlite.org) and
|
||||
[http://www3.sqlite.org/](http://www3.sqlite.org).
|
||||
|
||||
@@ -9,7 +9,7 @@ sqlite3_SOURCES = shell.c sqlite3.h
|
||||
EXTRA_sqlite3_SOURCES = sqlite3.c
|
||||
sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
|
||||
sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
|
||||
sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_DQS=0 -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)
|
||||
sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)
|
||||
|
||||
include_HEADERS = sqlite3.h sqlite3ext.h
|
||||
|
||||
|
||||
@@ -52,13 +52,6 @@ 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.
|
||||
#
|
||||
!IFNDEF USE_SEH
|
||||
USE_SEH = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to have the shell executable link against the core dynamic
|
||||
# link library.
|
||||
#
|
||||
@@ -187,12 +180,6 @@ WIN32HEAP = 0
|
||||
OSTRACE = 0
|
||||
!ENDIF
|
||||
|
||||
# enable address sanitizer using ASAN=1 on the command-line.
|
||||
#
|
||||
!IFNDEF ASAN
|
||||
ASAN = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this to one of the following values to enable various debugging
|
||||
# features. Each level includes the debugging options from the previous
|
||||
# levels. Currently, the recognized values for DEBUG are:
|
||||
@@ -296,7 +283,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
|
||||
@@ -325,14 +311,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
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.
|
||||
#
|
||||
!IF $(USE_SEH)==0
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_OMIT_SEH=1
|
||||
!ENDIF
|
||||
|
||||
# These are the "extended" SQLite compilation options used when compiling for
|
||||
# the Windows 10 platform.
|
||||
#
|
||||
@@ -740,13 +718,6 @@ RCC = $(RCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1
|
||||
!ENDIF
|
||||
|
||||
|
||||
# Address sanitizer if ASAN=1
|
||||
#
|
||||
!IF $(ASAN)>0
|
||||
TCC = $(TCC) /fsanitize=address
|
||||
!ENDIF
|
||||
|
||||
|
||||
# Compiler options needed for programs that use the readline() library.
|
||||
#
|
||||
!IFNDEF READLINE_FLAGS
|
||||
@@ -988,8 +959,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
|
||||
|
||||
|
||||
|
||||
@@ -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.42.0])
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
|
||||
|
||||
@@ -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.42.1.
|
||||
#
|
||||
#
|
||||
# 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.42.1'
|
||||
PACKAGE_STRING='sqlite 3.42.1'
|
||||
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.42.1 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.42.1:";;
|
||||
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.42.1
|
||||
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.42.1, 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.42.1, 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.42.1
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+2
-19
@@ -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"
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
# 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:
|
||||
|
||||
1. Install Microsoft Visual Studio. The free "community edition"
|
||||
will work fine. Do a standard install for C++ development.
|
||||
SQLite only needs the
|
||||
"cl" compiler and the "nmake" build tool.
|
||||
|
||||
2. Under the "Start" menu, find "All Apps" then go to "Visual Studio 20XX"
|
||||
and find "x64 Native Tools Command Prompt for VS 20XX". Pin that
|
||||
application to your task bar, as you will use it a lot. Bring up
|
||||
an instance of this command prompt and do all of the subsequent steps
|
||||
in that "x64 Native Tools" command prompt. (Or use "x86" if you want
|
||||
a 32-bit build.) The subsequent steps will not work in a vanilla
|
||||
DOS prompt. Nor will they work in PowerShell.
|
||||
|
||||
3. Install TCL development libraries. This note assumes that you will
|
||||
install the TCL development libraries in the "`c:\Tcl`" directory.
|
||||
Make adjustments
|
||||
if you want TCL installed somewhere else. SQLite needs both the
|
||||
"tclsh.exe" command-line tool as part of the build process, and
|
||||
the "tcl86.lib" library in order to run tests. You will need
|
||||
TCL version 8.6 or later.
|
||||
<ol type="a">
|
||||
<li>Get the TCL source archive, perhaps from
|
||||
[https://www.tcl.tk/software/tcltk/download.html](https://www.tcl.tk/software/tcltk/download.html).
|
||||
<li>Untar or unzip the source archive. CD into the "win/" subfolder
|
||||
of the source tree.
|
||||
<li>Run: `nmake /f makefile.vc release`
|
||||
<li>Run: `nmake /f makefile.vc INSTALLDIR=c:\Tcl install`
|
||||
<li>CD to `c:\Tcl\lib`. In that subfolder make a copy of the
|
||||
"`tcl86t.lib`" file to the alternative name "`tcl86.lib`"
|
||||
(omitting the second 't'). Leave the copy in the same directory
|
||||
as the original.
|
||||
<li>CD to `c:\Tcl\bin`. Make a copy of the "`tclsh86t.exe`"
|
||||
file into "`tclsh.exe`" (without the "86t") in the same directory.
|
||||
<li>Add `c:\Tcl\bin` to your %PATH%. To do this, go to Settings
|
||||
and search for "path". Select "edit environment variables for
|
||||
your account" and modify your default PATH accordingly.
|
||||
You will need to close and reopen your command prompts after
|
||||
making this change.
|
||||
</ol>
|
||||
|
||||
4. Download the SQLite source tree and unpack it. CD into the
|
||||
toplevel directory of the source tree.
|
||||
|
||||
5. Set the TCLDIR environment variable to point to your TCL installation.
|
||||
Like this:
|
||||
<ul>
|
||||
<li> `set TCLDIR=c:\Tcl`
|
||||
</ul>
|
||||
|
||||
6. Run the "`Makefile.msc`" makefile with an appropriate target.
|
||||
Examples:
|
||||
<ul>
|
||||
<li> `nmake /f makefile.msc`
|
||||
<li> `nmake /f makefile.msc sqlite3.c`
|
||||
<li> `nmake /f makefile.msc devtest`
|
||||
<li> `nmake /f makefile.msc releasetest`
|
||||
</ul>
|
||||
|
||||
## 32-bit Builds
|
||||
|
||||
Doing a 32-bit build is just like doing a 64-bit build with the
|
||||
following minor changes:
|
||||
|
||||
1. Use the "x86 Native Tools Command Prompt" instead of
|
||||
"x64 Native Tools Command Prompt". "**x86**" instead of "**x64**".
|
||||
|
||||
2. Use a different installation directory for TCL.
|
||||
The recommended directory is `c:\tcl32`. Thus you end up
|
||||
with two TCL builds:
|
||||
<ul>
|
||||
<li> `c:\tcl` ← 64-bit (the default)
|
||||
<li> `c:\tcl32` ← 32-bit
|
||||
</ul>
|
||||
|
||||
3. Ensure that `c:\tcl32\bin` comes before `c:\tcl\bin` on
|
||||
your PATH environment variable. You can achieve this using
|
||||
a command like:
|
||||
<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>
|
||||
+2
-2
@@ -1229,8 +1229,8 @@ first syntax error, of course, if there are no instances of the
|
||||
|
||||
<p>Lemon was originally written by Richard Hipp sometime in the late
|
||||
1980s on a Sun4 Workstation using K&R C.
|
||||
There was a companion LL(1) parser generator program named "Lime".
|
||||
The Lime source code has been lost.</p>
|
||||
There was a companion LL(1) parser generator program named "Lime", the
|
||||
source code to which as been lost.</p>
|
||||
|
||||
<p>The lemon.c source file was originally many separate files that were
|
||||
compiled together to generate the "lemon" executable. Sometime in the
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
@@ -545,8 +545,7 @@ int sqlite3Fts3InitAux(sqlite3 *db){
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
0 /* xIntegrity */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
int rc; /* Return code */
|
||||
|
||||
|
||||
@@ -362,8 +362,7 @@ int sqlite3Fts3InitTerm(sqlite3 *db){
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
0 /* xIntegrity */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
int rc; /* Return code */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
+8
-21
@@ -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++;
|
||||
|
||||
@@ -4356,7 +4347,6 @@ static int fts3IncrmergeLoad(
|
||||
|
||||
for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
|
||||
NodeReader reader;
|
||||
memset(&reader, 0, sizeof(reader));
|
||||
pNode = &pWriter->aNodeWriter[i];
|
||||
|
||||
if( pNode->block.a){
|
||||
@@ -4377,7 +4367,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;
|
||||
@@ -5227,7 +5217,7 @@ static u64 fts3ChecksumIndex(
|
||||
int rc;
|
||||
u64 cksum = 0;
|
||||
|
||||
if( *pRc ) return 0;
|
||||
assert( *pRc==SQLITE_OK );
|
||||
|
||||
memset(&filter, 0, sizeof(filter));
|
||||
memset(&csr, 0, sizeof(csr));
|
||||
@@ -5442,11 +5432,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 +5451,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;
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -263,7 +263,7 @@ struct Fts5PhraseIter {
|
||||
** See xPhraseFirstColumn above.
|
||||
*/
|
||||
struct Fts5ExtensionApi {
|
||||
int iVersion; /* Currently always set to 2 */
|
||||
int iVersion; /* Currently always set to 3 */
|
||||
|
||||
void *(*xUserData)(Fts5Context*);
|
||||
|
||||
@@ -492,8 +492,8 @@ struct Fts5ExtensionApi {
|
||||
** as separate queries of the FTS index are required for each synonym.
|
||||
**
|
||||
** When using methods (2) or (3), it is important that the tokenizer only
|
||||
** provide synonyms when tokenizing document text (method (3)) or query
|
||||
** text (method (2)), not both. Doing so will not cause any errors, but is
|
||||
** provide synonyms when tokenizing document text (method (2)) or query
|
||||
** text (method (3)), not both. Doing so will not cause any errors, but is
|
||||
** inefficient.
|
||||
*/
|
||||
typedef struct Fts5Tokenizer Fts5Tokenizer;
|
||||
@@ -541,7 +541,7 @@ struct fts5_api {
|
||||
int (*xCreateTokenizer)(
|
||||
fts5_api *pApi,
|
||||
const char *zName,
|
||||
void *pUserData,
|
||||
void *pContext,
|
||||
fts5_tokenizer *pTokenizer,
|
||||
void (*xDestroy)(void*)
|
||||
);
|
||||
@@ -550,7 +550,7 @@ struct fts5_api {
|
||||
int (*xFindTokenizer)(
|
||||
fts5_api *pApi,
|
||||
const char *zName,
|
||||
void **ppUserData,
|
||||
void **ppContext,
|
||||
fts5_tokenizer *pTokenizer
|
||||
);
|
||||
|
||||
@@ -558,7 +558,7 @@ struct fts5_api {
|
||||
int (*xCreateFunction)(
|
||||
fts5_api *pApi,
|
||||
const char *zName,
|
||||
void *pUserData,
|
||||
void *pContext,
|
||||
fts5_extension_function xFunction,
|
||||
void (*xDestroy)(void*)
|
||||
);
|
||||
|
||||
@@ -154,10 +154,6 @@ typedef struct Fts5Config Fts5Config;
|
||||
** attempt to merge together. A value of 1 sets the object to use the
|
||||
** compile time default. Zero disables auto-merge altogether.
|
||||
**
|
||||
** bContentlessDelete:
|
||||
** True if the contentless_delete option was present in the CREATE
|
||||
** VIRTUAL TABLE statement.
|
||||
**
|
||||
** zContent:
|
||||
**
|
||||
** zContentRowid:
|
||||
@@ -192,7 +188,6 @@ struct Fts5Config {
|
||||
int nPrefix; /* Number of prefix indexes */
|
||||
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
|
||||
int eContent; /* An FTS5_CONTENT value */
|
||||
int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
|
||||
char *zContent; /* content table */
|
||||
char *zContentRowid; /* "content_rowid=" option value */
|
||||
int bColumnsize; /* "columnsize=" option value (dflt==1) */
|
||||
@@ -214,7 +209,6 @@ struct Fts5Config {
|
||||
char *zRank; /* Name of rank function */
|
||||
char *zRankArgs; /* Arguments to rank function */
|
||||
int bSecureDelete; /* 'secure-delete' */
|
||||
int nDeleteMerge; /* 'deletemerge' */
|
||||
|
||||
/* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
|
||||
char **pzErrmsg;
|
||||
@@ -537,9 +531,6 @@ int sqlite3Fts5IndexReset(Fts5Index *p);
|
||||
|
||||
int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
|
||||
|
||||
int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin);
|
||||
int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid);
|
||||
|
||||
/*
|
||||
** End of interface to code in fts5_index.c.
|
||||
**************************************************************************/
|
||||
@@ -624,11 +615,6 @@ int sqlite3Fts5HashWrite(
|
||||
*/
|
||||
void sqlite3Fts5HashClear(Fts5Hash*);
|
||||
|
||||
/*
|
||||
** Return true if the hash is empty, false otherwise.
|
||||
*/
|
||||
int sqlite3Fts5HashIsEmpty(Fts5Hash*);
|
||||
|
||||
int sqlite3Fts5HashQuery(
|
||||
Fts5Hash*, /* Hash table to query */
|
||||
int nPre,
|
||||
@@ -650,7 +636,6 @@ void sqlite3Fts5HashScanEntry(Fts5Hash *,
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** End of interface to code in fts5_hash.c.
|
||||
**************************************************************************/
|
||||
|
||||
+12
-47
@@ -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{
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#define FTS5_DEFAULT_CRISISMERGE 16
|
||||
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
|
||||
|
||||
#define FTS5_DEFAULT_DELETE_AUTOMERGE 10 /* default 10% */
|
||||
|
||||
/* Maximum allowed page size */
|
||||
#define FTS5_MAX_PAGE_SIZE (64*1024)
|
||||
|
||||
@@ -354,16 +352,6 @@ static int fts5ConfigParseSpecial(
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( sqlite3_strnicmp("contentless_delete", zCmd, nCmd)==0 ){
|
||||
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
|
||||
*pzErr = sqlite3_mprintf("malformed contentless_delete=... directive");
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
pConfig->bContentlessDelete = (zArg[0]=='1');
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
|
||||
if( pConfig->zContentRowid ){
|
||||
*pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
|
||||
@@ -608,28 +596,6 @@ int sqlite3Fts5ConfigParse(
|
||||
sqlite3_free(zTwo);
|
||||
}
|
||||
|
||||
/* We only allow contentless_delete=1 if the table is indeed contentless. */
|
||||
if( rc==SQLITE_OK
|
||||
&& pRet->bContentlessDelete
|
||||
&& pRet->eContent!=FTS5_CONTENT_NONE
|
||||
){
|
||||
*pzErr = sqlite3_mprintf(
|
||||
"contentless_delete=1 requires a contentless table"
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* We only allow contentless_delete=1 if columnsize=0 is not present.
|
||||
**
|
||||
** This restriction may be removed at some point.
|
||||
*/
|
||||
if( rc==SQLITE_OK && pRet->bContentlessDelete && pRet->bColumnsize==0 ){
|
||||
*pzErr = sqlite3_mprintf(
|
||||
"contentless_delete=1 is incompatible with columnsize=0"
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* If a tokenizer= option was successfully parsed, the tokenizer has
|
||||
** already been allocated. Otherwise, allocate an instance of the default
|
||||
** tokenizer (unicode61) now. */
|
||||
@@ -924,18 +890,6 @@ int sqlite3Fts5ConfigSetValue(
|
||||
}
|
||||
}
|
||||
|
||||
else if( 0==sqlite3_stricmp(zKey, "deletemerge") ){
|
||||
int nVal = -1;
|
||||
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
|
||||
nVal = sqlite3_value_int(pVal);
|
||||
}else{
|
||||
*pbBadkey = 1;
|
||||
}
|
||||
if( nVal<0 ) nVal = FTS5_DEFAULT_DELETE_AUTOMERGE;
|
||||
if( nVal>100 ) nVal = 0;
|
||||
pConfig->nDeleteMerge = nVal;
|
||||
}
|
||||
|
||||
else if( 0==sqlite3_stricmp(zKey, "rank") ){
|
||||
const char *zIn = (const char*)sqlite3_value_text(pVal);
|
||||
char *zRank;
|
||||
@@ -984,7 +938,6 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
|
||||
pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
|
||||
pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
|
||||
pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
|
||||
pConfig->nDeleteMerge = FTS5_DEFAULT_DELETE_AUTOMERGE;
|
||||
|
||||
zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
|
||||
if( zSql ){
|
||||
|
||||
@@ -2477,7 +2477,7 @@ Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
||||
return pRet;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
|
||||
#ifdef SQLITE_TEST
|
||||
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
|
||||
sqlite3_int64 nByte = 0;
|
||||
Fts5ExprTerm *p;
|
||||
@@ -2583,8 +2583,6 @@ static char *fts5ExprPrintTcl(
|
||||
if( zRet==0 ) return 0;
|
||||
}
|
||||
|
||||
}else if( pExpr->eType==0 ){
|
||||
zRet = sqlite3_mprintf("{}");
|
||||
}else{
|
||||
char const *zOp = 0;
|
||||
int i;
|
||||
@@ -2846,14 +2844,14 @@ static void fts5ExprFold(
|
||||
sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics));
|
||||
}
|
||||
}
|
||||
#endif /* if SQLITE_TEST || SQLITE_FTS5_DEBUG */
|
||||
#endif /* ifdef SQLITE_TEST */
|
||||
|
||||
/*
|
||||
** This is called during initialization to register the fts5_expr() scalar
|
||||
** UDF with the SQLite handle passed as the only argument.
|
||||
*/
|
||||
int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
|
||||
#ifdef SQLITE_TEST
|
||||
struct Fts5ExprFunc {
|
||||
const char *z;
|
||||
void (*x)(sqlite3_context*,int,sqlite3_value**);
|
||||
|
||||
+5
-24
@@ -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,
|
||||
@@ -473,6 +475,7 @@ static int fts5HashEntrySort(
|
||||
pList = fts5HashEntryMerge(pList, ap[i]);
|
||||
}
|
||||
|
||||
pHash->nEntry = 0;
|
||||
sqlite3_free(ap);
|
||||
*ppSorted = pList;
|
||||
return SQLITE_OK;
|
||||
@@ -526,28 +529,6 @@ int sqlite3Fts5HashScanInit(
|
||||
return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int fts5HashCount(Fts5Hash *pHash){
|
||||
int nEntry = 0;
|
||||
int ii;
|
||||
for(ii=0; ii<pHash->nSlot; ii++){
|
||||
Fts5HashEntry *p = 0;
|
||||
for(p=pHash->aSlot[ii]; p; p=p->pHashNext){
|
||||
nEntry++;
|
||||
}
|
||||
}
|
||||
return nEntry;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return true if the hash table is empty, false otherwise.
|
||||
*/
|
||||
int sqlite3Fts5HashIsEmpty(Fts5Hash *pHash){
|
||||
assert( pHash->nEntry==fts5HashCount(pHash) );
|
||||
return pHash->nEntry==0;
|
||||
}
|
||||
|
||||
void sqlite3Fts5HashScanNext(Fts5Hash *p){
|
||||
assert( !sqlite3Fts5HashScanEof(p) );
|
||||
p->pScan = p->pScan->pScanNext;
|
||||
|
||||
+316
-1386
File diff suppressed because it is too large
Load Diff
+19
-131
@@ -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;
|
||||
@@ -1338,9 +1329,6 @@ static int fts5FilterMethod(
|
||||
pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
|
||||
}
|
||||
|
||||
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
|
||||
if( rc!=SQLITE_OK ) goto filter_out;
|
||||
|
||||
if( pTab->pSortCsr ){
|
||||
/* If pSortCsr is non-NULL, then this call is being made as part of
|
||||
** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
|
||||
@@ -1363,7 +1351,6 @@ 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 ){
|
||||
if( bOrderByRank ){
|
||||
@@ -1535,7 +1522,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 +1533,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 +1542,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 +1554,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 +1567,6 @@ static int fts5SpecialInsert(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && bLoadConfig ){
|
||||
pTab->p.pConfig->iCookie--;
|
||||
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1648,6 +1624,7 @@ static int fts5UpdateMethod(
|
||||
int eType0; /* value_type() of apVal[0] */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int bUpdateOrDelete = 0;
|
||||
|
||||
|
||||
/* A transaction must be open when this is called. */
|
||||
assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
|
||||
@@ -1677,14 +1654,7 @@ static int fts5UpdateMethod(
|
||||
if( pConfig->eContent!=FTS5_CONTENT_NORMAL
|
||||
&& 0==sqlite3_stricmp("delete", z)
|
||||
){
|
||||
if( pConfig->bContentlessDelete ){
|
||||
fts5SetVtabError(pTab,
|
||||
"'delete' may not be used with a contentless_delete=1 table"
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
rc = fts5SpecialDelete(pTab, apVal);
|
||||
}
|
||||
rc = fts5SpecialDelete(pTab, apVal);
|
||||
}else{
|
||||
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
|
||||
}
|
||||
@@ -1701,7 +1671,7 @@ static int fts5UpdateMethod(
|
||||
** Cases 3 and 4 may violate the rowid constraint.
|
||||
*/
|
||||
int eConflict = SQLITE_ABORT;
|
||||
if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->bContentlessDelete ){
|
||||
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
|
||||
eConflict = sqlite3_vtab_on_conflict(pConfig->db);
|
||||
}
|
||||
|
||||
@@ -1709,12 +1679,8 @@ 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
|
||||
** VIRTUAL TABLE statement contained "contentless_delete=1". */
|
||||
if( eType0==SQLITE_INTEGER
|
||||
&& pConfig->eContent==FTS5_CONTENT_NONE
|
||||
&& pConfig->bContentlessDelete==0
|
||||
){
|
||||
** This is not suported. */
|
||||
if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
|
||||
pTab->p.base.zErrMsg = sqlite3_mprintf(
|
||||
"cannot %s contentless fts5 table: %s",
|
||||
(nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
|
||||
@@ -1738,8 +1704,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);
|
||||
@@ -1802,7 +1767,8 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
|
||||
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
rc = sqlite3Fts5FlushToDisk(&pTab->p);
|
||||
fts5TripCursors(pTab);
|
||||
rc = sqlite3Fts5StorageSync(pTab->pStorage);
|
||||
pTab->p.pConfig->pzErrmsg = 0;
|
||||
return rc;
|
||||
}
|
||||
@@ -2569,12 +2535,6 @@ static int fts5ColumnMethod(
|
||||
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
|
||||
}
|
||||
pConfig->pzErrmsg = 0;
|
||||
}else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
|
||||
char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
|
||||
"columns on fts5 contentless-delete table: %s", pConfig->zName
|
||||
);
|
||||
sqlite3_result_error(pCtx, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -2613,12 +2573,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 +2588,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 +2599,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 +2611,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 +2835,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 +2860,7 @@ static int fts5Init(sqlite3 *db){
|
||||
/* xSavepoint */ fts5SavepointMethod,
|
||||
/* xRelease */ fts5ReleaseMethod,
|
||||
/* xRollbackTo */ fts5RollbackToMethod,
|
||||
/* xShadowName */ fts5ShadowName,
|
||||
/* xIntegrity */ fts5Integrity
|
||||
/* xShadowName */ fts5ShadowName
|
||||
};
|
||||
|
||||
int rc;
|
||||
|
||||
+13
-75
@@ -77,10 +77,10 @@ static int fts5StorageGetStmt(
|
||||
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
|
||||
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
|
||||
"DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
|
||||
"REPLACE INTO %Q.'%q_docsize' VALUES(?,?%s)", /* REPLACE_DOCSIZE */
|
||||
"REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */
|
||||
"DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */
|
||||
|
||||
"SELECT sz%s FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
|
||||
"SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
|
||||
|
||||
"REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
|
||||
"SELECT %s FROM %s AS T", /* SCAN */
|
||||
@@ -128,19 +128,6 @@ static int fts5StorageGetStmt(
|
||||
break;
|
||||
}
|
||||
|
||||
case FTS5_STMT_REPLACE_DOCSIZE:
|
||||
zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName,
|
||||
(pC->bContentlessDelete ? ",?" : "")
|
||||
);
|
||||
break;
|
||||
|
||||
case FTS5_STMT_LOOKUP_DOCSIZE:
|
||||
zSql = sqlite3_mprintf(azStmt[eStmt],
|
||||
(pC->bContentlessDelete ? ",origin" : ""),
|
||||
pC->zDb, pC->zName
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName);
|
||||
break;
|
||||
@@ -330,11 +317,9 @@ int sqlite3Fts5StorageOpen(
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
||||
const char *zCols = "id INTEGER PRIMARY KEY, sz BLOB";
|
||||
if( pConfig->bContentlessDelete ){
|
||||
zCols = "id INTEGER PRIMARY KEY, sz BLOB, origin INTEGER";
|
||||
}
|
||||
rc = sqlite3Fts5CreateTable(pConfig, "docsize", zCols, 0, pzErr);
|
||||
rc = sqlite3Fts5CreateTable(
|
||||
pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr
|
||||
);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5CreateTable(
|
||||
@@ -411,7 +396,7 @@ static int fts5StorageDeleteFromIndex(
|
||||
){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int rc; /* Return code */
|
||||
int rc2; /* sqlite3_reset() return code */
|
||||
int iCol;
|
||||
Fts5InsertCtx ctx;
|
||||
@@ -427,6 +412,7 @@ static int fts5StorageDeleteFromIndex(
|
||||
|
||||
ctx.pStorage = p;
|
||||
ctx.iCol = -1;
|
||||
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
|
||||
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
|
||||
if( pConfig->abUnindexed[iCol-1]==0 ){
|
||||
const char *zText;
|
||||
@@ -463,37 +449,6 @@ static int fts5StorageDeleteFromIndex(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called to process a DELETE on a contentless_delete=1
|
||||
** table. It adds the tombstone required to delete the entry with rowid
|
||||
** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs,
|
||||
** an SQLite error code.
|
||||
*/
|
||||
static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){
|
||||
i64 iOrigin = 0;
|
||||
sqlite3_stmt *pLookup = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( p->pConfig->bContentlessDelete );
|
||||
assert( p->pConfig->eContent==FTS5_CONTENT_NONE );
|
||||
|
||||
/* Look up the origin of the document in the %_docsize table. Store
|
||||
** this in stack variable iOrigin. */
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pLookup, 1, iDel);
|
||||
if( SQLITE_ROW==sqlite3_step(pLookup) ){
|
||||
iOrigin = sqlite3_column_int64(pLookup, 1);
|
||||
}
|
||||
rc = sqlite3_reset(pLookup);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && iOrigin!=0 ){
|
||||
rc = sqlite3Fts5IndexContentlessDelete(p->pIndex, iOrigin, iDel);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert a record into the %_docsize table. Specifically, do:
|
||||
@@ -514,17 +469,10 @@ static int fts5StorageInsertDocsize(
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pReplace, 1, iRowid);
|
||||
if( p->pConfig->bContentlessDelete ){
|
||||
i64 iOrigin = 0;
|
||||
rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
|
||||
sqlite3_bind_int64(pReplace, 3, iOrigin);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
|
||||
sqlite3_step(pReplace);
|
||||
rc = sqlite3_reset(pReplace);
|
||||
sqlite3_bind_null(pReplace, 2);
|
||||
}
|
||||
sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
|
||||
sqlite3_step(pReplace);
|
||||
rc = sqlite3_reset(pReplace);
|
||||
sqlite3_bind_null(pReplace, 2);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -588,15 +536,7 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
|
||||
|
||||
/* Delete the index records */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( p->pConfig->bContentlessDelete ){
|
||||
rc = fts5StorageContentlessDelete(p, iDel);
|
||||
}else{
|
||||
rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
|
||||
}
|
||||
rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
|
||||
}
|
||||
|
||||
/* Delete the %_docsize record */
|
||||
@@ -1184,9 +1124,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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
# 2023 May 28
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5bigid
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set nRow 20000
|
||||
|
||||
proc do_ascdesc_test {tn query} {
|
||||
set ::lAsc [db eval { SELECT rowid FROM x1($query) }]
|
||||
set ::lDesc [db eval { SELECT rowid FROM x1($query) ORDER BY rowid DESC }]
|
||||
do_test $tn.1 { lsort -integer $::lAsc } $::lAsc
|
||||
do_test $tn.2 { lsort -integer -decr $::lDesc } $::lDesc
|
||||
do_test $tn.3 { lsort -integer $::lDesc } $::lAsc
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(a);
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
for {set ii 0} {$ii < $nRow} {incr ii} {
|
||||
db eval {
|
||||
REPLACE INTO x1(rowid, a) VALUES(random(), 'movement at the station');
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
do_ascdesc_test 1.2 "the"
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
DELETE FROM x1
|
||||
}
|
||||
|
||||
do_test 1.4 {
|
||||
for {set ii 0} {$ii < $nRow} {incr ii} {
|
||||
db eval {
|
||||
INSERT INTO x1(rowid, a) VALUES(
|
||||
$ii + 0x6FFFFFFFFFFFFFFF, 'movement at the station'
|
||||
);
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
do_ascdesc_test 1.5 "movement"
|
||||
|
||||
finish_test
|
||||
@@ -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
|
||||
|
||||
@@ -294,3 +294,4 @@ do_catchsql_test 7.2.5 {
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
# 2014 Dec 20
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains tests for the content= and content_rowid= options.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5contentless
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Check that it is not possible to specify "contentless_delete=1" for
|
||||
# anything other than a contentless table.
|
||||
#
|
||||
set res(0) {0 {}}
|
||||
set res(1) {1 {contentless_delete=1 requires a contentless table}}
|
||||
foreach {tn sql bError} {
|
||||
1 "(a, b, contentless_delete=1)" 1
|
||||
2 "(a, b, contentless_delete=1, content=abc)" 1
|
||||
3 "(a, b, contentless_delete=1, content=)" 0
|
||||
4 "(content=, contentless_delete=1, a)" 0
|
||||
5 "(content='', contentless_delete=1, hello)" 0
|
||||
} {
|
||||
execsql { BEGIN }
|
||||
do_catchsql_test 1.$tn "CREATE VIRTUAL TABLE t1 USING fts5 $sql" $res($bError)
|
||||
execsql { ROLLBACK }
|
||||
}
|
||||
|
||||
# Check that it is not possible to specify "contentless_delete=1"
|
||||
# along with columnsize=1.
|
||||
#
|
||||
set res(0) {0 {}}
|
||||
set res(1) {1 {contentless_delete=1 is incompatible with columnsize=0}}
|
||||
foreach {tn sql bError} {
|
||||
2 "(a, b, content='', contentless_delete=1, columnsize=0)" 1
|
||||
} {
|
||||
execsql { BEGIN }
|
||||
do_catchsql_test 1.$tn "CREATE VIRTUAL TABLE t1 USING fts5 $sql" $res($bError)
|
||||
execsql { ROLLBACK }
|
||||
}
|
||||
|
||||
# Check that if contentless_delete=1 is specified, then the "origin"
|
||||
# column is added to the %_docsize table.
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(c, content='');
|
||||
CREATE VIRTUAL TABLE x2 USING fts5(c, content='', contentless_delete=1);
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
SELECT sql FROM sqlite_schema WHERE name IN ('x1_docsize', 'x2_docsize');
|
||||
} {
|
||||
{CREATE TABLE 'x1_docsize'(id INTEGER PRIMARY KEY, sz BLOB)}
|
||||
{CREATE TABLE 'x2_docsize'(id INTEGER PRIMARY KEY, sz BLOB, origin INTEGER)}
|
||||
}
|
||||
|
||||
do_execsql_test 3.2.1 {
|
||||
SELECT hex(block) FROM x1_data WHERE id=10
|
||||
} {00000000000000}
|
||||
do_execsql_test 3.2.2 {
|
||||
SELECT hex(block) FROM x2_data WHERE id=10
|
||||
} {00000000FF000001000000}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
INSERT INTO x2 VALUES('first text');
|
||||
INSERT INTO x2 VALUES('second text');
|
||||
}
|
||||
do_execsql_test 3.4 {
|
||||
SELECT id, origin FROM x2_docsize
|
||||
} {1 1 2 2}
|
||||
do_execsql_test 3.5 {
|
||||
SELECT level, segment, loc1, loc2 FROM fts5_structure(
|
||||
(SELECT block FROM x2_data WHERE id=10)
|
||||
)
|
||||
} {
|
||||
0 0 1 1
|
||||
0 1 2 2
|
||||
}
|
||||
do_execsql_test 3.6 {
|
||||
INSERT INTO x2(x2) VALUES('optimize');
|
||||
}
|
||||
do_execsql_test 3.7 {
|
||||
SELECT level, segment, loc1, loc2 FROM fts5_structure(
|
||||
(SELECT block FROM x2_data WHERE id=10)
|
||||
)
|
||||
} {
|
||||
1 0 1 2
|
||||
}
|
||||
|
||||
do_execsql_test 3.8 {
|
||||
DELETE FROM x2 WHERE rowid=2;
|
||||
}
|
||||
|
||||
do_execsql_test 3.9 {
|
||||
SELECT rowid FROM x2('text')
|
||||
} {1}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
reset_db
|
||||
proc document {n} {
|
||||
set vocab [list A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
|
||||
set ret [list]
|
||||
for {set ii 0} {$ii < $n} {incr ii} {
|
||||
lappend ret [lindex $vocab [expr int(rand()*[llength $vocab])]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
|
||||
set nRow 1000
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1(x);
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=1);
|
||||
INSERT INTO ft(ft, rank) VALUES('pgsz', 100);
|
||||
}
|
||||
do_test 4.1 {
|
||||
for {set ii 0} {$ii < $nRow} {incr ii} {
|
||||
set doc [document 6]
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES($doc);
|
||||
INSERT INTO ft VALUES($doc);
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
foreach v {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
|
||||
set L1 [execsql {SELECT rowid FROM t1 WHERE x LIKE '%'||$v||'%'}]
|
||||
set L2 [execsql {SELECT rowid FROM ft($v)}]
|
||||
do_test 4.2.$v { set L1 } $L2
|
||||
}
|
||||
|
||||
do_test 4.3 {
|
||||
for {set ii 1} {$ii < $nRow} {incr ii 2} {
|
||||
execsql {
|
||||
DELETE FROM ft WHERE rowid=$ii;
|
||||
DELETE FROM t1 WHERE rowid=$ii;
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
foreach v {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
|
||||
set L1 [execsql {SELECT rowid FROM t1 WHERE x LIKE '%'||$v||'%'}]
|
||||
set L2 [execsql {SELECT rowid FROM ft($v)}]
|
||||
do_test 4.4.$v { set L1 } $L2
|
||||
}
|
||||
|
||||
do_execsql_test 4.5 {
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
} {}
|
||||
|
||||
foreach v {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
|
||||
set L1 [execsql {SELECT rowid FROM t1 WHERE x LIKE '%'||$v||'%'}]
|
||||
set L2 [execsql {SELECT rowid FROM ft($v)}]
|
||||
do_test 4.6.$v { set L1 } $L2
|
||||
}
|
||||
|
||||
#execsql_pp { SELECT fts5_decode(id, block) FROM ft_data }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=1);
|
||||
INSERT INTO ft(rowid, x) VALUES(1, 'one two three');
|
||||
INSERT INTO ft(rowid, x) VALUES(2, 'one two four');
|
||||
INSERT INTO ft(rowid, x) VALUES(3, 'one two five');
|
||||
INSERT INTO ft(rowid, x) VALUES(4, 'one two seven');
|
||||
INSERT INTO ft(rowid, x) VALUES(5, 'one two eight');
|
||||
}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
DELETE FROM ft WHERE rowid=2
|
||||
}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
SELECT rowid FROM ft
|
||||
} {1 3 4 5}
|
||||
|
||||
do_catchsql_test 5.3 {
|
||||
UPDATE ft SET x='four six' WHERE rowid=3
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 5.4 {
|
||||
SELECT rowid FROM ft('one');
|
||||
} {1 4 5}
|
||||
|
||||
do_execsql_test 5.5 {
|
||||
REPLACE INTO ft(rowid, x) VALUES(3, 'four six');
|
||||
SELECT rowid FROM ft('one');
|
||||
} {1 4 5}
|
||||
|
||||
do_execsql_test 5.6 {
|
||||
REPLACE INTO ft(rowid, x) VALUES(6, 'one two eleven');
|
||||
SELECT rowid FROM ft('one');
|
||||
} {1 4 5 6}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=1);
|
||||
INSERT INTO ft(rowid, x) VALUES(1, 'one two three');
|
||||
INSERT INTO ft(rowid, x) VALUES(2, 'one two four');
|
||||
}
|
||||
|
||||
do_test 6.1 {
|
||||
db eval { SELECT rowid FROM ft('one two') } {
|
||||
if {$rowid==1} {
|
||||
db eval { INSERT INTO ft(rowid, x) VALUES(3, 'one two four') }
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=1);
|
||||
}
|
||||
|
||||
set lRowid [list -450 0 1 2 42]
|
||||
|
||||
do_test 7.1 {
|
||||
execsql BEGIN
|
||||
foreach r $lRowid {
|
||||
execsql { INSERT INTO ft(rowid, x) VALUES($r, 'one one one'); }
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
do_test 7.2 {
|
||||
execsql BEGIN
|
||||
foreach r $lRowid {
|
||||
execsql { REPLACE INTO ft(rowid, x) VALUES($r, 'two two two'); }
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
do_execsql_test 7.3 { SELECT rowid FROM ft('one'); } {}
|
||||
do_execsql_test 7.4 { SELECT rowid FROM ft('two'); } $lRowid
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=1);
|
||||
INSERT INTO ft VALUES('hello world');
|
||||
INSERT INTO ft VALUES('one two three');
|
||||
}
|
||||
|
||||
do_catchsql_test 8.1 {
|
||||
INSERT INTO ft(ft, rowid, x) VALUES('delete', 1, 'hello world');
|
||||
} {1 {'delete' may not be used with a contentless_delete=1 table}}
|
||||
|
||||
do_execsql_test 8.2 {
|
||||
BEGIN;
|
||||
INSERT INTO ft(rowid, x) VALUES(3, 'four four four');
|
||||
DELETE FROM ft WHERE rowid=3;
|
||||
COMMIT;
|
||||
SELECT rowid FROM ft('four');
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
@@ -1,207 +0,0 @@
|
||||
# 2023 July 19
|
||||
#
|
||||
# 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 tests for the content= and content_rowid= options.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5contentless2
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc vocab {} {
|
||||
list aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp
|
||||
}
|
||||
|
||||
proc document {nToken} {
|
||||
set doc [list]
|
||||
set vocab [vocab]
|
||||
for {set ii 0} {$ii < $nToken} {incr ii} {
|
||||
lappend doc [lindex $vocab [expr int(rand()*[llength $vocab])]]
|
||||
}
|
||||
set doc
|
||||
}
|
||||
db func document document
|
||||
|
||||
proc contains {doc token} {
|
||||
expr {[lsearch $doc $token]>=0}
|
||||
}
|
||||
db func contains contains
|
||||
|
||||
proc do_compare_tables_test {tn} {
|
||||
uplevel [list do_test $tn {
|
||||
foreach v [vocab] {
|
||||
set l1 [execsql { SELECT rowid FROM t1 WHERE contains(doc, $v) }]
|
||||
set l2 [execsql { SELECT rowid FROM t2($v) }]
|
||||
if {$l1!=$l2} { error "1: query mismatch ($l1) ($l2)" }
|
||||
|
||||
set w "[string range $v 0 1]*"
|
||||
set l1 [execsql { SELECT rowid FROM t1 WHERE contains(doc, $w) }]
|
||||
set l2 [execsql { SELECT rowid FROM t2($w) }]
|
||||
if {$l1!=$l2} { error "2: query mismatch ($l1) ($l2)" }
|
||||
|
||||
set w "[string range $v 0 0]*"
|
||||
set l1 [execsql { SELECT rowid FROM t1 WHERE contains(doc, $w) }]
|
||||
set l2 [execsql { SELECT rowid FROM t2($w) }]
|
||||
if {$l1!=$l2} { error "2: query mismatch ($l1) ($l2)" }
|
||||
|
||||
set l1 [execsql {
|
||||
SELECT rowid FROM t1 WHERE contains(doc, $v) ORDER BY rowid DESC
|
||||
}]
|
||||
set l2 [execsql { SELECT rowid FROM t2($v) ORDER BY rowid DESC }]
|
||||
if {$l1!=$l2} { error "1: query mismatch ($l1) ($l2)" }
|
||||
}
|
||||
set {} {}
|
||||
} {}]
|
||||
}
|
||||
|
||||
proc lshuffle {in} {
|
||||
set L [list]
|
||||
set ret [list]
|
||||
foreach elem $in { lappend L [list [expr rand()] $elem] }
|
||||
foreach pair [lsort -index 0 $L] { lappend ret [lindex $pair 1] }
|
||||
set ret
|
||||
}
|
||||
|
||||
expr srand(0)
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(
|
||||
doc, prefix=2, content=, contentless_delete=1
|
||||
);
|
||||
|
||||
CREATE TABLE t1(doc);
|
||||
CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
|
||||
DELETE FROM t2 WHERE rowid = old.rowid;
|
||||
END;
|
||||
}
|
||||
|
||||
set SMALLEST64 -9223372036854775808
|
||||
set LARGEST64 9223372036854775807
|
||||
|
||||
foreach {tn r1 r2} {
|
||||
1 0 50
|
||||
2 $SMALLEST64 $SMALLEST64+50
|
||||
3 $LARGEST64-50 $LARGEST64
|
||||
4 -50 -1
|
||||
} {
|
||||
set r1 [expr $r1]
|
||||
set r2 [expr $r2]
|
||||
|
||||
do_test 1.1.$tn {
|
||||
execsql BEGIN
|
||||
for {set ii $r1} {$ii <= $r2} {incr ii} {
|
||||
execsql { INSERT INTO t1(rowid, doc) VALUES ($ii, document(8)); }
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
}
|
||||
do_test 1.2 {
|
||||
db eval { SELECT rowid, doc FROM t1 } {
|
||||
execsql { INSERT INTO t2(rowid, doc) VALUES($rowid, $doc) }
|
||||
}
|
||||
} {}
|
||||
|
||||
foreach {tn rowid} {
|
||||
1 $SMALLEST64
|
||||
2 0
|
||||
3 -5
|
||||
4 -30
|
||||
5 $LARGEST64
|
||||
6 $LARGEST64-1
|
||||
} {
|
||||
set rowid [expr $rowid]
|
||||
do_execsql_test 1.3.$tn.1 {
|
||||
DELETE FROM t1 WHERE rowid=$rowid
|
||||
}
|
||||
do_compare_tables_test 1.3.$tn.2
|
||||
}
|
||||
|
||||
set iTest 1
|
||||
foreach r [lshuffle [execsql {SELECT rowid FROM t1}]] {
|
||||
if {($iTest % 50)==0} {
|
||||
execsql { INSERT INTO t2(t2) VALUES('optimize') }
|
||||
}
|
||||
if {($iTest % 5)==0} {
|
||||
execsql { INSERT INTO t2(t2, rank) VALUES('merge', 5) }
|
||||
}
|
||||
do_execsql_test 1.4.$iTest.1($r) {
|
||||
DELETE FROM t1 WHERE rowid=$r
|
||||
}
|
||||
do_compare_tables_test 1.4.$iTest.2
|
||||
incr iTest
|
||||
}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
SELECT * FROM t1
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
db func document document
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(doc, content=, contentless_delete=1);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
|
||||
)
|
||||
INSERT INTO t2(rowid, doc) SELECT i, i || ' ' || i FROM s;
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
BEGIN;
|
||||
DELETE FROM t2 WHERE rowid=32;
|
||||
DELETE FROM t2 WHERE rowid=64;
|
||||
DELETE FROM t2 WHERE rowid=96;
|
||||
DELETE FROM t2 WHERE rowid=128;
|
||||
DELETE FROM t2 WHERE rowid=160;
|
||||
DELETE FROM t2 WHERE rowid=192;
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT * FROM t2('128');
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
foreach {tn step} {
|
||||
1 3
|
||||
2 7
|
||||
3 15
|
||||
} {
|
||||
set step [expr $step]
|
||||
|
||||
reset_db
|
||||
db func document document
|
||||
do_execsql_test 3.$tn.0 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(doc, content=, contentless_delete=1);
|
||||
INSERT INTO t2(t2, rank) VALUES('pgsz', 100);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
|
||||
)
|
||||
INSERT INTO t2(rowid, doc) SELECT i, i || ' ' || i FROM s;
|
||||
}
|
||||
do_execsql_test 3.$tn.1 {
|
||||
DELETE FROM t2 WHERE (rowid % $step)==0
|
||||
}
|
||||
do_execsql_test 3.$tn.2 {
|
||||
SELECT * FROM t2( $step * 5 )
|
||||
} {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -1,195 +0,0 @@
|
||||
# 2023 July 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 contains tests for the content= and content_rowid= options.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5contentless3
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content=, contentless_delete=1);
|
||||
BEGIN;
|
||||
INSERT INTO ft VALUES('one one one');
|
||||
INSERT INTO ft VALUES('two two two');
|
||||
INSERT INTO ft VALUES('three three three');
|
||||
INSERT INTO ft VALUES('four four four');
|
||||
INSERT INTO ft VALUES('five five five');
|
||||
INSERT INTO ft VALUES('six six six');
|
||||
INSERT INTO ft VALUES('seven seven seven');
|
||||
INSERT INTO ft VALUES('eight eight eight');
|
||||
INSERT INTO ft VALUES('nine nine nine');
|
||||
COMMIT;
|
||||
|
||||
DELETE FROM ft WHERE rowid=3;
|
||||
}
|
||||
|
||||
proc myhex {hex} { binary decode hex $hex }
|
||||
db func myhex myhex
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
UPDATE ft_data SET block =
|
||||
myhex('04000000 00000001' ||
|
||||
'01020304 01020304 01020304 01020304' ||
|
||||
'01020304 01020304 01020304 01020304'
|
||||
)
|
||||
WHERE id = (SELECT max(id) FROM ft_data);
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
DELETE FROM ft WHERE rowid=1
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT rowid FROM ft('two');
|
||||
} {2}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
UPDATE ft_data SET block =
|
||||
myhex('08000000 00000001' ||
|
||||
'0000000001020304 0000000001020304 0000000001020304 0000000001020304' ||
|
||||
'0000000001020304 0000000001020304 0000000001020304 0000000001020304'
|
||||
)
|
||||
WHERE id = (SELECT max(id) FROM ft_data);
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT rowid FROM ft('two');
|
||||
} {2}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
DELETE FROM ft WHERE rowid=4
|
||||
}
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
UPDATE ft_data SET block = myhex('04000000 00000000')
|
||||
WHERE id = (SELECT max(id) FROM ft_data);
|
||||
}
|
||||
do_execsql_test 1.7 {
|
||||
SELECT rowid FROM ft('two');
|
||||
} {2}
|
||||
|
||||
do_execsql_test 1.8 {
|
||||
UPDATE ft_data SET block = myhex('04000000 00000000')
|
||||
WHERE id = (SELECT max(id) FROM ft_data);
|
||||
}
|
||||
do_execsql_test 1.9 {
|
||||
DELETE FROM ft WHERE rowid=8
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content=, contentless_delete=1);
|
||||
INSERT INTO ft VALUES('one one one');
|
||||
INSERT INTO ft VALUES('two two two');
|
||||
INSERT INTO ft VALUES('three three three');
|
||||
INSERT INTO ft VALUES('four four four');
|
||||
INSERT INTO ft VALUES('five five five');
|
||||
INSERT INTO ft VALUES('six six six');
|
||||
INSERT INTO ft VALUES('seven seven seven');
|
||||
INSERT INTO ft VALUES('eight eight eight');
|
||||
INSERT INTO ft VALUES('nine nine nine');
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
}
|
||||
do_execsql_test 2.2 {
|
||||
SELECT count(*) FROM ft_data
|
||||
} {3}
|
||||
do_execsql_test 2.3 {
|
||||
DELETE FROM ft WHERE rowid=5
|
||||
}
|
||||
do_execsql_test 2.4 {
|
||||
SELECT count(*) FROM ft_data
|
||||
} {4}
|
||||
|
||||
# Check that an 'optimize' works (rewrites the index) if there is a single
|
||||
# segment with one or more tombstone hash pages.
|
||||
do_execsql_test 2.5 {
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
}
|
||||
do_execsql_test 2.6 {
|
||||
SELECT count(*) FROM ft_data
|
||||
} {3}
|
||||
|
||||
# Check that an 'optimize' is a no-op if there is a single segment
|
||||
# and no tombstone hash pages.
|
||||
do_execsql_test 2.7 {
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
SELECT rowid FROM ft_data;
|
||||
} [db eval {SELECT rowid FROM ft_data}]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content=, contentless_delete=1);
|
||||
INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
|
||||
)
|
||||
INSERT INTO ft(rowid, x) SELECT i, i||' '||i||' '||i||' '||i FROM s;
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
SELECT count(*) FROM ft_data
|
||||
} {200}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
DELETE FROM ft WHERE (rowid % 50)==0;
|
||||
SELECT count(*) FROM ft_data;
|
||||
} {203}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
INSERT INTO ft(ft, rank) VALUES('merge', 500);
|
||||
SELECT rowid FROM ft_data;
|
||||
} [db eval {SELECT rowid FROM ft_data}]
|
||||
|
||||
do_execsql_test 3.4 {
|
||||
INSERT INTO ft(ft, rank) VALUES('merge', -1000);
|
||||
SELECT count(*) FROM ft_data;
|
||||
} {197}
|
||||
|
||||
do_execsql_test 3.5 {
|
||||
DELETE FROM ft WHERE (rowid % 50)==1;
|
||||
SELECT count(*) FROM ft_data;
|
||||
} {200}
|
||||
|
||||
do_execsql_test 3.6 {
|
||||
SELECT level, segment, npgtombstone FROM fts5_structure(
|
||||
(SELECT block FROM ft_data WHERE id=10)
|
||||
)
|
||||
} {1 0 3}
|
||||
|
||||
do_test 3.6 {
|
||||
while 1 {
|
||||
set nChange [db total_changes]
|
||||
execsql { INSERT INTO ft(ft, rank) VALUES('merge', -5) }
|
||||
if {([db total_changes] - $nChange)<2} break
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 3.7 {
|
||||
SELECT level, segment, npgtombstone FROM fts5_structure(
|
||||
(SELECT block FROM ft_data WHERE id=10)
|
||||
)
|
||||
} {2 0 0}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -1,247 +0,0 @@
|
||||
# 2023 July 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 contains tests for the content= and content_rowid= options.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5contentless4
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc document {n} {
|
||||
set vocab [list A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
|
||||
set ret [list]
|
||||
for {set ii 0} {$ii < $n} {incr ii} {
|
||||
lappend ret [lindex $vocab [expr int(rand()*[llength $vocab])]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db func document document
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=1);
|
||||
INSERT INTO ft(ft, rank) VALUES('pgsz', 240);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
|
||||
)
|
||||
INSERT INTO ft SELECT document(12) FROM s;
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
INSERT INTO ft(ft) VALUES('optimize');
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT level, segment, nentry, nentrytombstone FROM fts5_structure((
|
||||
SELECT block FROM ft_data WHERE id=10
|
||||
))
|
||||
} {0 0 1000 0}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
DELETE FROM ft WHERE rowid < 50
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT level, segment, nentry, nentrytombstone FROM fts5_structure((
|
||||
SELECT block FROM ft_data WHERE id=10
|
||||
))
|
||||
} {0 0 1000 49}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
DELETE FROM ft WHERE rowid < 1000
|
||||
}
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
SELECT level, segment, nentry, nentrytombstone FROM fts5_structure((
|
||||
SELECT block FROM ft_data WHERE id=10
|
||||
))
|
||||
} {1 0 1 0}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
reset_db
|
||||
db func document document
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=1);
|
||||
}
|
||||
|
||||
do_test 2.1 {
|
||||
for {set ii 0} {$ii < 5000} {incr ii} {
|
||||
execsql { INSERT INTO ft VALUES( document(12) ) }
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT sum(nentry) - sum(nentrytombstone) FROM fts5_structure((
|
||||
SELECT block FROM ft_data WHERE id=10
|
||||
))
|
||||
} {5000}
|
||||
|
||||
for {set ii 5000} {$ii >= 0} {incr ii -100} {
|
||||
do_execsql_test 2.3.$ii {
|
||||
DELETE FROM ft WHERE rowid > $ii
|
||||
}
|
||||
do_execsql_test 2.3.$ii.2 {
|
||||
SELECT
|
||||
CAST((total(nentry) - total(nentrytombstone)) AS integer)
|
||||
FROM
|
||||
fts5_structure( (SELECT block FROM ft_data WHERE id=10) )
|
||||
} $ii
|
||||
}
|
||||
|
||||
execsql_pp {
|
||||
SELECT * FROM fts5_structure((
|
||||
SELECT block FROM ft_data WHERE id=10
|
||||
))
|
||||
}
|
||||
|
||||
do_test 2.4 {
|
||||
for {set ii 0} {$ii < 5000} {incr ii} {
|
||||
execsql { INSERT INTO ft VALUES( document(12) ) }
|
||||
}
|
||||
} {}
|
||||
|
||||
for {set ii 1} {$ii <= 5000} {incr ii 10} {
|
||||
do_execsql_test 2.3.$ii {
|
||||
DELETE FROM ft WHERE rowid = $ii;
|
||||
INSERT INTO ft VALUES( document(12) );
|
||||
INSERT INTO ft(ft, rank) VALUES('merge', -10);
|
||||
}
|
||||
|
||||
do_execsql_test 2.3.$ii.2 {
|
||||
SELECT
|
||||
CAST((total(nentry) - total(nentrytombstone)) AS integer)
|
||||
FROM
|
||||
fts5_structure( (SELECT block FROM ft_data WHERE id=10) )
|
||||
} 5000
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
db func document document
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=1);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO ft SELECT document(12) FROM s;
|
||||
}
|
||||
|
||||
do_catchsql_test 3.1 {
|
||||
INSERT INTO ft(ft, rank) VALUES('deletemerge', 'text');
|
||||
} {1 {SQL logic error}}
|
||||
do_catchsql_test 3.2 {
|
||||
INSERT INTO ft(ft, rank) VALUES('deletemerge', 50);
|
||||
} {0 {}}
|
||||
do_execsql_test 3.3 {
|
||||
SELECT * FROM ft_config WHERE k='deletemerge'
|
||||
} {deletemerge 50}
|
||||
do_catchsql_test 3.4 {
|
||||
INSERT INTO ft(ft, rank) VALUES('deletemerge', 101);
|
||||
} {0 {}}
|
||||
do_execsql_test 3.5 {
|
||||
SELECT * FROM ft_config WHERE k='deletemerge'
|
||||
} {deletemerge 101}
|
||||
|
||||
do_execsql_test 3.6 {
|
||||
DELETE FROM ft WHERE rowid<95
|
||||
}
|
||||
|
||||
do_execsql_test 3.7 {
|
||||
SELECT nentrytombstone, nentry FROM fts5_structure((
|
||||
SELECT block FROM ft_data WHERE id=10
|
||||
))
|
||||
} {94 100}
|
||||
|
||||
do_execsql_test 3.8 {
|
||||
DELETE FROM ft WHERE rowid=95
|
||||
}
|
||||
|
||||
do_execsql_test 3.9 {
|
||||
SELECT nentrytombstone, nentry FROM fts5_structure((
|
||||
SELECT block FROM ft_data WHERE id=10
|
||||
))
|
||||
} {95 100}
|
||||
|
||||
do_execsql_test 3.10 {
|
||||
DELETE FROM ft;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO ft SELECT document(12) FROM s;
|
||||
INSERT INTO ft(ft, rank) VALUES('deletemerge', 50);
|
||||
}
|
||||
|
||||
do_execsql_test 3.11 {
|
||||
DELETE FROM ft WHERE rowid<95
|
||||
}
|
||||
|
||||
do_execsql_test 3.12 {
|
||||
SELECT nentrytombstone, nentry FROM fts5_structure((
|
||||
SELECT block FROM ft_data WHERE id=10
|
||||
))
|
||||
} {0 6}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
db func document document
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(x, content='', contentless_delete=1);
|
||||
INSERT INTO x1(x1, rank) VALUES('usermerge', 16);
|
||||
INSERT INTO x1(x1, rank) VALUES('deletemerge', 40);
|
||||
INSERT INTO x1 VALUES('one');
|
||||
INSERT INTO x1 VALUES('two');
|
||||
INSERT INTO x1 VALUES('three');
|
||||
INSERT INTO x1 VALUES('four');
|
||||
INSERT INTO x1 VALUES('five');
|
||||
INSERT INTO x1 VALUES('six');
|
||||
INSERT INTO x1 VALUES('seven');
|
||||
INSERT INTO x1 VALUES('eight');
|
||||
INSERT INTO x1 VALUES('nine');
|
||||
INSERT INTO x1 VALUES('ten');
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
SELECT level, segment FROM fts5_structure((
|
||||
SELECT block FROM x1_data WHERE id=10
|
||||
))
|
||||
} {
|
||||
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9
|
||||
}
|
||||
|
||||
for {set ii 1} {$ii < 4} {incr ii} {
|
||||
do_execsql_test 4.2.$ii {
|
||||
DELETE FROM x1 WHERE rowid = $ii;
|
||||
INSERT INTO x1(x1, rank) VALUES('merge', 5);
|
||||
SELECT level, segment FROM fts5_structure((
|
||||
SELECT block FROM x1_data WHERE id=10
|
||||
))
|
||||
} {
|
||||
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
DELETE FROM x1 WHERE rowid = $ii;
|
||||
INSERT INTO x1(x1, rank) VALUES('merge', 5);
|
||||
SELECT level, segment, nentry FROM fts5_structure((
|
||||
SELECT block FROM x1_data WHERE id=10
|
||||
))
|
||||
} {
|
||||
1 0 6
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -1,58 +0,0 @@
|
||||
# 2023 August 7
|
||||
#
|
||||
# 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 tests for the content= and content_rowid= options.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5contentless5
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, content='', contentless_delete=1);
|
||||
INSERT INTO t1 VALUES('A', 'B', 'C');
|
||||
INSERT INTO t1 VALUES('D', 'E', 'F');
|
||||
INSERT INTO t1 VALUES('G', 'H', 'I');
|
||||
}
|
||||
|
||||
do_execsql_test 1.01 {
|
||||
CREATE TABLE t2(x, y);
|
||||
INSERT INTO t2 VALUES('x', 'y');
|
||||
}
|
||||
|
||||
# explain_i "UPDATE t1 SET a='a' WHERE t1.rowid=1"
|
||||
breakpoint
|
||||
explain_i "UPDATE t1 SET a='a' FROM t2 WHERE t1.rowid=1 AND b IS NULL"
|
||||
|
||||
#breakpoint
|
||||
#explain_i "UPDATE t1 SET a='a' WHERE b IS NULL AND rowid=?"
|
||||
|
||||
foreach {tn up err} {
|
||||
1 "UPDATE t1 SET a='a', b='b', c='c' WHERE rowid=1" 0
|
||||
2 "UPDATE t1 SET a='a', b='b' WHERE rowid=1" 1
|
||||
3 "UPDATE t1 SET b='b', c='c' WHERE rowid=1" 1
|
||||
4 "UPDATE t1 SET a='a', c='c' WHERE rowid=1" 1
|
||||
5 "UPDATE t1 SET a='a', c='c' WHERE t1.rowid=1 AND b IS NULL" 1
|
||||
6 "UPDATE t1 SET a='a' FROM t2 WHERE t1.rowid=1" 1
|
||||
7 "UPDATE t1 SET a='a', b='b', c='c' FROM t2 WHERE t1.rowid=1" 0
|
||||
} {
|
||||
|
||||
set res(0) {0 {}}
|
||||
set res(1) {1 {cannot UPDATE a subset of columns on fts5 contentless-delete table: t1}}
|
||||
do_catchsql_test 1.$tn $up $res($err)
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5corrupt5
|
||||
set testprefix fts5corrupt3
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
@@ -793,179 +793,6 @@ do_catchsql_test 4.5 {
|
||||
REPLACE INTO t1(rowid,a,b,rowid) VALUES(200,1,2,3);
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 5.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 28672 pagesize 4096 filename crash-0c6d3451d11597.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 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 04 ................
|
||||
| 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 59 20 4b 45 59 2c 20 63 R PRIMARY 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 00 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 00 00 1e 06 30 61 62 61 ......N.....0aba
|
||||
| 4048: 63 6b 01 02 02 04 02 66 74 02 02 02 04 04 6e 64 ck.....ft.....nd
|
||||
| 4064: 6f 6e 03 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 00 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 f4 0f ee 00 00 ................
|
||||
| 16: 00 00 01 00 00 00 00 00 00 00 00 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 f4 10 e1 0f d6 00 00 ................
|
||||
| 16: 00 00 00 01 00 00 00 00 00 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...
|
||||
| end crash-0c6d3451d11597.db
|
||||
}]} {}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
|
||||
}
|
||||
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
|
||||
|
||||
|
||||
@@ -95,9 +95,6 @@ do_execsql_test 3.3 {
|
||||
SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"/" OR "just"' ORDER BY rank;
|
||||
} {1 -1e-06}
|
||||
|
||||
do_execsql_test 3.4 "
|
||||
SELECT fts5_expr_tcl('e AND \" \"');
|
||||
" {{AND [nearset -- {e}] [{}]}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
# 2023 July 20
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
# This file is focused on OOM errors. Particularly those that may occur
|
||||
# when using contentless_delete=1 databases.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix fts5faultF
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
faultsim_save_and_close
|
||||
do_faultsim_test 1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, y, content=, contentless_delete=1)
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}}
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(doc, content=, contentless_delete=1);
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, doc) VALUES(1, 'a b c d');
|
||||
INSERT INTO t1(rowid, doc) VALUES(2, 'a b c d');
|
||||
INSERT INTO t1(rowid, doc) VALUES(3, 'a b c d');
|
||||
INSERT INTO t1(rowid, doc) VALUES(4, 'a b c d');
|
||||
COMMIT;
|
||||
DELETE FROM t1 WHERE rowid IN (2, 4);
|
||||
}
|
||||
|
||||
do_faultsim_test 2 -prep {
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT rowid FROM t1 }
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT rowid FROM t1('b c');
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 3}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(doc, content=, contentless_delete=1);
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, doc) VALUES(1, 'a b c d');
|
||||
INSERT INTO t1(rowid, doc) VALUES(2, 'a b c d');
|
||||
INSERT INTO t1(rowid, doc) VALUES(3, 'a b c d');
|
||||
INSERT INTO t1(rowid, doc) VALUES(4, 'a b c d');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
faultsim_save_and_close
|
||||
do_faultsim_test 3 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql { SELECT rowid FROM t1 }
|
||||
} -body {
|
||||
execsql {
|
||||
INSERT INTO t1(rowid, doc) VALUES(5, 'a b c d');
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(doc, content=, contentless_delete=1);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
|
||||
)
|
||||
INSERT INTO t1(rowid, doc) SELECT i, 'a b c d' FROM s;
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 { DELETE FROM t1 WHERE rowid <= 25 }
|
||||
|
||||
faultsim_save_and_close
|
||||
do_faultsim_test 4 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql { SELECT rowid FROM t1 }
|
||||
} -body {
|
||||
execsql {
|
||||
DELETE FROM t1 WHERE rowid < 100
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -44,12 +44,12 @@ do_catchsql_test 1.2.2 {
|
||||
|
||||
do_catchsql_test 1.3.1 {
|
||||
SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads');
|
||||
} {1 {no such cursor: 2}}
|
||||
} {1 {no such cursor: 1}}
|
||||
|
||||
do_catchsql_test 1.3.2 {
|
||||
SELECT a FROM t1
|
||||
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads'));
|
||||
} {1 {no such cursor: 2}}
|
||||
} {1 {no such cursor: 1}}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -180,28 +180,4 @@ do_execsql_test 6.1 {
|
||||
{table table table} {the table names.} {rank on an fts5 table}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# forum post: https://sqlite.org/forum/forumpost/a2dd636330
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t USING fts5 (a, b);
|
||||
INSERT INTO t (a, b) VALUES ('data1', 'sentence1'), ('data2', 'sentence2');
|
||||
INSERT INTO t(t, rank) VALUES ('rank', 'bm25(10.0,1.0)');
|
||||
}
|
||||
|
||||
sqlite3 db2 test.db
|
||||
do_execsql_test -db db2 1.1 {
|
||||
SELECT *, rank<0.0 FROM t('data*') ORDER BY RANK;
|
||||
} {data1 sentence1 1 data2 sentence2 1}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t(t, rank) VALUES ('rank', 'bm25(10.0,1.0)');
|
||||
}
|
||||
do_execsql_test -db db2 1.3 {
|
||||
SELECT *, rank<0.0 FROM t('data*') ORDER BY RANK;
|
||||
} {data1 sentence1 1 data2 sentence2 1}
|
||||
db2 close
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -86,71 +86,76 @@ do_execsql_test 2.8 {
|
||||
# Tests with large/small rowid values.
|
||||
#
|
||||
|
||||
reset_db
|
||||
|
||||
expr srand(0)
|
||||
|
||||
set vocab {
|
||||
Popper Poppins Popsicle Porfirio Porrima Porsche
|
||||
Porter Portia Portland Portsmouth Portugal Portuguese
|
||||
Poseidon Post PostgreSQL Potemkin Potomac Potsdam
|
||||
Pottawatomie Potter Potts Pound Poussin Powell
|
||||
PowerPC PowerPoint Powers Powhatan Poznan Prada
|
||||
Prado Praetorian Prague Praia Prakrit Pratchett
|
||||
Pratt Pravda Praxiteles Preakness Precambrian Preminger
|
||||
Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
|
||||
}
|
||||
proc newdoc {} {
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
|
||||
foreach {tn cfg} {
|
||||
1 ""
|
||||
2 "INSERT INTO fff(fff, rank) VALUES('secure-delete', 1)"
|
||||
} {
|
||||
reset_db
|
||||
|
||||
expr srand(0)
|
||||
|
||||
set vocab {
|
||||
Popper Poppins Popsicle Porfirio Porrima Porsche
|
||||
Porter Portia Portland Portsmouth Portugal Portuguese
|
||||
Poseidon Post PostgreSQL Potemkin Potomac Potsdam
|
||||
Pottawatomie Potter Potts Pound Poussin Powell
|
||||
PowerPC PowerPoint Powers Powhatan Poznan Prada
|
||||
Prado Praetorian Prague Praia Prakrit Pratchett
|
||||
Pratt Pravda Praxiteles Preakness Precambrian Preminger
|
||||
Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db func newdoc newdoc
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE fff USING fts5(y);
|
||||
INSERT INTO fff(fff, rank) VALUES('pgsz', 64);
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
INSERT INTO fff(fff, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
proc lshuffle {in} {
|
||||
set out [list]
|
||||
while {[llength $in]>0} {
|
||||
set idx [expr int(abs(rand()) * [llength $in])]
|
||||
lappend out [lindex $in $idx]
|
||||
set in [lreplace $in $idx $idx]
|
||||
}
|
||||
set out
|
||||
}
|
||||
|
||||
#dump fff
|
||||
|
||||
set iTest 1
|
||||
foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
|
||||
#if {$iTest==1} { dump fff }
|
||||
#if {$iTest==1} { breakpoint }
|
||||
do_execsql_test 3.1.$iTest.$ii {
|
||||
DELETE FROM fff WHERE rowid=$ii;
|
||||
}
|
||||
#if {$iTest==1} { dump fff }
|
||||
if {($iTest % 20)==0} {
|
||||
do_execsql_test 3.1.$iTest.$ii.ic {
|
||||
INSERT INTO fff(fff) VALUES('integrity-check');
|
||||
proc newdoc {} {
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db func newdoc newdoc
|
||||
|
||||
do_execsql_test 3.$tn.0 {
|
||||
CREATE VIRTUAL TABLE fff USING fts5(y);
|
||||
INSERT INTO fff(fff, rank) VALUES('pgsz', 64);
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
}
|
||||
|
||||
execsql $cfg
|
||||
|
||||
proc lshuffle {in} {
|
||||
set out [list]
|
||||
while {[llength $in]>0} {
|
||||
set idx [expr int(abs(rand()) * [llength $in])]
|
||||
lappend out [lindex $in $idx]
|
||||
set in [lreplace $in $idx $idx]
|
||||
}
|
||||
set out
|
||||
}
|
||||
|
||||
#dump fff
|
||||
|
||||
set iTest 1
|
||||
foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
|
||||
#if {$iTest==1} { dump fff }
|
||||
#if {$iTest==1} { breakpoint }
|
||||
do_execsql_test 3.$tn.1.$iTest.$ii {
|
||||
DELETE FROM fff WHERE rowid=$ii;
|
||||
}
|
||||
#if {$iTest==1} { dump fff }
|
||||
if {($iTest % 20)==0} {
|
||||
do_execsql_test 3.$tn.1.$iTest.$ii.ic {
|
||||
INSERT INTO fff(fff) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
#if {$iTest==1} { break }
|
||||
incr iTest
|
||||
}
|
||||
#if {$iTest==1} { break }
|
||||
incr iTest
|
||||
}
|
||||
|
||||
#execsql_pp { SELECT rowid FROM fff('post') ORDER BY rowid ASC }
|
||||
|
||||
@@ -73,6 +73,46 @@ do_execsql_test 2.2 {
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', $sd)
|
||||
}
|
||||
|
||||
do_execsql_test 2.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 2.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', $sd)
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, x) VALUES(-100000, 'abc def ghi');
|
||||
INSERT INTO t1(rowid, x) VALUES(-99999, 'abc def ghi');
|
||||
INSERT INTO t1(rowid, x) VALUES(9223372036854775800, 'abc def ghi');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -109,33 +149,5 @@ 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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -122,9 +122,6 @@ foreach {tn expr} {
|
||||
4.1 "NEAR(one two, 2)"
|
||||
4.2 "NEAR(one two three, 2)"
|
||||
4.3 "NEAR(eight nine, 1) OR NEAR(six seven, 1)"
|
||||
|
||||
5.1 "one + two"
|
||||
5.2 "1 + two"
|
||||
} {
|
||||
if {[fts5_expr_ok $expr ss]==0} {
|
||||
do_test 1.$tok.$tn.OMITTED { list } [list]
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -1,505 +0,0 @@
|
||||
# Quick-and-dirty makefile to bootstrap the sqlite3-jni project. This
|
||||
# build assumes a Linux-like system.
|
||||
default: all
|
||||
|
||||
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
|
||||
ifeq (,$(wildcard $(JDK_HOME)))
|
||||
$(error set JDK_HOME to the top-most dir of your JDK installation.)
|
||||
endif
|
||||
MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
$(MAKEFILE):
|
||||
|
||||
package.jar := sqlite3-jni.jar
|
||||
|
||||
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.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
|
||||
|
||||
classpath := $(dir.src)
|
||||
CLEAN_FILES := $(package.jar)
|
||||
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)
|
||||
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.
|
||||
enable.fts5 ?= 1
|
||||
|
||||
ifeq (,$(wildcard $(dir.tests)/*))
|
||||
enable.tester := 0
|
||||
else
|
||||
enable.tester := 1
|
||||
endif
|
||||
|
||||
# bin.version-info = binary to output various sqlite3 version info
|
||||
# building the distribution zip file.
|
||||
bin.version-info := $(dir.top)/version-info
|
||||
.NOTPARALLEL: $(bin.version-info)
|
||||
$(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
|
||||
$(MAKE) -C $(dir.top) version-info
|
||||
|
||||
# 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 \
|
||||
NativePointerHolder.java \
|
||||
OutputPointer.java \
|
||||
PrepareMultiCallback.java \
|
||||
PreupdateHookCallback.java \
|
||||
ProgressHandlerCallback.java \
|
||||
ResultCode.java \
|
||||
RollbackHookCallback.java \
|
||||
ScalarFunction.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_stmt.java \
|
||||
sqlite3_value.java \
|
||||
) $(patsubst %,$(dir.src.jni)/wrapper1/%,\
|
||||
AggregateFunction.java \
|
||||
ScalarFunction.java \
|
||||
SqlFunction.java \
|
||||
Sqlite.java \
|
||||
SqliteException.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)/%,\
|
||||
fts5_api.java \
|
||||
fts5_extension_function.java \
|
||||
fts5_tokenizer.java \
|
||||
Fts5.java \
|
||||
Fts5Context.java \
|
||||
Fts5ExtensionApi.java \
|
||||
Fts5PhraseIter.java \
|
||||
Fts5Tokenizer.java \
|
||||
XTokenizeCallback.java \
|
||||
)
|
||||
endif
|
||||
JAVA_FILES.tester := $(SQLTester.java)
|
||||
JAVA_FILES.package.info := \
|
||||
$(dir.src.jni)/package-info.java \
|
||||
$(dir.src.jni)/annotation/package-info.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)
|
||||
ifeq (1,$(enable.tester))
|
||||
JAVA_FILES += $(JAVA_FILES.tester)
|
||||
endif
|
||||
|
||||
CLASS_FILES :=
|
||||
define CLASSFILE_DEPS
|
||||
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)
|
||||
$(bin.javac) $(javac.flags) -h $(dir.bld.c) -cp $(classpath) $(JAVA_FILES)
|
||||
|
||||
#.PHONY: classfiles
|
||||
|
||||
########################################################################
|
||||
# Set up sqlite3.c and sqlite3.h...
|
||||
#
|
||||
# To build with SEE (https://sqlite.org/see), either put sqlite3-see.c
|
||||
# in the top of this build tree or pass
|
||||
# sqlite3.c=PATH_TO_sqlite3-see.c to the build. Note that only
|
||||
# encryption modules with no 3rd-party dependencies will currently
|
||||
# work here: AES256-OFB, AES128-OFB, and AES128-CCM. Not
|
||||
# coincidentally, those 3 modules are included in the sqlite3-see.c
|
||||
# bundle.
|
||||
#
|
||||
# A custom sqlite3.c must not have any spaces in its name.
|
||||
# $(sqlite3.canonical.c) must point to the sqlite3.c in
|
||||
# the sqlite3 canonical source tree, as that source file
|
||||
# is required for certain utility and test code.
|
||||
sqlite3.canonical.c := $(firstword $(wildcard $(dir.src.c)/sqlite3.c) $(dir.top)/sqlite3.c)
|
||||
sqlite3.canonical.h := $(firstword $(wildcard $(dir.src.c)/sqlite3.h) $(dir.top)/sqlite3.h)
|
||||
sqlite3.c := $(sqlite3.canonical.c)
|
||||
sqlite3.h := $(sqlite3.canonical.h)
|
||||
#ifeq (,$(shell grep sqlite3_activate_see $(sqlite3.c) 2>/dev/null))
|
||||
# SQLITE_C_IS_SEE := 0
|
||||
#else
|
||||
# SQLITE_C_IS_SEE := 1
|
||||
# $(info This is an SEE build.)
|
||||
#endif
|
||||
|
||||
.NOTPARALLEL: $(sqlite3.h)
|
||||
$(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_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
|
||||
|
||||
ifeq (1,$(opt.debug))
|
||||
SQLITE_OPT += -DSQLITE_DEBUG -g -DDEBUG -UNDEBUG
|
||||
else
|
||||
SQLITE_OPT += -Os
|
||||
endif
|
||||
|
||||
ifeq (1,$(enable.fts5))
|
||||
SQLITE_OPT += -DSQLITE_ENABLE_FTS5
|
||||
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
|
||||
# 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
|
||||
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))
|
||||
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))
|
||||
endif
|
||||
$(sqlite3-jni.h.in): $(dir.bld.c)
|
||||
|
||||
#package.dll.cfiles :=
|
||||
package.dll.cflags = \
|
||||
-std=c99 \
|
||||
-fPIC \
|
||||
-I. \
|
||||
-I$(dir $(sqlite3.h)) \
|
||||
-I$(dir.src.c) \
|
||||
-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.
|
||||
########################################################################
|
||||
ifeq (1,$(enable.tester))
|
||||
package.dll.cflags += -DSQLITE_JNI_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) \
|
||||
$(sqlite3-jni.c) -shared -o $@
|
||||
all: $(package.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
|
||||
|
||||
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)
|
||||
$(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
|
||||
$(java.flags) -cp $(classpath) \
|
||||
org.sqlite.jni.capi.SQLTester $(tester.flags) $(tester.scripts)
|
||||
tester: tester-local
|
||||
else
|
||||
tester:
|
||||
@echo "SQLTester support is disabled."
|
||||
endif
|
||||
|
||||
tester.extdir.default := $(dir.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)
|
||||
else
|
||||
tester-ext:
|
||||
@echo "******************************************************"; \
|
||||
echo "*** Include the out-of-tree test suite in the 'tester'"; \
|
||||
echo "*** target by either symlinking its directory to"; \
|
||||
echo "*** $(tester.extdir.default) or passing it to make"; \
|
||||
echo "*** as tester.extdir=/path/to/that/dir."; \
|
||||
echo "******************************************************";
|
||||
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...
|
||||
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)
|
||||
@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 $@"
|
||||
|
||||
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) \
|
||||
hs_err_pid*.log
|
||||
|
||||
.PHONY: clean distclean
|
||||
clean:
|
||||
-rm -f $(CLEAN_FILES)
|
||||
distclean: clean
|
||||
-rm -f $(DISTCLEAN_FILES)
|
||||
-rm -fr $(dir.bld.c) $(dir.doc)
|
||||
|
||||
########################################################################
|
||||
# disttribution bundle rules...
|
||||
|
||||
ifeq (,$(filter snapshot,$(MAKECMDGOALS)))
|
||||
dist-name-prefix := sqlite-jni
|
||||
else
|
||||
dist-name-prefix := sqlite-jni-snapshot-$(shell /usr/bin/date +%Y%m%d)
|
||||
endif
|
||||
dist-name := $(dist-name-prefix)-TEMP
|
||||
|
||||
|
||||
dist-dir.top := $(dist-name)
|
||||
dist-dir.src := $(dist-dir.top)/src
|
||||
dist.top.extras := \
|
||||
README.md
|
||||
|
||||
.PHONY: dist snapshot
|
||||
|
||||
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)/.
|
||||
@cp -p jar-dist.make $(dist-dir.top)/Makefile
|
||||
@cp -p $(dir.src.c)/*.[ch] $(dist-dir.src)/.
|
||||
@cp -p $(sqlite3.canonical.c) $(sqlite3.canonical.h) $(dist-dir.src)/.
|
||||
@set -e; \
|
||||
vnum=$$($(bin.version-info) --download-version); \
|
||||
vjar=$$($(bin.version-info) --version); \
|
||||
vdir=$(dist-name-prefix)-$$vnum; \
|
||||
arczip=$$vdir.zip; \
|
||||
cp -p $(package.jar) $(dist-dir.top)/sqlite3-jni-$${vjar}.jar; \
|
||||
echo "Making $$arczip ..."; \
|
||||
rm -fr $$arczip $$vdir; \
|
||||
mv $(dist-dir.top) $$vdir; \
|
||||
zip -qr $$arczip $$vdir; \
|
||||
rm -fr $$vdir; \
|
||||
ls -la $$arczip; \
|
||||
set +e; \
|
||||
unzip -lv $$arczip || echo "Missing unzip app? Not fatal."
|
||||
|
||||
snapshot: dist
|
||||
|
||||
.PHONY: dist-clean
|
||||
clean: dist-clean
|
||||
dist-clean:
|
||||
rm -fr $(dist-name) $(wildcard sqlite-jni-*.zip)
|
||||
@@ -1,316 +0,0 @@
|
||||
SQLite3 via JNI
|
||||
========================================================================
|
||||
|
||||
This directory houses a Java Native Interface (JNI) binding for the
|
||||
sqlite3 API. If you are reading this from the distribution ZIP file,
|
||||
links to resources in the canonical source tree will note work. The
|
||||
canonical copy of this file can be browsed at:
|
||||
|
||||
<https://sqlite.org/src/doc/trunk/ext/jni/README.md>
|
||||
|
||||
Technical support is available in the forum:
|
||||
|
||||
<https://sqlite.org/forum>
|
||||
|
||||
|
||||
> **FOREWARNING:** this subproject is very much in development and
|
||||
subject to any number of changes. Please do not rely on any
|
||||
information about its API until this disclaimer is removed. The JNI
|
||||
bindings released with version 3.43 are a "tech preview." Once
|
||||
finalized, strong backward compatibility guarantees will apply.
|
||||
|
||||
Project goals/requirements:
|
||||
|
||||
- A [1-to-1(-ish) mapping of the C API](#1to1ish) to Java via JNI,
|
||||
insofar as cross-language semantics allow for. A closely-related
|
||||
goal is that [the C documentation](https://sqlite.org/c3ref/intro.html)
|
||||
should be usable as-is, insofar as possible, for the JNI binding.
|
||||
|
||||
- Support Java as far back as version 8 (2014).
|
||||
|
||||
- Environment-independent. Should work everywhere both Java
|
||||
and SQLite3 do.
|
||||
|
||||
- No 3rd-party dependencies beyond the JDK. That includes no
|
||||
build-level dependencies for specific IDEs and toolchains. We
|
||||
welcome the addition of build files for arbitrary environments
|
||||
insofar as they neither interfere with each other nor become
|
||||
a maintenance burden for the sqlite developers.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Building
|
||||
========================================================================
|
||||
|
||||
The canonical builds assumes a Linux-like environment and requires:
|
||||
|
||||
- GNU Make
|
||||
- A JDK supporting Java 8 or higher
|
||||
- A modern C compiler. gcc and clang should both work.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
------------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
|
||||
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...)
|
||||
------------------------------------------------------------------------
|
||||
|
||||
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`.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Unwieldy Constructs are Re-mapped
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Some constructs, when modelled 1-to-1 from C to Java, are unduly
|
||||
clumsy to work with in Java because they try to shoehorn C's way of
|
||||
doing certain things into Java's wildly different ways. The following
|
||||
subsections cover those, starting with a verbose explanation and
|
||||
demonstration of where such changes are "really necessary"...
|
||||
|
||||
### Custom Collations
|
||||
|
||||
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,
|
||||
int (*xCompare)(void*,int,void const *,int,void const *));
|
||||
|
||||
int sqlite3_create_collation_v2(sqlite3 * db, const char * name, int eTextRep,
|
||||
void *pUserData,
|
||||
int (*xCompare)(void*,int,void const *,int,void const *),
|
||||
void (*xDestroy)(void*));
|
||||
```
|
||||
|
||||
The `pUserData` object is optional client-defined state for the
|
||||
`xCompare()` and/or `xDestroy()` callback functions, both of which are
|
||||
passed that object as their first argument. That data is passed around
|
||||
"externally" in C because that's how C models the world. If we were to
|
||||
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);
|
||||
|
||||
int sqlite3_create_collation_v2(sqlite3 db, String name, int eTextRep,
|
||||
Object pUserData,
|
||||
xCompareType xCompare, xDestroyType xDestroy);
|
||||
```
|
||||
|
||||
The awkwardness comes from (A) having two distinctly different objects
|
||||
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);
|
||||
```
|
||||
|
||||
Where the `Collation` class has an abstract `call()` 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(){
|
||||
|
||||
// Required comparison function:
|
||||
@Override public int call(byte[] lhs, byte[] rhs){ ... }
|
||||
|
||||
// Optional finalizer function:
|
||||
@Override public void xDestroy(){ ... }
|
||||
|
||||
// Optional local state:
|
||||
private String localState1 =
|
||||
"This is local state. There are many like it, but this one is mine.";
|
||||
private MyStateType localState2 = new MyStateType();
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
- No capabilities of the C API are lost or unduly obscured via the
|
||||
above API reshaping, so power users need not make any compromises.
|
||||
|
||||
- In the specific example above, `sqlite3_create_collation_v2()`
|
||||
becomes superfluous because the provided interface effectively
|
||||
provides both the v1 and v2 interfaces, the difference being 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)
|
||||
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.
|
||||
|
||||
`SQLFunction` is not used directly, but is instead instantiated via
|
||||
one of its three subclasses:
|
||||
|
||||
- `ScalarFunction` implements simple scalar functions using but a
|
||||
single callback.
|
||||
- `AggregateFunction` implements aggregate functions using two
|
||||
callbacks.
|
||||
- `WindowFunction` implements window functions using four
|
||||
callbacks.
|
||||
|
||||
Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/capi/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.
|
||||
@@ -1,60 +0,0 @@
|
||||
#!/this/is/make
|
||||
#^^^^ help emacs out
|
||||
#
|
||||
# This is a POSIX-make-compatible makefile for building the sqlite3
|
||||
# JNI library from "dist" zip file. It must be edited to set the
|
||||
# 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.
|
||||
|
||||
default: all
|
||||
|
||||
JAVA_HOME = /usr/lib/jvm/java-1.8.0-openjdk-amd64
|
||||
CFLAGS = \
|
||||
-fPIC \
|
||||
-Isrc \
|
||||
-I$(JAVA_HOME)/include \
|
||||
-I$(JAVA_HOME)/include/linux \
|
||||
-I$(JAVA_HOME)/include/apple \
|
||||
-I$(JAVA_HOME)/include/bsd \
|
||||
-Wall
|
||||
|
||||
SQLITE_OPT = \
|
||||
-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_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_OMIT_DEPRECATED \
|
||||
-DSQLITE_OMIT_SHARED_CACHE \
|
||||
-DSQLITE_THREADSAFE=1 \
|
||||
-DSQLITE_TEMP_STORE=2 \
|
||||
-DSQLITE_USE_URI=1 \
|
||||
-DSQLITE_ENABLE_FTS5 \
|
||||
-DSQLITE_DEBUG
|
||||
|
||||
sqlite3-jni.dll = libsqlite3-jni.so
|
||||
$(sqlite3-jni.dll):
|
||||
@echo "************************************************************************"; \
|
||||
echo "*** If this fails to build, be sure to edit this makefile ***"; \
|
||||
echo "*** to configure it for your system. ***"; \
|
||||
echo "************************************************************************"
|
||||
$(CC) $(CFLAGS) $(SQLITE_OPT) \
|
||||
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
|
||||
|
||||
clean:
|
||||
-rm -f $(sqlite3-jni.dll)
|
||||
|
||||
all: $(sqlite3-jni.dll)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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,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;
|
||||
|
||||
/**
|
||||
Callback for use with {@link CApi#sqlite3_collation_needed}.
|
||||
*/
|
||||
public interface CollationNeededCallback extends CallbackProxy {
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
void call(sqlite3 db, int eTextRep, String collationName);
|
||||
}
|
||||
@@ -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_commit_hook}.
|
||||
*/
|
||||
public interface CommitHookCallback extends CallbackProxy {
|
||||
/**
|
||||
Works as documented for the C-level sqlite3_commit_hook()
|
||||
callback. If it throws, the exception is translated into
|
||||
a db-level error.
|
||||
*/
|
||||
int call();
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
** 2023-08-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.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file is part of the JNI bindings for the sqlite3 C API.
|
||||
*/
|
||||
package org.sqlite.jni.capi;
|
||||
|
||||
/**
|
||||
A callback for use with sqlite3_config().
|
||||
*/
|
||||
public interface ConfigLogCallback {
|
||||
/**
|
||||
Must function as described for a C-level callback for
|
||||
{@link CApi#sqlite3_config(ConfigLogCallback)}, with the slight signature change.
|
||||
*/
|
||||
void call(int errCode, String msg);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
** 2023-08-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.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file is part of the JNI bindings for the sqlite3 C API.
|
||||
*/
|
||||
package org.sqlite.jni.capi;
|
||||
|
||||
/**
|
||||
A callback for use with sqlite3_config().
|
||||
*/
|
||||
public interface ConfigSqlLogCallback {
|
||||
/**
|
||||
Must function as described for a C-level callback for
|
||||
{@link CApi#sqlite3_config(ConfigSqlLogCallback)}, with the slight signature change.
|
||||
*/
|
||||
void call(sqlite3 db, String msg, int msgType );
|
||||
}
|
||||
@@ -1,46 +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;
|
||||
|
||||
/**
|
||||
A helper for passing pointers between JNI C code and Java, in
|
||||
particular for output pointers of high-level object types in the
|
||||
sqlite3 C API, e.g. (sqlite3**) and (sqlite3_stmt**). This is
|
||||
intended to be subclassed and the ContextType is intended to be the
|
||||
class which is doing the subclassing. The intent of the ContextType
|
||||
is strictly to provide some level of type safety by avoiding that
|
||||
NativePointerHolder is not inadvertently passed to an incompatible
|
||||
function signature.
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public final long getNativePointer(){ return nativePointer; }
|
||||
}
|
||||
@@ -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,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_progress_handler}.
|
||||
*/
|
||||
public interface ProgressHandlerCallback extends CallbackProxy {
|
||||
/**
|
||||
Works as documented for the C-level sqlite3_progress_handler() callback.
|
||||
|
||||
<p>If it throws, the exception message is passed on to the db and
|
||||
the exception is suppressed.
|
||||
*/
|
||||
int call();
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +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 scalar functions.
|
||||
*/
|
||||
public abstract class ScalarFunction implements SQLFunction {
|
||||
/**
|
||||
As for the xFunc() argument of the C API's
|
||||
sqlite3_create_function(). If this function throws, it is
|
||||
translated into an sqlite3_result_error().
|
||||
*/
|
||||
public abstract void xFunc(sqlite3_context cx, sqlite3_value[] args);
|
||||
|
||||
/**
|
||||
Optionally override to be notified when the UDF is finalized by
|
||||
SQLite. This default implementation does nothing.
|
||||
*/
|
||||
public void xDestroy() {}
|
||||
}
|
||||
@@ -1,35 +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;
|
||||
|
||||
/**
|
||||
A wrapper object for use with sqlite3_table_column_metadata().
|
||||
They are populated only via that interface.
|
||||
*/
|
||||
public final class TableColumnMetadata {
|
||||
OutputPointer.Bool pNotNull = new OutputPointer.Bool();
|
||||
OutputPointer.Bool pPrimaryKey = new OutputPointer.Bool();
|
||||
OutputPointer.Bool pAutoinc = new OutputPointer.Bool();
|
||||
OutputPointer.String pzCollSeq = new OutputPointer.String();
|
||||
OutputPointer.String pzDataType = new OutputPointer.String();
|
||||
|
||||
public TableColumnMetadata(){
|
||||
}
|
||||
|
||||
public String getDataType(){ return pzDataType.value; }
|
||||
public String getCollation(){ return pzCollSeq.value; }
|
||||
public boolean isNotNull(){ return pNotNull.value; }
|
||||
public boolean isPrimaryKey(){ return pPrimaryKey.value; }
|
||||
public boolean isAutoincrement(){ return pAutoinc.value; }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user