Compare commits

..

1 Commits

Author SHA1 Message Date
drh 6b783ec950 Pervent the parser stack from growing to be larger than 100 plus four times
the SQLITE_LIMIT_EXPR_DEPTH setting.

FossilOrigin-Name: 5728129e5432500550096e2a1350897881f0379b49b60faf49481c505b1eb323
2025-11-18 02:24:46 +00:00
415 changed files with 21023 additions and 61089 deletions
-125
View File
@@ -1,125 +0,0 @@
# AGENTS.md
Guidance for AI coding agents working in this repository.
## Project nature
SQLite is a self-contained, serverless SQL database engine written in C. The
source is **public domain** — no copyright or license header should ever be
added to any file. The blessing comment that appears at the top of each source
file is intentional and should be preserved unchanged.
SQLite does not accept pull requests without prior agreement and/or
accompanying legal paperwork that places the pull request in the public domain.
However, the human SQLite developers will review a concise and well-written
pull request as a proof-of-concept prior to reimplementing the changes
themselves.
SQLite does not accept agentic code. However the project
will accept agentic bug reports that include a reproducible test case.
Patches or pull requests demonstrating a possible fix, for documentation
purposes, are welcomed.
SQLite uses the [Fossil](https://fossil-scm.org/) for version control,
not Git. The canonical repository is at <https://sqlite.org/src>.
## Build
The configure script uses [autosetup](https://msteveb.github.io/autosetup/),
not GNU Autoconf.
```bash
apt install gcc make tcl-dev # prerequisites (Debian/Ubuntu)
./configure --dev # debug build
make sqlite3 # CLI shell
make sqlite3d # Debugging variant of the CLI shell
make sqlite3.c # amalgamation (single-file distribution form)
make testfixture # test runner binary (requires tcl-dev)
make tclextension-install # install TCL extension before running tests
```
## Testing
Tests are TCL scripts run through the `testfixture` enhanced interpreter.
```bash
# From the build directory:
./testfixture test/main.test # single test file
test/testrunner.tcl # quick suite
test/testrunner.tcl full # full suite
test/testrunner.tcl fts5% # pattern match
# Check for failures:
grep '!' testrunner.log
```
`make devtest` is the fastest way to run a representative subset. Always run
at least `devtest` after any change to `src/`.
## Architecture
SQL text → **tokenizer** (`tokenize.c`) → **parser** (`parse.y` / Lemon) →
**code generator** (`build.c`, `select.c`, `insert.c`, `update.c`, `delete.c`,
`expr.c`) → **optimizer** (`where*.c`) → **VDBE** (`vdbe.c`) → **B-Tree**
(`btree.c`) → **Pager** (`pager.c`) → **WAL** (`wal.c`) → **VFS**
(`os_unix.c`, `os_win.c`).
The master internal header is `src/sqliteInt.h`. Major subsystems have private
headers: `vdbeInt.h`, `btreeInt.h`, `whereInt.h`. The public API is defined in
`src/sqlite.h.in` (template) which generates `sqlite3.h`.
## Do not edit generated files
These files are produced by scripts and must not be edited by hand:
| File | Regenerate with |
|---|---|
| `sqlite3.h` | `tool/mksqlite3h.tcl` |
| `parse.c`, `parse.h` | build lemon (`tool/lemon.c`) then run on `src/parse.y` |
| `opcodes.h` | `tool/mkopcodeh.tcl` (reads `src/vdbe.c`) |
| `opcodes.c` | `tool/mkopcodec.tcl` (reads `opcodes.h`) |
| `keywordhash.h` | `tool/mkkeywordhash.c` |
| `pragma.h` | `tool/mkpragmatab.tcl` |
| `sqlite3.c` | `tool/mksqlite3c.tcl` (the amalgamation) |
Editing rules:
- To add a PRAGMA: edit `tool/mkpragmatab.tcl`, then regenerate `pragma.h`.
- To add a VDBE opcode: add the `case OP_Xxx:` handler in `src/vdbe.c`; the
opcode number and name are extracted automatically by `mkopcodeh.tcl`.
- To change the SQL grammar: edit `src/parse.y`, not `parse.c`.
## Coding conventions
- C89/C99 compatible C only. No C++, no STL, no exceptions, no VLAs.
- All memory allocation goes through `sqlite3Malloc` / `sqlite3_malloc64`
(never raw `malloc`). The `sqlite3MallocZero` variant zero-initializes.
- Integer widths: use `i64` (`sqlite3_int64`) for 64-bit values, `u32`/`u64`
for unsigned. Avoid bare `long` or `int` for values that could exceed 2G.
- Error propagation: functions return `SQLITE_OK` (0) on success and a
`SQLITE_*` error code on failure. Many routines also set `db->mallocFailed`
on OOM, allowing deferred error checking.
- Assert liberally for invariants that must hold in correct code; use
`ALWAYS(x)` / `NEVER(x)` for conditions that are logically always
true/false but that the compiler cannot prove.
## Extensions (`ext/`)
Extensions are compiled separately from the core and are not part of the
amalgamation by default (except where explicitly included). Major subsystems:
- `ext/fts5/` — Full-Text Search 5 (current)
- `ext/rtree/` — R-Tree spatial indexing
- `ext/session/` — Changesets and sessions
- `ext/recover/` — Database file recovery
- `ext/misc/` — Single-file utility extensions (many included in the CLI)
- `ext/qrf/` — Query Result Formatter utility library
## Useful references
- Architecture: <https://sqlite.org/arch.html>
- File format: <https://sqlite.org/fileformat2.html>
- VDBE opcodes: <https://sqlite.org/opcode.html>
- Query planner: <https://sqlite.org/optoverview.html>
- Lemon parser generator: <https://sqlite.org/doc/trunk/doc/lemon.html>
- Compile-time options: <https://sqlite.org/compile.html>
+3 -11
View File
@@ -131,15 +131,9 @@ libsqlite3.DLL.install-rules = @SQLITE_DLL_INSTALL_RULES@
CFLAGS.fuzzcheck-asan.fsanitize = @CFLAGS_ASAN_FSANITIZE@
#
# TARGET_DEBUG is intended to either be empty or be set to -g
# -DSQLITE_DEBUG=1, plus any other flags relevant for debug-only
# builds. These get added near the front of $(T.cc) so that they can
# be overridden by CFLAGS passed directly to make. Historically (prior
# to 2026-03-30) these were at/near the end of the flags but that made
# it impossible to pass custom -O* flags to specific binaries without
# reconfiguring.
# Intended to either be empty or be set to -g -DSQLITE_DEBUG=1.
#
T.cc += @TARGET_DEBUG@
T.cc.TARGET_DEBUG = @TARGET_DEBUG@
#
# $(JIMSH) and $(CFLAGS.jimsh) are documented in main.mk. $(JIMSH)
@@ -170,9 +164,7 @@ OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ $(OPTIONS)
PACKAGE_VERSION = @PACKAGE_VERSION@
#
# Filename extensions for binaries and libraries. B.* are for the
# being-built-on platform and T.* are for the build's target platform.
# i.e. B.* is for build-time tooling and T.* is for deliverables.
# Filename extensions for binaries and libraries
#
B.exe = @BUILD_EXEEXT@
T.exe = @TARGET_EXEEXT@
+163 -263
View File
@@ -11,8 +11,6 @@
TOP = .
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# Set this non-0 to create and use the SQLite amalgamation file.
#
!IFNDEF USE_AMALGAMATION
@@ -103,6 +101,13 @@ NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706
!ENDIF
!ENDIF
# Set this non-0 to use the library paths and other options necessary for
# Windows Phone 8.1.
#
!IFNDEF USE_WP81_OPTS
USE_WP81_OPTS = 0
!ENDIF
# Set this non-0 to split the SQLite amalgamation file into chunks to
# be used for debugging with Visual Studio.
#
@@ -111,8 +116,14 @@ SPLIT_AMALGAMATION = 0
!ENDIF
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
# Set this non-0 to have this makefile assume the Tcl shell executable
# (tclsh*.exe) is available in the PATH. By default, this is disabled
# for compatibility with older build environments. This setting only
# applies if TCLSH_CMD is not set manually.
#
!IFNDEF USE_TCLSH_IN_PATH
USE_TCLSH_IN_PATH = 0
!ENDIF
# Set this non-0 to use zlib, possibly compiling it from source code.
#
@@ -175,6 +186,14 @@ USE_NATIVE_LIBPATHS = 0
USE_RC = 1
!ENDIF
# Set this non-0 to compile binaries suitable for the WinRT environment.
# This setting does not apply to any binaries that require Tcl to operate
# properly (i.e. the text fixture, etc).
#
!IFNDEF FOR_WINRT
FOR_WINRT = 0
!ENDIF
# Set this non-0 to compile binaries suitable for the UWP environment.
# This setting does not apply to any binaries that require Tcl to operate
# properly (i.e. the text fixture, etc).
@@ -190,8 +209,6 @@ FOR_WIN10 = 0
!ENDIF
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# Set this non-0 to skip attempting to look for and/or link with the Tcl
# runtime library.
#
@@ -248,8 +265,6 @@ DEBUG = 0
!ENDIF
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# By default, use --linemacros=1 argument to the mksqlite3c.tcl tool, which
# is used to build the amalgamation. This can be turned off to ease debug
# of the amalgamation away from the source tree.
@@ -345,8 +360,6 @@ SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
!ENDIF
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# These are the names of the customized Tcl header files used by various parts
# of this makefile when the stdcall calling convention is in use. It is not
# used for any other purpose.
@@ -628,24 +641,16 @@ RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src $(RCOPTS) $(RCCOPTS)
!IF "$(PLATFORM)"=="x86"
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
TEST_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl
# <</mark>>
!ELSE
!IFNDEF PLATFORM
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
TEST_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl
# <</mark>>
!ELSE
CORE_CCONV_OPTS =
SHELL_CCONV_OPTS =
@@ -772,6 +777,18 @@ SHELL_LINK_OPTS = $(SHELL_CORE_LIB)
TCC = $(TCC) -FAcs
!ENDIF
# When compiling the library for use in the WinRT environment,
# the following compile-time options must be used as well to
# disable use of Win32 APIs that are not available and to enable
# use of Win32 APIs that are specific to Windows 8 and/or WinRT.
#
!IF $(FOR_WINRT)!=0
TCC = $(TCC) -DSQLITE_OS_WINRT=1
RCC = $(RCC) -DSQLITE_OS_WINRT=1
TCC = $(TCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
!ENDIF
# C compiler options for the Windows 10 platform (needs MSVC 2015).
#
!IF $(FOR_WIN10)!=0
@@ -784,31 +801,25 @@ BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
# USE_CRT_DLL option is set to force dynamically linking to the
# MSVC runtime library.
#
!IF $(USE_CRT_DLL)!=0
!IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
ZLIBCFLAGS = -nologo -MDd -W3 -O2 -Oy- -Zi
!ELSE
TCC = $(TCC) -MD
BCC = $(BCC) -MD
ZLIBCFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi
!ENDIF
!ELSE
!IF $(DEBUG)>1
TCC = $(TCC) -MTd
BCC = $(BCC) -MTd
ZLIBCFLAGS = -nologo -MTd -W3 -O2 -Oy- -Zi
!ELSE
TCC = $(TCC) -MT
BCC = $(BCC) -MT
ZLIBCFLAGS = -nologo -MT -W3 -O2 -Oy- -Zi
!ENDIF
!ENDIF
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# The mksqlite3c.tcl and mksqlite3h.tcl scripts will pull in
# any extension header files by default. For non-amalgamation
# builds, we need to make sure the compiler can find these.
@@ -859,6 +870,16 @@ MKSQLITE3H_ARGS =
!ENDIF
# <</mark>>
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
# Omitting the define will cause extra debugging code to be inserted and
# includes extra comments when "EXPLAIN stmt" is used.
#
!IF $(DEBUG)==0
TCC = $(TCC) -DNDEBUG
BCC = $(BCC) -DNDEBUG
RCC = $(RCC) -DNDEBUG
!ENDIF
!IF $(DEBUG)>0 || $(API_ARMOR)!=0 || $(FOR_WIN10)!=0
TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR=1
RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
@@ -924,8 +945,6 @@ TCC = $(TCC) /fsanitize=address
!ENDIF
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# The locations of the Tcl header and library files. Also, the library that
# non-stubs enabled programs using Tcl must link against. These variables
# (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment
@@ -1165,8 +1184,6 @@ BCC = $(BCC) -Zi
!ENDIF
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# If zlib support is enabled, add the compiler options for it.
#
!IF $(USE_ZLIB)!=0
@@ -1219,6 +1236,56 @@ LTLINKOPTS = /NOLOGO
LTLIBOPTS = /NOLOGO
!ENDIF
# When compiling for use in the WinRT environment, the following
# linker option must be used to mark the executable as runnable
# only in the context of an application container.
#
!IF $(FOR_WINRT)!=0
LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER
!IF "$(VISUALSTUDIOVERSION)"=="12.0" || "$(VISUALSTUDIOVERSION)"=="14.0"
!IFNDEF STORELIBPATH
!IF "$(PLATFORM)"=="x86"
STORELIBPATH = $(CRTLIBPATH)\store
!ELSEIF "$(PLATFORM)"=="x64"
STORELIBPATH = $(CRTLIBPATH)\store\amd64
!ELSEIF "$(PLATFORM)"=="ARM"
STORELIBPATH = $(CRTLIBPATH)\store\arm
!ELSE
STORELIBPATH = $(CRTLIBPATH)\store
!ENDIF
!ENDIF
STORELIBPATH = $(STORELIBPATH:\\=\)
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(STORELIBPATH)"
!ENDIF
!ENDIF
# When compiling for Windows Phone 8.1, an extra library path is
# required.
#
!IF $(USE_WP81_OPTS)!=0
!IFNDEF WP81LIBPATH
!IF "$(PLATFORM)"=="x86"
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
!ELSEIF "$(PLATFORM)"=="ARM"
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\ARM
!ELSE
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
!ENDIF
!ENDIF
!ENDIF
# When compiling for Windows Phone 8.1, some extra linker options
# are also required.
#
!IF $(USE_WP81_OPTS)!=0
!IFDEF WP81LIBPATH
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
!ENDIF
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
!ENDIF
# When compiling for UWP or the Windows 10 platform, some extra linker
# options are also required.
#
@@ -1242,14 +1309,12 @@ LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
LDFLAGS = /NODEFAULTLIB:msvcrt /DEBUG $(LDOPTS)
LDFLAGS = /DEBUG $(LDOPTS)
!ELSE
LDFLAGS = /NODEFAULTLIB:msvcrt $(LDOPTS)
LDFLAGS = $(LDOPTS)
!ENDIF
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# Start with the Tcl related linker options.
#
!IF $(NO_TCL)==0
@@ -1276,8 +1341,6 @@ LTLIBS = $(LTLIBS) $(LIBICU)
###############################################################################
# <<mark>>
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
#
# Object files for the SQLite library (non-amalgamation).
#
LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
@@ -1396,7 +1459,7 @@ SRC01 = \
$(TOP)\src\status.c \
$(TOP)\src\table.c \
$(TOP)\src\threads.c \
tclsqlite-ex.c \
$(TOP)\src\tclsqlite.c \
$(TOP)\src\tokenize.c \
$(TOP)\src\treeview.c \
$(TOP)\src\trigger.c \
@@ -1719,7 +1782,6 @@ FUZZERSHELL_COMPILE_OPTS =
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -I$(TOP)\test -I$(TOP)\ext\recover
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_MEMSYS5
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OSS_FUZZ
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_DECIMAL_MAX_DIGIT=1000
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_CARRAY
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB
@@ -1766,18 +1828,7 @@ FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\fuzzinvariants.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\vt02.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\dbdata.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\sqlite3recover.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\base64.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\base85.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\completion.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\decimal.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\diskused.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\ieee754.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\randomjson.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\regexp.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\series.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\shathree.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\sha1.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\stmtrand.c
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
@@ -1878,8 +1929,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 $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS) $(TOP)\tool\winmain.c
$(LTLINK) $(NO_WARN) -I$(TOP)\ext\misc $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.c $(TOP)\tool\winmain.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
sqldiff.exe: $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -I$(TOP)\ext\misc $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -1897,6 +1948,9 @@ RSYNC_OPT = \
sqlite3_rsync.exe: $(RSYNC_SRC) $(LIBRESOBJS)
$(LTLINK) $(RSYNC_OPT) $(NO_WARN) $(RSYNC_SRC) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) -DSCRUB_STANDALONE=1 $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
srcck1.exe: $(TOP)\tool\srcck1.c
$(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c
@@ -1966,18 +2020,8 @@ sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-v
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(JIM_TCLSH)
$(JIM_TCLSH) $(TOP)\tool\split-sqlite3c.tcl
TCLSQLITEEX = \
$(TOP)\ext\qrf\qrf.h \
$(TOP)\ext\qrf\qrf.c \
$(TOP)\src\tclsqlite.c
tclsqlite-ex.c: $(TCLSQLITEEX) $(TOP)\tool\mkcombo.tcl $(JIM_TCLSH)
$(JIM_TCLSH) $(TOP)\tool\mkcombo.tcl $(TCLSQLITEEX) -o $@
# <</mark>>
tclsqlite-ex.c:
# Rule to build the amalgamation
#
sqlite3.lo: $(SQLITE3C)
@@ -2277,11 +2321,11 @@ whereexpr.lo: $(TOP)\src\whereexpr.c $(HDR)
window.lo: $(TOP)\src\window.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\window.c
tclsqlite.lo: tclsqlite-ex.c $(HDR) $(SQLITE_TCL_DEP)
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c tclsqlite-ex.c /OUT:tclsqlite.lo
tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
tclsqlite-shell.lo: tclsqlite-ex.c $(HDR) $(SQLITE_TCL_DEP)
$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c tclsqlite-ex.c
tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
@@ -2334,8 +2378,6 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
# Source and header files that shell.c depends on
SHELL_DEP = \
$(TOP)\src\shell.c.in \
$(TOP)\ext\qrf\qrf.c \
$(TOP)\ext\qrf\qrf.h \
$(TOP)\ext\expert\sqlite3expert.c \
$(TOP)\ext\expert\sqlite3expert.h \
$(TOP)\ext\intck\sqlite3intck.c \
@@ -2345,7 +2387,6 @@ SHELL_DEP = \
$(TOP)\ext\misc\base85.c \
$(TOP)\ext\misc\completion.c \
$(TOP)\ext\misc\decimal.c \
$(TOP)\ext\misc\diskused.c \
$(TOP)\ext\misc\fileio.c \
$(TOP)\ext\misc\ieee754.c \
$(TOP)\ext\misc\memtrace.c \
@@ -2376,7 +2417,7 @@ shell.c: $(SHELL_DEP) $(TOP)\tool\mkshellc.tcl $(JIM_TCLSH)
$(JIM_TCLSH) $(TOP)\tool\mkshellc.tcl shell.c
zlib:
pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) CFLAGS="$(ZLIBCFLAGS)" && popd
pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd
# Rules to build the extension objects.
#
@@ -2500,9 +2541,9 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STRICT_SUBTYPE=1
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
!IF $(USE_AMALGAMATION)==0
TESTFIXTURE_SRC = $(TESTSRC) tclsqlite-ex.c $(TESTFIXTURE_SRC0)
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0)
!ELSE
TESTFIXTURE_SRC = $(TESTSRC) tclsqlite-ex.c $(TESTFIXTURE_SRC1)
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC1)
!ENDIF
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
@@ -2550,19 +2591,43 @@ coretestprogs: testfixture.exe sqlite3.exe
testprogs: $(TESTPROGS) srcck1.exe fuzzcheck.exe sessionfuzz.exe
fulltest: alltest fuzztest
alltest: $(TESTPROGS)
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\all.test $(TESTOPTS)
soaktest: $(TESTPROGS)
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\all.test -soak=1 $(TESTOPTS)
fulltestonly: $(TESTPROGS) fuzztest
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\full.test
queryplantest: testfixture.exe shell
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS)
fuzztest: fuzzcheck.exe
.\fuzzcheck.exe $(FUZZDATA)
# Legacy testing target for third-party integrators. The SQLite
# developers seldom use this target themselves. Instead
# they use "nmake /f Makefile.msc devtest" which runs tests on
# a standard set of options
#
# Legacy testing targets, no longer used by the developers and
# now aliased to one of the commonly used testing targets.
test: $(TESTPROGS) sourcetest fuzztest tcltest
# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest: testfixture.exe sourcetest
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS)
# This is the common case. Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
quicktest: devtest
test: devtest
fulltest: releasetest
alltest: releasetest
soaktest: releasetest
fulltestonly: releasetest
# The veryquick.test TCL tests.
#
@@ -2587,22 +2652,6 @@ devtest: srctree-check sourcetest
mdevtest:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest
# Rerun test cases that failed on the previous testrunner invocation
#
retest:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl retest
# Show all errors from the most reason testrunner invocation
#
errors:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl errors
# Show the status of the current testrunner invocation,
# updated every couple of seconds
#
status:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl status -d 2
# Validate that various generated files in the source tree
# are up-to-date.
#
@@ -2626,23 +2675,17 @@ smoketest: $(TESTPROGS)
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
# Measure the performance of floating-point conversions.
#
fp-speed-test: fp-speed-1.exe fp-speed-2.exe
fp-speed-1 1000000
fp-speed-2 1000000
shelltest: $(TESTPROGS)
.\testfixture.exe $(TOP)\test\permutations.test shell
shelltest:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl release shell
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) tclsqlite-ex.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE_TCL_DEP)
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE_TCL_DEP)
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl -DINCLUDE_SQLITE3_C $(TOP)\tool\sqlite3_analyzer.c.in > $@
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
sqltclsh.c: sqlite3.c tclsqlite-ex.c $(TOP)\tool\sqltclsh.tcl $(TOP)\ext\misc\appendvfs.c $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in
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.exe: sqltclsh.c $(SHELL_CORE_DEP) $(LIBRESOBJS)
@@ -2652,6 +2695,23 @@ sqltclsh.exe: sqltclsh.c $(SHELL_CORE_DEP) $(LIBRESOBJS)
sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c
$(LTLINK) $(NO_WARN) $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(SQLITE3C) $(TLIBS)
CHECKER_DEPS =\
$(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
sqlite3_checker.c: $(CHECKER_DEPS)
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\ext\repair\sqlite3_checker.c.in > $@
sqlite3_checker.exe: sqlite3_checker.c $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_checker.c \
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
dbdump.exe: $(TOP)\ext\misc\dbdump.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -DDBDUMP_STANDALONE $(TOP)\ext\misc\dbdump.c $(SQLITE3C) \
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS)
@@ -2684,9 +2744,6 @@ showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) $(SQLITE3H)
showshm.exe: $(TOP)\tool\showshm.c
$(LTLINK) $(NO_WARN) $(TOP)\tool\showshm.c /link $(LDFLAGS) $(LTLINKOPTS)
showtmlog.exe: $(TOP)\tool\showtmlog.c
$(LTLINK) $(NO_WARN) $(TOP)\tool\showtmlog.c /link $(LDFLAGS) $(LTLINKOPTS)
index_usage.exe: $(TOP)\tool\index_usage.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\tool\index_usage.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -2724,14 +2781,6 @@ speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\test\speedtest1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
fp-speed-1.exe: $(TOP)\test\fp-speed-1.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\test\fp-speed-1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
fp-speed-2.exe: $(TOP)\test\fp-speed-2.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\test\fp-speed-2.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
kvtest.exe: $(TOP)\test\kvtest.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(KV_COMPILE_OPTS) \
$(TOP)\test\kvtest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -2740,9 +2789,6 @@ rbu.exe: $(TOP)\ext\rbu\rbu.c $(TOP)\ext\rbu\sqlite3rbu.c $(SQLITE3C) $(SQLITE3H
$(LTLINK) $(NO_WARN) -DSQLITE_ENABLE_RBU \
$(TOP)\ext\rbu\rbu.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
$(AUXTEST).exe: $(TOP)\test\c\$(AUXTEST).c
$(LTLINK) $(NO_WARN) $(TOP)\test\c\$(AUXTEST).c sqlite3.lo /link $(LDFLAGS) $(LTLINKOPTS)
THREADTEST3_SRC = \
$(TOP)\test\threadtest3.c \
$(TOP)\test\tt3_checkpoint.c \
@@ -2754,21 +2800,6 @@ THREADTEST3_SRC = \
threadtest3.exe: $(THREADTEST3_SRC) $(TOP)\src\test_multiplex.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\test\threadtest3.c $(TOP)\src\test_multiplex.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
# Convenienced targets for common executables that omit
# the .exe suffix
#
sqldiff: sqldiff.exe
sqlite3_rsync: sqlite3_rsync.exe
fuzzcheck: fuzzcheck.exe
testfixture: testfixture.exe
sqlite3: $(SQLITE3EXE)
showdb: showdb.exe
LogEst: LogEst.exe
wordcount: wordcount.exe
speedtest1: speedtest1.exe
kvtest: kvtest.exe
jimsh0: jimsh0.exe
# Display key variables that control which version of TCL is to be used.
#
tcl-env:
@@ -2781,135 +2812,6 @@ tcl-env:
@echo JIM_TCLSH = $(JIM_TCLSH)
@echo VISUALSTUDIOVERSION = $(VISUALSTUDIOVERSION)
env:
@echo ALL_TCL_TARGETS = $(ALL_TCL_TARGETS)
@echo API_ARMOR = $(API_ARMOR)
@echo ASAN = $(ASAN)
@echo BCC = $(BCC)
@echo BUILD_ZLIB = $(BUILD_ZLIB)
@echo CC = $(CC)
@echo CCOPTS = $(CCOPTS)
@echo CHECKER_DEPS = $(CHECKER_DEPS)
@echo CORE_CCONV_OPTS = $(CORE_CCONV_OPTS)
@echo CORE_COMPILE_OPTS = $(CORE_COMPILE_OPTS)
@echo CORE_LINK_DEP = $(CORE_LINK_DEP)
@echo CORE_LINK_OPTS = $(CORE_LINK_OPTS)
@echo CRTLIBPATH = $(CRTLIBPATH)
@echo CSC = $(CSC)
@echo DBFUZZ_COMPILE_OPTS = $(DBFUZZ_COMPILE_OPTS)
@echo DEBUG = $(DEBUG)
@echo DYNAMIC_SHELL = $(DYNAMIC_SHELL)
@echo EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS)
@echo EXTHDR = $(EXTHDR)
@echo EXTRA_SRC = $(EXTRA_SRC)
@echo FOR_UWP = $(FOR_UWP)
@echo FUZZCHECK_OPTS = $(FUZZCHECK_OPTS)
@echo FUZZCHECK_SRC = $(FUZZCHECK_SRC)
@echo FUZZDATA = $(FUZZDATA)
@echo FUZZERSHELL_COMPILE_OPTS = $(FUZZERSHELL_COMPILE_OPTS)
@echo HDR = $(HDR)
@echo ICUDIR = $(ICUDIR)
@echo ICUINCDIR = $(ICUINCDIR)
@echo ICULIBDIR = $(ICULIBDIR)
@echo JIM_TCLSH = $(JIM_TCLSH)
@echo KV_COMPILE_OPTS = $(KV_COMPILE_OPTS)
@echo LDFLAGS = $(LDFLAGS)
@echo LD = $(LD)
@echo LIBICU = $(LIBICU)
@echo LIBOBJ = $(LIBOBJ)
@echo LIBREADLINE = $(LIBREADLINE)
@echo LIBRESOBJS = $(LIBRESOBJS)
@echo LIBTCLPATH = $(LIBTCLPATH)
@echo LIBTCLSTUB = $(LIBTCLSTUB)
@echo LIBTCL = $(LIBTCL)
@echo LTCOMPILE = $(LTCOMPILE)
@echo LTLIB = $(LTLIB)
@echo LTLIBOPTS = $(LTLIBOPTS)
@echo LTLIBPATHS = $(LTLIBPATHS)
@echo LTLIBS = $(LTLIBS)
@echo LTLINK = $(LTLINK)
@echo LTLINKOPTS = $(LTLINKOPTS)
@echo LTRCOMPILE = $(LTRCOMPILE)
@echo MEMDEBUG = $(MEMDEBUG)
@echo MINIMAL_AMALGAMATION = $(MINIMAL_AMALGAMATION)
@echo MPTESTER_COMPILE_OPTS = $(MPTESTER_COMPILE_OPTS)
@echo NCC = $(NCC)
@echo NCRTLIBPATH = $(NCRTLIBPATH)
@echo NLTLIBPATHS = $(NLTLIBPATHS)
@echo NO_LINEMACROS = $(NO_LINEMACROS)
@echo NO_TCL = $(NO_TCL)
@echo NO_WARN = $(NO_WARN)
@echo NSDKLIBPATH = $(NSDKLIBPATH)
@echo NUCRTLIBPATH = $(NUCRTLIBPATH)
@echo OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS)
@echo OPTIMIZATIONS = $(OPTIMIZATIONS)
@echo OSSSHELL_SRC = $(OSSSHELL_SRC)
@echo OSTRACE = $(OSTRACE)
@echo RBU = $(RBU)
@echo RCC = $(RCC)
@echo RC = $(RC)
@echo READLINE_FLAGS = $(READLINE_FLAGS)
@echo REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS)
@echo RSYNC_OPT = $(RSYNC_OPT)
@echo RSYNC_SRC = $(RSYNC_SRC)
@echo SESSION = $(SESSION)
@echo SETLK_TIMEOUT = $(SETLK_TIMEOUT)
@echo SHELL_CCONV_OPTS = $(SHELL_CCONV_OPTS)
@echo SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS)
@echo SHELL_CORE_DEP = $(SHELL_CORE_DEP)
@echo SHELL_CORE_LIB = $(SHELL_CORE_LIB)
@echo SHELL_CORE_SRC = $(SHELL_CORE_SRC)
@echo SHELL_DEP = $(SHELL_DEP)
@echo SHELL_LINK_OPTS = $(SHELL_LINK_OPTS)
@echo SPLIT_AMALGAMATION = $(SPLIT_AMALGAMATION)
@echo SQLITETCLDECLSH = $(SQLITETCLDECLSH)
@echo SQLITE_TCL_DEP = $(SQLITE_TCL_DEP)
@echo SQLITETCLH = $(SQLITETCLH)
@echo SRC = $(SRC)
@echo STATICALLY_LINK_TCL = $(STATICALLY_LINK_TCL)
@echo ST_COMPILE_OPTS = $(ST_COMPILE_OPTS)
@echo STORELIBPATH = $(STORELIBPATH)
@echo SYMBOLS = $(SYMBOLS)
@echo TCC = $(TCC)
@echo TCLDIR = $(TCLDIR)
@echo TCLINCDIR = $(TCLINCDIR)
@echo TCLLIBDIR = $(TCLLIBDIR)
@echo TCLLIBPATHS = $(TCLLIBPATHS)
@echo TCLLIBS = $(TCLLIBS)
@echo TCLSH_CMD = $(TCLSH_CMD)
@echo TCLSQLITEEX = $(TCLSQLITEEX)
@echo TCLSUFFIX = $(TCLSUFFIX)
@echo TCLVERSION = $(TCLVERSION)
@echo TEST_CCONV_OPTS = $(TEST_CCONV_OPTS)
@echo TESTEXT = $(TESTEXT)
@echo TESTFIXTURE_DEP = $(TESTFIXTURE_DEP)
@echo TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS)
@echo TESTFIXTURE_SRC = $(TESTFIXTURE_SRC)
@echo TESTOPTS = $(TESTOPTS)
@echo TESTPROGS = $(TESTPROGS)
@echo TESTSRC = $(TESTSRC)
@echo TLIBS = $(TLIBS)
@echo TOP = $(TOP)
@echo UCRTLIBPATH = $(UCRTLIBPATH)
@echo USE_AMALGAMATION = $(USE_AMALGAMATION)
@echo USE_CRT_DLL = $(USE_CRT_DLL)
@echo USE_FATAL_WARN = $(USE_FATAL_WARN)
@echo USE_FULLWARN = $(USE_FULLWARN)
@echo USE_ICU = $(USE_ICU)
@echo USE_LISTINGS = $(USE_LISTINGS)
@echo USE_NATIVE_LIBPATHS = $(USE_NATIVE_LIBPATHS)
@echo USE_RC = $(USE_RC)
@echo USE_RUNTIME_CHECKS = $(USE_RUNTIME_CHECKS)
@echo USE_SEH = $(USE_SEH)
@echo USE_STDCALL = $(USE_STDCALL)
@echo USE_ZLIB = $(USE_ZLIB)
@echo XCOMPILE = $(XCOMPILE)
@echo ZLIBCFLAGS = $(ZLIBCFLAGS)
@echo ZLIBDIR = $(ZLIBDIR)
@echo ZLIBINCDIR = $(ZLIBINCDIR)
@echo ZLIBLIBDIR = $(ZLIBLIBDIR)
@echo ZLIBLIB = $(ZLIBLIB)
moreclean: clean
del /Q $(SQLITE3C) $(SQLITE3H) 2>NUL
# <</mark>>
@@ -2939,7 +2841,6 @@ clean:
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL
del /Q changeset.exe 2>NUL
del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
del /Q fp-speed-1.exe fp-speed-2.exe 2>NUL
del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL
del /Q sqlite3rc.h 2>NUL
@@ -2954,5 +2855,4 @@ clean:
del /Q fts5.* fts5parse.* 2>NUL
del /q src-verify.exe 2>NUL
del /q jimsh.exe jimsh0.exe 2>NUL
-$(TCLSH_CMD) test/testrunner.tcl clean
# <</mark>>
+54 -56
View File
@@ -1,9 +1,8 @@
<h1 align="center">SQLite Source Repository</h1>
This repository contains the complete source code for the
[SQLite database engine](https://sqlite.org/) going back
to 2000-05-29. The tree includes many tests and some
documentation, though additional tests and most documentation
[SQLite database engine](https://sqlite.org/), including
many tests. Additional tests and most documentation
are managed separately.
See the [on-line documentation](https://sqlite.org/) for more information
@@ -33,11 +32,10 @@ verify its integrity, there are hints on how to do that in the
## Contacting The SQLite Developers
The preferred way to ask questions or make comments about SQLite is to
visit the [SQLite Forum](https://sqlite.org/forum) at
<https://sqlite.org/forum/>. Anonymous postings are permitted. For
bug reports, please use the [SQLite bugs
forum](https://sqlite.org/bugs) at <https://sqlite.org/bugs>.
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
@@ -81,8 +79,8 @@ Then run commands like this:
fossil open https://sqlite.org/src
The initial "fossil open" command will take two or three minutes. Afterwards,
you can do fast, bandwidth-efficient updates to whatever versions of SQLite you
like. Some examples:
you can do fast, bandwidth-efficient updates to the whatever versions
of SQLite you like. Some examples:
fossil update trunk ;# latest trunk check-in
fossil update release ;# latest official release
@@ -98,21 +96,19 @@ the build products. It is recommended, but not required, that the
build directory be separate from the source directory. Cd into the
build directory and then from the build directory run the configure
script found at the root of the source tree. Then run "make".
See the [compile-for-unix.md](doc/compile-for-unix.md) document for
more detail.
For example:
apt install gcc make tcl-dev ;# Install the necessary build tools
apt install gcc make tcl-dev ;# Make sure you have all the necessary build tools
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
mkdir bld ;# Build happens in a sibling directory
mkdir bld ;# Build will occur in a sibling directory
cd bld ;# Change to the build directory
../sqlite/configure ;# Run the configure script
make sqlite3 ;# The "sqlite3" command-line tool
make sqlite3.c ;# The "amalgamation" source file
make sqldiff ;# The "sqldiff" command-line tool
#### Targets below require tcl-dev ####
make tclextension-install ;# Install the SQLite TCL extension
make sqlite3 ;# Builds the "sqlite3" command-line tool
make sqlite3.c ;# Build the "amalgamation" source file
make sqldiff ;# Builds the "sqldiff" command-line tool
# Makefile targets below this point require tcl-dev
make tclextension-install ;# Build and install the SQLite TCL extension
make devtest ;# Run development tests
make releasetest ;# Run full release tests
make sqlite3_analyzer ;# Builds the "sqlite3_analyzer" tool
@@ -120,15 +116,14 @@ For example:
See the makefile for additional targets. For debugging builds, the
core developers typically run "configure" with options like this:
../sqlite/configure --all --debug CFLAGS='-O0 -g'
../sqlite/configure --enable-all --enable-debug CFLAGS='-O0 -g'
For release builds, the core developers usually do:
../sqlite/configure --all
../sqlite/configure --enable-all
Core deliverables (sqlite3.c, sqlite3) can be built without a TCL, but
many makefile targets require a "tclsh" TCL interpreter version 8.6
or later. The "tclextension-install" target and the test targets that follow
Almost all makefile targets require a "tclsh" TCL interpreter version 8.6 or
later. The "tclextension-install" target and the test targets that follow
all require TCL development libraries too. ("apt install tcl-dev"). It is
helpful, but is not required, to install the SQLite TCL extension (the
"tclextension-install" target) prior to running tests. The "releasetest"
@@ -138,20 +133,20 @@ On "make" command-lines, one can add "OPTIONS=..." to specify additional
compile-time options over and above those set by ./configure. For example,
to compile with the SQLITE_OMIT_DEPRECATED compile-time option, one could say:
./configure --all
./configure --enable-all
make OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3
The configure script uses [autosetup](https://msteveb.github.io/autosetup/).
If the configure script does not work out for you, there is a generic
makefile named "Makefile.linux-gcc" in the top directory of the source tree
that you can copy and edit to suit your needs. Comments on the generic
makefile show what changes are needed.
The configure script uses autoconf 2.61 and libtool. If the configure
script does not work out for you, there is a generic makefile named
"Makefile.linux-gcc" in the top directory of the source tree that you
can copy and edit to suit your needs. Comments on the generic makefile
show what changes are needed.
## Compiling for Windows Using MSVC
On Windows, everything can be compiled with MSVC.
You will also need a working installation of TCL if you want to run tests,
though TCL is not required if you just want to build SQLite itself.
You will also need a working installation of TCL if you want to run tests.
TCL is not required if you just want to build SQLite itself.
See the [compile-for-windows.md](doc/compile-for-windows.md) document for
additional information about how to install MSVC and TCL and configure your
build environment.
@@ -161,25 +156,24 @@ TCL library, using a command like this:
set TCLDIR=c:\Tcl
SQLite itself does not contain any TCL code, but it does use TCL to run
tests. You may need to install TCL development libraries in order to
successfully complete some makefile targets. It is helpful, but is not
required, to install the SQLite TCL extension (the "tclextension-install"
target) prior to running tests.
SQLite uses "tclsh.exe" as part of the build process, and so that
program will need to be somewhere on your %PATH%. SQLite itself
does not contain any TCL code, but it does use TCL to run tests.
You may need to install TCL development
libraries in order to successfully complete some makefile targets.
It is helpful, but is not required, to install the SQLite TCL extension
(the "tclextension-install" target) prior to running tests.
The source tree contains a "make.bat" file that allows the same "make"
commands of Unix to work on Windows. In the following, you can substitute
"nmake /f Makefile.msc" in place of "make", if you prefer to avoid this BAT
file:
Build using Makefile.msc. Example:
make sqlite3.exe
make sqlite3.c
make sqldiff.exe
#### Targets below require TCL development libraries ####
make tclextension-install
make devtest
make releasetest
make sqlite3_analyzer.exe
nmake /f Makefile.msc sqlite3.exe
nmake /f Makefile.msc sqlite3.c
nmake /f Makefile.msc sqldiff.exe
# Makefile targets below this point require TCL development libraries
nmake /f Makefile.msc tclextension-install
nmake /f Makefile.msc devtest
nmake /f Makefile.msc releasetest
nmake /f Makefile.msc sqlite3_analyzer.exe
There are many other makefile targets. See comments in Makefile.msc for
details.
@@ -187,7 +181,7 @@ details.
As with the unix Makefile, the OPTIONS=... argument can be passed on the nmake
command-line to enable new compile-time options. For example:
make OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3.exe
nmake /f Makefile.msc OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3.exe
## Source Tree Map
@@ -200,7 +194,8 @@ command-line to enable new compile-time options. For example:
* **test/** - This directory and its subdirectories contains code used
for testing. Files that end in "`.test`" are TCL scripts that run
tests using an augmented TCL interpreter named "testfixture". Use
a command like "`make testfixture`" to build that
a command like "`make testfixture`" (unix) or
"`nmake /f Makefile.msc testfixture.exe`" (windows) to build that
augmented TCL interpreter, then run individual tests using commands like
"`testfixture test/main.test`". This test/ subdirectory also contains
additional C code modules and scripts for other kinds of testing.
@@ -382,11 +377,10 @@ implementation. It will not be the easiest library in the world to hack.
(and some other test programs too) is built and run when you type
"make test".
* **VERSION**, **manifest**, **manifest.tags**, and **manifest.uuid** -
These files define the current SQLite version number. The "VERSION" file
is human generated, but the "manifest", "manifest.tags", and
"manifest.uuid" files are automatically generated by the
[Fossil version control system](https://fossil-scm.org/).
* **VERSION**, **manifest**, and **manifest.uuid** - These files define
the current SQLite version number. The "VERSION" file is human generated,
but the "manifest" and "manifest.uuid" files are automatically generated
by the [Fossil version control system](https://fossil-scm.org/).
There are many other source files. Each has a succinct header comment that
describes its purpose and role within the larger system.
@@ -412,6 +406,10 @@ 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.
+1 -1
View File
@@ -1 +1 @@
3.54.0
3.52.0
+1 -1
View File
@@ -282,7 +282,7 @@ DIST_FILES := \
README.txt VERSION \
auto.def autosetup configure tea \
sqlite3.h sqlite3.c shell.c sqlite3ext.h \
Makefile.in Makefile.msc Makefile.fallback make.bat \
Makefile.in Makefile.msc Makefile.fallback \
sqlite3.rc sqlite3rc.h Replace.cs \
sqlite3.pc.in sqlite3.1
+90 -14
View File
@@ -101,6 +101,13 @@ NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706
!ENDIF
!ENDIF
# Set this non-0 to use the library paths and other options necessary for
# Windows Phone 8.1.
#
!IFNDEF USE_WP81_OPTS
USE_WP81_OPTS = 0
!ENDIF
# Set this non-0 to split the SQLite amalgamation file into chunks to
# be used for debugging with Visual Studio.
#
@@ -149,6 +156,14 @@ USE_NATIVE_LIBPATHS = 0
USE_RC = 1
!ENDIF
# Set this non-0 to compile binaries suitable for the WinRT environment.
# This setting does not apply to any binaries that require Tcl to operate
# properly (i.e. the text fixture, etc).
#
!IFNDEF FOR_WINRT
FOR_WINRT = 0
!ENDIF
# Set this non-0 to compile binaries suitable for the UWP environment.
# This setting does not apply to any binaries that require Tcl to operate
# properly (i.e. the text fixture, etc).
@@ -548,14 +563,10 @@ RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) $(RCOPTS) $(RCCOPTS)
!IF "$(PLATFORM)"=="x86"
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
!ELSE
!IFNDEF PLATFORM
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
!ELSE
CORE_CCONV_OPTS =
SHELL_CCONV_OPTS =
@@ -656,6 +667,18 @@ SHELL_LINK_OPTS = $(SHELL_CORE_LIB)
TCC = $(TCC) -FAcs
!ENDIF
# When compiling the library for use in the WinRT environment,
# the following compile-time options must be used as well to
# disable use of Win32 APIs that are not available and to enable
# use of Win32 APIs that are specific to Windows 8 and/or WinRT.
#
!IF $(FOR_WINRT)!=0
TCC = $(TCC) -DSQLITE_OS_WINRT=1
RCC = $(RCC) -DSQLITE_OS_WINRT=1
TCC = $(TCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
!ENDIF
# C compiler options for the Windows 10 platform (needs MSVC 2015).
#
!IF $(FOR_WIN10)!=0
@@ -668,29 +691,35 @@ BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
# USE_CRT_DLL option is set to force dynamically linking to the
# MSVC runtime library.
#
!IF $(USE_CRT_DLL)!=0
!IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
ZLIBCFLAGS = -nologo -MDd -W3 -O2 -Oy- -Zi
!ELSE
TCC = $(TCC) -MD
BCC = $(BCC) -MD
ZLIBCFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi
!ENDIF
!ELSE
!IF $(DEBUG)>1
TCC = $(TCC) -MTd
BCC = $(BCC) -MTd
ZLIBCFLAGS = -nologo -MTd -W3 -O2 -Oy- -Zi
!ELSE
TCC = $(TCC) -MT
BCC = $(BCC) -MT
ZLIBCFLAGS = -nologo -MT -W3 -O2 -Oy- -Zi
!ENDIF
!ENDIF
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
# Omitting the define will cause extra debugging code to be inserted and
# includes extra comments when "EXPLAIN stmt" is used.
#
!IF $(DEBUG)==0
TCC = $(TCC) -DNDEBUG
BCC = $(BCC) -DNDEBUG
RCC = $(RCC) -DNDEBUG
!ENDIF
!IF $(DEBUG)>0 || $(API_ARMOR)!=0 || $(FOR_WIN10)!=0
TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR=1
RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
@@ -880,6 +909,56 @@ LTLINKOPTS = /NOLOGO
LTLIBOPTS = /NOLOGO
!ENDIF
# When compiling for use in the WinRT environment, the following
# linker option must be used to mark the executable as runnable
# only in the context of an application container.
#
!IF $(FOR_WINRT)!=0
LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER
!IF "$(VISUALSTUDIOVERSION)"=="12.0" || "$(VISUALSTUDIOVERSION)"=="14.0"
!IFNDEF STORELIBPATH
!IF "$(PLATFORM)"=="x86"
STORELIBPATH = $(CRTLIBPATH)\store
!ELSEIF "$(PLATFORM)"=="x64"
STORELIBPATH = $(CRTLIBPATH)\store\amd64
!ELSEIF "$(PLATFORM)"=="ARM"
STORELIBPATH = $(CRTLIBPATH)\store\arm
!ELSE
STORELIBPATH = $(CRTLIBPATH)\store
!ENDIF
!ENDIF
STORELIBPATH = $(STORELIBPATH:\\=\)
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(STORELIBPATH)"
!ENDIF
!ENDIF
# When compiling for Windows Phone 8.1, an extra library path is
# required.
#
!IF $(USE_WP81_OPTS)!=0
!IFNDEF WP81LIBPATH
!IF "$(PLATFORM)"=="x86"
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
!ELSEIF "$(PLATFORM)"=="ARM"
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\ARM
!ELSE
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
!ENDIF
!ENDIF
!ENDIF
# When compiling for Windows Phone 8.1, some extra linker options
# are also required.
#
!IF $(USE_WP81_OPTS)!=0
!IFDEF WP81LIBPATH
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
!ENDIF
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
!ENDIF
# When compiling for UWP or the Windows 10 platform, some extra linker
# options are also required.
#
@@ -903,9 +982,9 @@ LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
LDFLAGS = /NODEFAULTLIB:msvcrt /DEBUG $(LDOPTS)
LDFLAGS = /DEBUG $(LDOPTS)
!ELSE
LDFLAGS = /NODEFAULTLIB:msvcrt $(LDOPTS)
LDFLAGS = $(LDOPTS)
!ENDIF
@@ -941,7 +1020,6 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_PERCENTILE=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
!ENDIF
@@ -990,8 +1068,6 @@ $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLIT
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
tclsqlite-ex.c:
# Rule to build the amalgamation
#
sqlite3.lo: $(SQLITE3C)
+1 -11
View File
@@ -375,11 +375,6 @@ configure process, and check it in.
Patching Autosetup for Project-local Changes
------------------------------------------------------------------------
The autosetup files require the following patches after updating
from their upstream sources:
### `--debug` flag
Autosetup reserves the flag name **`--debug`** for its own purposes,
and its own special handling of `--enable-...` flags makes `--debug`
an alias for `--enable-debug`. As this project has a long history of
@@ -393,11 +388,6 @@ If autosetup is upgraded and this patch is _not_ applied the invoking
`./configure` will fail loudly because of the declaration of the
`debug` flag in `auto.def` - duplicated flags are not permitted.
### Fail on `malloc()` error
See [check-in 72c8a5b94cdf5d](/info/72c8a5b94cdf5d).
<a name="branch-customization"></a>
Branch-specific Customization
========================================================================
@@ -461,4 +451,4 @@ all other significant processing.
[sqlite-config.tcl]: /file/autosetup/sqlite-config.tcl
[Makefile.in]: /file/Makefile.in
[main.mk]: /file/main.mk
[JimTCL]: https://msteveb.github.io/jimtcl/
[JimTCL]: https://jim.tcl.tk
+960 -1647
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -1842,7 +1842,7 @@ proc proj-setup-autoreconfig {defName} {
}
#
# @prop-define-append defineName args...
# @prop-append-to defineName args...
#
# A proxy for Autosetup's [define-append]. Appends all non-empty $args
# to [define-append $defineName].
@@ -1873,7 +1873,7 @@ proc proj-define-append {defineName args} {
# but it is technically correct and still relevant on some
# environments.
#
# See: proj-define-append
# See: proj-append-to
#
proc proj-define-amend {args} {
set defName ""
@@ -2028,7 +2028,7 @@ array set proj__Cache {}
# Returns a cache key for the given argument:
#
# integer: relative call stack levels to get the scope name of for
# use as a key. [proj-scope [expr {1 + $arg + $addLevel}]] is
# use as a key. [proj-scope [expr {1 + $arg + addLevel}]] is
# then used to generate the key. i.e. the default of 0 uses the
# calling scope's name as the key.
#
@@ -2226,7 +2226,7 @@ proc proj-coalesce {args} {
#
# Pragmas:
#
# The prototype list may contain :PRAGMAS to modify how it works. The
# Passing :PRAGMAS to this function may modify how it works. The
# following pragmas are supported (note the leading ":"):
#
# :all-flags indicates that the whole input list should be scanned,
+23 -69
View File
@@ -466,7 +466,7 @@ proc sqlite-configure {buildMode configScript} {
proc sqlite-configure-phase1 {buildMode} {
define PACKAGE_NAME sqlite
define PACKAGE_URL {https://sqlite.org}
define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/bugs
define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
define PACKAGE_STRING "[get-define PACKAGE_NAME] [get-define PACKAGE_VERSION]"
proj-xfer-options-aliases {
# Carry values from hidden --flag aliases over to their canonical
@@ -679,7 +679,6 @@ proc sqlite-check-common-system-deps {} {
define HAVE_ZLIB 1
define LDFLAGS_ZLIB -lz
sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
sqlite-add-feature-flag -DSQLITE_HAVE_ZLIB=1
} else {
define HAVE_ZLIB 0
define LDFLAGS_ZLIB ""
@@ -743,11 +742,12 @@ proc sqlite-setup-default-cflags {} {
# compiling binaries for the target system (CC a.k.a. $(T.cc)).
# Normally they're the same, but they will differ when
# cross-compiling.
#
# When cross-compiling we default to not using the -g flag, based on a
# /chat discussion prompted by
# https://sqlite.org/forum/forumpost/9a67df63eda9925c
set defaultCFlags {-O2}
if {!$::sqliteConfig(is-cross-compiling)} {
# When cross-compiling we default to not using the -g flag, based
# on a /chat discussion prompted by
# https://sqlite.org/forum/forumpost/9a67df63eda9925c
lappend defaultCFlags -g
}
define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
@@ -805,8 +805,7 @@ proc sqlite-handle-common-feature-flags {} {
sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
}
}
bytecode-vtab -DSQLITE_ENABLE_BYTECODE_VTAB {}
scanstatus {-DSQLITE_ENABLE_STMT_SCANSTATUS -DSQLITE_ENABLE_BYTECODE_VTAB} {}
scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
column-metadata -DSQLITE_ENABLE_COLUMN_METADATA {}
dbpage -DSQLITE_ENABLE_DBPAGE_VTAB {}
dbstat -DSQLITE_ENABLE_DBSTAT_VTAB {}
@@ -1067,7 +1066,7 @@ proc sqlite-get-readline-dir-list {} {
}
*-haiku {
lappend dirs /boot/system/develop/headers
if {![opt-bool editline] && [opt-val with-readline-ldflags] in {auto ""}} {
if {[opt-val with-readline-ldflags] in {auto ""}} {
# If the user did not supply their own --with-readline-ldflags
# value, hijack that flag to inject options which are known to
# work on Haiku OS installations.
@@ -1094,30 +1093,16 @@ proc sqlite-get-readline-dir-list {} {
# - HAVE_LINENOISE to 0, 1, or 2
# - HAVE_EDITLINE to 0 or 1
#
# Those will be set as follows:
#
# HAVE_LINENOISE=0, HAVE_EDITLINE=0, HAVE_READLINE=0: no line editing
#
# HAVE_LINENOISE>0: 1=antirez flavor, 2=msteveb flavor
#
# HAVE_EDITLINE=0, HAVE_READLINE=1: use GNU readline
#
# HAVE_EDITLINE=1, HAVE_READLINE=1: use BSD editline header
# <readline/readline.h>.
#
# HAVE_EDITLINE=1, HAVE_READLINE=0: use BSD editline header
# <editline/readline.h>.
#
# Other defines it sets:
# Only one of ^^^ those will be set to non-0.
#
# - LDFLAGS_READLINE = linker flags or empty string
#
# - CFLAGS_READLINE = compilation flags for clients or empty string.
#
# Both LDFLAGS_READLINE and CFLAGS_READLINE may refer to linenoise or
# editline, not necessarily libreadline. In some cases it will set
# HAVE_READLINE=1 when it's really using editline, for reasons
# described in this function's comments.
# Note that LDFLAGS_READLINE and CFLAGS_READLINE may refer to
# linenoise or editline, not necessarily libreadline. In some cases
# it will set HAVE_READLINE=1 when it's really using editline, for
# reasons described in this function's comments.
#
# Returns a string describing which line-editing approach to use, or
# "none" if no option is available.
@@ -1151,27 +1136,6 @@ proc sqlite-check-line-editing {} {
set editLibName "readline" ; # "readline" or "editline"
set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
set dirLn [opt-val with-linenoise]
# If none of --with-linenoise, --enable-readline, or --enable-editline
# are provided, but there exists a directory "linenoise" at $HOME or
# a sibling of the build or source directory, then try to use that linenoise
# directory.
#
if {"" eq $dirLn
&& ![proj-opt-was-provided readline]
&& ![proj-opt-was-provided editline]
} {
set dirlist ../linenoise
catch {lappend dirlist [file-normalize $::autosetup(srcdir)/../linenoise]}
catch {lappend dirlist $::env(HOME)/linenoise}
foreach d $dirlist {
if {[file exists $d/linenoise.c] && [file exists $d/linenoise.h]} {
set dirLn $d
break
}
}
}
if {"" ne $dirLn} {
# Use linenoise from a copy of its sources (not a library)...
if {![file isdir $dirLn]} {
@@ -1207,8 +1171,6 @@ proc sqlite-check-line-editing {} {
if {$::sqliteConfig(use-jim-for-codegen) && 2 == $lnVal} {
define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE]
user-notice "Adding linenoise support to jimsh."
} else {
msg-result "Using linenoise at [file-normalize $dirLn]"
}
return "linenoise ($flavor)"
} elseif {[opt-bool editline]} {
@@ -1319,18 +1281,14 @@ proc sqlite-check-line-editing {} {
# If we found a library, configure the build to use it...
if {"" ne $rlLib} {
if {"editline" eq $editLibName} {
# sqlite-add-shell-opt -DEL_WIDECHAR=1;
if {"HAVE_READLINE" eq $editLibDef} {
sqlite-add-shell-opt -DHAVE_EDITLINE=1
# Alert the user that, despite outward appearances, we won't be
# linking to the GPL'd libreadline. Presumably that distinction is
# significant for those using --editline.
proj-indented-notice {
NOTE: the local libedit uses <readline/readline.h> so we
will compile with -DHAVE_READLINE=1 but will link with
libedit.
}
if {"editline" eq $editLibName && "HAVE_READLINE" eq $editLibDef} {
# Alert the user that, despite outward appearances, we won't be
# linking to the GPL'd libreadline. Presumably that distinction is
# significant for those using --editline.
proj-indented-notice {
NOTE: the local libedit uses <readline/readline.h> so we
will compile with -DHAVE_READLINE=1 but will link with
libedit.
}
}
set rlLib [join $rlLib]
@@ -1763,12 +1721,8 @@ proc sqlite-handle-env-quirks {} {
set autoDll 0; # true if --out-implib/--dll-basename should be implied
set host [get-define host]
switch -glob -- $host {
*-*-darwin* {
set instName darwin
# We don't look for *apple* because:
# https://sqlite.org/forum/forumpost/7b218c3c9f207646
# There's at least one Linux out there which matches *apple*.
}
*apple* -
*darwin* { set instName darwin }
default {
set x [sqlite-env-is-unix-on-windows $host]
if {"" ne $x} {
@@ -2064,7 +2018,7 @@ proc sqlite-check-tcl {} {
}
}
if {![file-isexec $with_tclsh]} {
proj-warn "Cannot find a usable tclsh (tried: $tryThese)"
proj-warn "Cannot find a usable tclsh (tried: $tryThese)
}
}
define TCLSH_CMD $with_tclsh
+7 -33
View File
@@ -22,10 +22,9 @@ guidance on building for Windows.
or <https://sqlite.org/tmp/tcl9.0.0.tar.gz>.
<li>Untar the source archive. CD into the "unix/" subfolder
of the source tree.
<li>Run: &ensp; `mkdir $HOME/local`
<li>Run: &ensp; `./configure --prefix=$HOME/local`<br>
SQLite deliverable builds add: &emsp; `--static CFLAGS=-Os`
<li>Run: &ensp; `make install`
<li>Run: `mkdir $HOME/local`
<li>Run: `./configure --prefix=$HOME/local`
<li>Run: `make install`
</ol>
<p>
As of 2024-10-25, TCL is not longer required for many
@@ -37,35 +36,12 @@ guidance on building for Windows.
4. Download the SQLite source tree and unpack it. CD into the
toplevel directory of the source tree.
5. *(Optional):* Download Antirez's "linenoise" command-line editing
library to provide command-line editing in the CLI. You can find
a suitable copy of the linenoise sources at
<https://sqlite.org/linenoise.tar.gz> or at various other locations
on the internet. If you put the linenoise source tree in
a directory named $HOME/linenoise or a directory "linenoise" which
is a sibling of the SQLite source tree, then the SQLite ./configure
script will automatically find and use that source code to provide
command-line editing in the CLI. If you would rather use the readline
or editline libraries or a precompiled linenoise library, there are
./configure options to accommodate that choice. The SQLite developers
typically use $HOME/linenoise since linenoise is small, has no
external dependencies, "just works", and the ./configure script
will pick it up and use it automatically. But you do what works
best for you.
<p>
You are not required to have any command-line editing support in
order to use SQLite. But command-line editing does make the
interactive experience more enjoyable.
6. Run: `./configure --enable-all --with-tclsh=$HOME/local/bin/tclsh9.0`
5. Run: `./configure --enable-all --with-tclsh=$HOME/local/bin/tclsh9.0`
You do not need to use --with-tclsh if the tclsh you want to use is the
first one on your PATH or if you are building without TCL.
Lots of other options to ./configure are available.
Run `./configure --help` for further guidance.
7. Run the "`Makefile`" makefile with an appropriate target.
6. Run the "`Makefile`" makefile with an appropriate target.
Examples:
<ul>
<li> `make sqlite3.c`
@@ -90,7 +66,5 @@ guidance on building for Windows.
of SQLite.
8. For a debugging build of the CLI, use `./configure --dev`. A debugging
build contains lots of extra debugging code, so it is slow and a lot
bigger. You probably do not want to deploy a debugging build. But if
you are working on the code, a debugging build works much better.
7. For a debugging build of the CLI, where the ".treetrace" and ".wheretrace"
commands work, add the the --with-debug argument to configure.
-36
View File
@@ -180,39 +180,3 @@ statically linked so that it does not depend on separate DLL:
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>
## Linking Against ZLIB
Some feature (such as zip-file support in the CLI) require the ZLIB
compression library. That library is more or less universally available
on unix platforms, but is seldom provided on Windows. You will probably
need to provide it yourself. Here the the steps needed:
1. Download the zlib-1.3.1.tar.gz tarball (or a similar version).
Unpack the tarball sources. You can put them wherever you like.
For the purposes of this document, let's assume you put the source
tree in c:\\zlib-64. Note: If you are building for both x64 and
x86, you will need separate builds of ZLIB for each, thus separate
build directories.
2. Before building SQLite (as described above) first make these
environment changes. The lead-programmer for SQLite (who writes
these words) has BAT files named "env-x64.bat" and "env-x32.bat"
and "env-arm64.bat" that make these changes, and he runs those
BAT file whenever he starts a new shell. These are the settings
needed:
<blockquote>
set USE_ZLIB=1<br>
set BUILD_ZLIB=0<br>
set ZLIBDIR=c:\\zlib-64
</blockquote>
3. Because the settings in step 2 specify "BUILD_ZLIB=0", you will need
to build the library at least once. I recommand:
<blockquote>
make clean sqlite3.exe BUILD_ZLIB=1
</blockquote>
4. After making the environment changes specified in steps 1 through 3
above, you then build and test SQLite as you normally would. The
environment variable changes will cause ZLIB to be linked automatically.
+24 -23
View File
@@ -695,8 +695,8 @@ other than that, the order of directives in Lemon is arbitrary.</p>
<li><tt><a href='#parse_failure'>%parse_failure</a></tt>
<li><tt><a href='#pright'>%right</a></tt>
<li><tt><a href='#reallc'>%realloc</a></tt>
<li><tt><a href='#reallc'>%reallocx</a></tt>
<li><tt><a href='#stack_overflow'>%stack_overflow</a></tt>
<li><tt><a href='#reallc'>%stack_size_limit</a></tt>
<li><tt><a href='#stack_size'>%stack_size</a></tt>
<li><tt><a href='#start_symbol'>%start_symbol</a></tt>
<li><tt><a href='#syntax_error'>%syntax_error</a></tt>
@@ -1204,33 +1204,34 @@ the wildcard token and some other token, the other token is always used.
The wildcard token is only matched if there are no alternatives.</p>
<a id='reallc'></a>
<h4>4.4.26 The <tt>%realloc</tt>, <tt>%free</tt>, and
<tt>%stack_size_limit</tt> directives</h4>
<h4>4.4.26 The <tt>%realloc</tt>, <tt>%reallocx</tt>,
and <tt>%free</tt> directives</h4>
<p>The <tt>%realloc</tt> and <tt>%free</tt> directives defines function
that allocate and free heap memory. The signatures and semantics of
these functions are similar to the realloc() and free() functions from
the standard C library, except that these functions take an extra
parameter at the end that is determined by %extra_context. If
%extra_context is not defined, then the extra argument is 0. The
extra parameter provides the capability to do better error reporting
in the event of a memory allocation error, and/or to use an alternative
private application heap.
<p>The <tt>%realloc</tt>, <tt>%reallocx</tt>, and <tt>%free</tt>
directives defines function that allocate and free heap memory.
The signatures of th3 %realloc and %free are the same as
realloc() and free() functions from the standard C library.
The %reallocx function has the same semantics as %realloc but
takes four parameters instead of two:
<ol>
<li> A pointer to the space to be reallocated, or NULL for a new allocation,
<li> The number of elements to allocate,
<li> The size of each element,
<li> The %extra parameter.
</ol>
The extra parameters of %reallocx can be used, for example, to monitor
the parser stack size and raise an error if it exceeds application-defined
limits.
If both %reallocx and %realloc are defined, then %reallocx is used
and %realloc is ignored.
<p>If both of these functions are defined then they are used to
allocate and free memory for supplemental parser stack space, if
the initial parse stack space is exceeded. The initial parser stack size
<p>If %free is defined and one of %realloc and %reallocx is
defined then the functions are used to allocate and free
memory for supplemental parser stack space, if the initial
parse stack space is exceeded. The initial parser stack size
is specified by either <tt>%stack_size</tt> or the
-DYYSTACKDEPTH compile-time flag.
<p>The <tt>%stack_size_limit</tt> directive defines a function that returns
the maximum allowed parser stack size. If this diretive does not exist,
no size limit is enforced. This function takes a single argument which
is the %extra_context value or "0" if %extra_context is not defined.
The function should return an integer that is the maximum
number of parser stack entries. If more stack space
than this is needed, the %stack_overflow code is invoked.
<a id='errors'></a>
<h2>5.0 Error Processing</h2>
+57 -107
View File
@@ -4,12 +4,6 @@
<ul type=none>
<li> 1. <a href=#overview>Overview</a>
<ul type=none>
<li> 1.1. <a href=#runtr>Running testrunner.tcl</a>
<li> 1.2. <a href=#runviamake>Run using "make"</a>
<li> 1.3. <a href=#outputs>Outputs from testrunner.tcl</a>
<li> 1.4. <a href=#help>Built-in help</a>
</ul>
<li> 2. <a href=#binary_tests>Binary Tests</a>
<ul type=none>
<li> 2.1. <a href=#organization_tests>Organization of Tcl Tests</a>
@@ -32,45 +26,17 @@
The testrunner.tcl program is a Tcl script used to run multiple SQLite
tests in parallel, thus reducing testing time on multi-core machines.
The testrunner.tcl supports running tests that based on `testfixture`,
`sqlite3`, `fuzzcheck`, and C programs found in test/c.
It supports the following types of tests:
<a name="runtr"></a>
## 1.1 Running testrunner.tcl
* Tcl test scripts.
The testrunner.tcl script is located in the "test" subdirectory of the
SQLite source tree. So if your shell is current positioned at the top
of the source tree, you would normally run the script using the command:
"<tt>test/testrunner.tcl</tt>". On Windows, you have to specify the
`tclsh` interpreter command first, like this:
"<tt>tclsh&nbsp;test/testrunner.tcl</tt>".
* Fuzzcheck tests, including using an external fuzzcheck database.
In this document, we will assume that you are on a unix-like OS
(not on Windows) and that your current directory is the root
of the SQLite source tree, and so all invocations of the testrunner.tcl
script will be of the form "<tt>test/testrunner.tcl</tt>". If you
are in a different directory, then make appropriate adjustments to
the path. On Windows, add the "<tt>tclsh</tt>" interpreter command
up front.
<a name="runviamake"></a>
## 1.2 Run using make
The standard Makefiles for SQLite include targets that invoke
testrunner.tcl. So the following commands also run testrunner.tcl:
* `make test`
* `make devtest`
* `make releasetest`
* `make sdevtest`
* `make testrunner`
Since SQLite 3.53.0, there is a "<tt>make.bat</tt>" script in the root
of the source tree that causes the "make" command to work on Windows.
There is no need to do something different using "nmake" on Windows.
<a name="outputs"></a>
## 1.3 Outputs from testrunner.tcl
* Tests run with `make` commands. Examples:
- `make devtest`
- `make releasetest`
- `make sdevtest`
- `make testrunner`
The testrunner.tcl program stores output of all tests and builds run in
log file **testrunner.log**, created in the current working directory.
@@ -88,19 +54,17 @@ A useful query might be:
```
You can get a summary of errors in a prior run by invoking commands like
those shown below. Note that the testrunner.tcl script can be run directly
on unix systems (including Macs) but you will need to add <tt>tclsh</tt>
to the front on Windows.
these:
```
test/testrunner.tcl errors
test/testrunner.tcl errors -v
tclsh $(TESTDIR)/testrunner.tcl errors
tclsh $(TESTDIR)/testrunner.tcl errors -v
```
Running the command:
```
test/testrunner.tcl status
tclsh $(TESTDIR)/testrunner.tcl status
```
in the directory containing the testrunner.db database runs various queries
@@ -109,43 +73,32 @@ A good way to keep and eye on test progress is to run either of the two
following commands:
```
watch test/testrunner.tcl status
test/testrunner.tcl status -d 2
watch tclsh $(TESTDIR)/testrunner.tcl status
tclsh $(TESTDIR)/testrunner.tcl status -d 2
```
Both of the commands above accomplish about the same thing, but the second
one has the advantage of not requiring "watch" to be installed on your
system.
Sometimes testrunner.tcl uses the `testfixture` and `sqlite3` binaries that
are in the directory from which testrunner.tcl is run.
(see "Binary Tests" below). Sometimes it builds testfixture and
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=help></a>
## 1.4 Built-in help
Run this command:
```
test/testrunner.tcl help
```
To get a summary of all of the various command-line options available
with testrunner.tcl
<a name=binary_tests></a>
# 2. Binary Tests
The commands described in this section all run various combinations of the Tcl
test scripts using whatever `testfixture` binary (and maybe also the `sqlite3`
binary, depending on the test) that is found in the directory from which
testrunner.tcl is launched. So typically, one must first run something
like "`make testfixture sqlite3`" before launching binary tests. In other
words, testrunner.tcl does not automatically build the binaries under test
for binary tests. The testrunner.tcl expects the binaries to be available
already.
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.
@@ -187,22 +140,22 @@ are defined in file *testrunner_data.tcl*.
To run the "veryquick" test set, use either of the following:
```
test/testrunner.tcl
test/testrunner.tcl veryquick
./testfixture $TESTDIR/testrunner.tcl
./testfixture $TESTDIR/testrunner.tcl veryquick
```
To run the "full" test suite:
```
test/testrunner.tcl full
./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:
```
test/testrunner.tcl fts5%
test/testrunner.tcl 'fts5*'
./testfixture $TESTDIR/testrunner.tcl fts5%
./testfixture $TESTDIR/testrunner.tcl 'fts5*'
```
Strictly speaking, for a test to be run the pattern must match the script
@@ -214,7 +167,7 @@ characters specified as part of the pattern are transformed to "\*".
To run "all" tests (full + permutations):
```
test/testrunner.tcl all
./testfixture $TESTDIR/testrunner.tcl all
```
<a name=binary_test_failures></a>
@@ -233,15 +186,10 @@ If there is no permutation, the individual test script may be run with:
Or, if the failure occured as part of a permutation:
```
test/testrunner.tcl $PERMUTATION $PATH_TO_SCRIPT
./testfixture $TESTDIR/testrunner.tcl $PERMUTATION $PATH_TO_SCRIPT
```
One can also rerun all tests that failed or did not complete
in the previous invocation by typing:
```
test/testrunner.tcl retest
```
TODO: An example instead of "$PERMUTATION" and $PATH\_TO\_SCRIPT?
<a name=source_code_tests></a>
# 3. Source Code Tests
@@ -256,9 +204,11 @@ other tests. The advantages of this are that:
* 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 do not require that
the testfixture and/or sqlite3 binaries be built ahead of time. Those
binaries will be constructed automatically.
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
@@ -268,7 +218,7 @@ the `make fuzztest` target once for each of two --enable-all builds - one
with debugging enabled and one without:
```
test/testrunner.tcl mdevtest
tclsh $TESTDIR/testrunner.tcl mdevtest
```
In other words, it is equivalent to running:
@@ -277,13 +227,13 @@ In other words, it is equivalent to running:
$TOP/configure --enable-all --enable-debug
make fuzztest
make testfixture
$TOP/test/testrunner.tcl veryquick
./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
$TOP/test/testrunner.tcl veryquick
./testfixture $TOP/test/testrunner.tcl veryquick
```
The **sdevtest** command is identical to the mdevtest command, except that the
@@ -291,7 +241,7 @@ second of the two builds is a sanitizer build. Specifically, this means that
OPTS="-fsanitize=address,undefined" is specified instead of OPTS="-O0":
```
test/testrunner.tcl sdevtest
tclsh $TESTDIR/testrunner.tcl sdevtest
```
The **release** command runs lots of tests under lots of builds. It runs
@@ -300,7 +250,7 @@ on Linux, Windows or OSX. Refer to *testrunner\_data.tcl* for the details
of the specific tests run.
```
test/testrunner.tcl release
tclsh $TESTDIR/testrunner.tcl release
```
As with <a href=#source code tests>source code tests</a>, one or more patterns
@@ -308,7 +258,7 @@ may be appended to any of the above commands (mdevtest, sdevtest or release).
Pattern matching is used for both Tcl tests and fuzz tests.
```
test/testrunner.tcl release rtree%
tclsh $TESTDIR/testrunner.tcl release rtree%
```
<a name=zipvfs_tests></a>
@@ -318,14 +268,14 @@ testrunner.tcl can build a zipvfs-enabled testfixture and use it to run
tests from the Zipvfs project with the following command:
```
test/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS
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:
```
test/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
```
<a name=source_code_test_failures></a>
@@ -345,10 +295,10 @@ a dos \*.bat file on windows. For example:
```
# Create a script that recreates build configuration "Device-One" on
# Linux or OSX:
test/testrunner.tcl script Device-One > make.sh
tclsh $TESTDIR/testrunner.tcl script Device-One > make.sh
# Create a script that recreates build configuration "Have-Not" on Windows:
test/testrunner.tcl script Have-Not > make.bat
tclsh $TESTDIR/testrunner.tcl script Have-Not > make.bat
```
The generated bash or \*.bat file script accepts a single argument - a makefile
@@ -371,7 +321,7 @@ Thus, for example, to run a full releasetest including an external
dbsqlfuzz database, run a command like one of these:
```
test/testrunner.tcl releasetest --fuzzdb ../fuzz/20250415.db
tclsh test/testrunner.tcl releasetest --fuzzdb ../fuzz/20250415.db
FUZZDB=../fuzz/20250415.db make releasetest
nmake /f Makefile.msc FUZZDB=../fuzz/20250415.db releasetest
```
@@ -381,7 +331,7 @@ databases. So if you want to run *only* tests involving the external
database, you can use a command something like this:
```
test/testrunner.tcl releasetest 20250415 --fuzzdb ../fuzz/20250415.db
tclsh test/testrunner.tcl releasetest 20250415 --fuzzdb ../fuzz/20250415.db
```
<a name=testrunner_options></a>
@@ -395,7 +345,7 @@ required by a test, not to run any actual tests. For example:
```
# Build binaries required by release test.
test/testrunner.tcl --buildonly release"
tclsh $TESTDIR/testrunner.tcl --buildonly release"
```
The **--dryrun** option prevents testrunner.tcl from building any binaries
@@ -404,7 +354,7 @@ would normally execute into the testrunner.log file. Example:
```
# Log the shell commmands that make up the mdevtest test.
test/testrunner.tcl --dryrun mdevtest"
tclsh $TESTDIR/testrunner.tcl --dryrun mdevtest"
```
The **--explain** option is similar to --dryrun in that it prevents
@@ -414,7 +364,7 @@ summary of all the builds and tests that would have been run.
```
# Show what builds and tests would have been run
test/testrunner.tcl --explain mdevtest
tclsh $TESTDIR/testrunner.tcl --explain mdevtest
```
The **--status** option uses VT100 escape sequences to display the test
@@ -430,7 +380,7 @@ When running either binary or source code tests, testrunner.tcl reports the
number of jobs it intends to use to stdout. e.g.
```
$ test/testrunner.tcl
$ ./testfixture $TESTDIR/testrunner.tcl
splitting work across 16 jobs
... more output ...
```
@@ -440,7 +390,7 @@ of real cores on the machine. This can be overridden using the "--jobs" (or -j)
switch:
```
$ test/testrunner.tcl --jobs 8
$ ./testfixture $TESTDIR/testrunner.tcl --jobs 8
splitting work across 8 jobs
... more output ...
```
@@ -450,5 +400,5 @@ running by exucuting the following command from the directory containing the
testrunner.log and testrunner.db files:
```
$ test/testrunner.tcl njob $NEW_NUMBER_OF_JOBS
$ ./testfixture $TESTDIR/testrunner.tcl njob $NEW_NUMBER_OF_JOBS
```
+1 -37
View File
@@ -90,7 +90,7 @@ foreach {tn setup} {
proc do_rec_test {tn sql res} {
set res [squish [string trim $res]]
set tst [subst -nocommands {
squish [string trim [exec $::CLI -noinit test.db ".expert" {$sql;}]]
squish [string trim [exec $::CLI test.db ".expert" {$sql;}]]
}]
uplevel [list do_test $tn $tst $res]
}
@@ -606,40 +606,4 @@ ifcapable fts5 {
}
}
#-------------------------------------------------------------------------
reset_db
set ci {CREATE INDEX i1 ON t1(a COLLATE "binary,sqlite_expert_rem(999,0)");}
do_execsql_test 8.0 {
BEGIN TRANSACTION;
CREATE TABLE t1(a TEXT, b TEXT);
INSERT INTO t1 VALUES('v0','d0');
INSERT INTO t1 VALUES('v1','d1');
INSERT INTO t1 VALUES('v2','d2');
INSERT INTO t1 VALUES('v3','d3');
INSERT INTO t1 VALUES('v4','d4');
INSERT INTO t1 VALUES('v5','d5');
INSERT INTO t1 VALUES('v6','d6');
INSERT INTO t1 VALUES('v7','d7');
INSERT INTO t1 VALUES('v8','d8');
INSERT INTO t1 VALUES('v9','d9');
CREATE INDEX i1 ON t1(a);
COMMIT;
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = $ci WHERE name = 'i1';
}
db close
sqlite3 db test.db
do_test 8.1 {
set expert [sqlite3_expert_new db]
$expert sql { SELECT 1234 }
list [catch { $expert analyze } msg] $msg
} {1 {no such collation sequence: binary,sqlite_expert_rem(999,0)}}
$expert destroy
finish_test
+2 -2
View File
@@ -1501,7 +1501,7 @@ static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
/* The statement the vtab will pass to sqlite3_declare_vtab() */
zInner = idxAppendText(&rc, 0, "CREATE TABLE x(");
for(i=0; i<pTab->nCol; i++){
zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %Q",
zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s",
(i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl
);
}
@@ -1701,7 +1701,7 @@ static int idxPopulateOneStat1(
return sqlite3_reset(pIndexXInfo);
}
zCols = idxAppendText(&rc, zCols,
"%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %Q",
"%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
zComma, zName, nCol, zName, zColl
);
zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
+9 -21
View File
@@ -302,12 +302,6 @@
SQLITE_EXTENSION_INIT1
#endif
/*
** Assume any b-tree layer with more levels than this is corrupt.
*/
#define FTS3_MAX_BTREE_HEIGHT 48
typedef struct Fts3HashWrapper Fts3HashWrapper;
struct Fts3HashWrapper {
Fts3Hash hash; /* Hash table */
@@ -1822,7 +1816,9 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
if( !zSql ) return SQLITE_NOMEM;
p->bLock++;
rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt);
rc = sqlite3_prepare_v3(
p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
);
p->bLock--;
sqlite3_free(zSql);
}
@@ -2024,11 +2020,7 @@ static int fts3SelectLeaf(
assert( piLeaf || piLeaf2 );
fts3GetVarint32(zNode, &iHeight);
if( iHeight>FTS3_MAX_BTREE_HEIGHT ){
rc = FTS_CORRUPT_VTAB;
}else{
rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
}
rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
if( rc==SQLITE_OK && iHeight>1 ){
@@ -2073,13 +2065,8 @@ static void fts3PutDeltaVarint(
sqlite3_int64 iVal /* Write this value to the list */
){
assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
if( iVal-(*piPrev)>=0 ){
/* Refuse to write a negative delta integer. This only happens with a
** corrupt db (see the assert above) and can cause buffer overwrites
** in some cases. */
*pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
*piPrev = iVal;
}
*pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
*piPrev = iVal;
}
/*
@@ -3406,7 +3393,9 @@ static int fts3FilterMethod(
}
if( zSql ){
p->bLock++;
rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt);
rc = sqlite3_prepare_v3(
p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
);
p->bLock--;
sqlite3_free(zSql);
}else{
@@ -4029,7 +4018,6 @@ static int fts3IntegrityMethod(
UNUSED_PARAMETER(isQuick);
rc = sqlite3Fts3IntegrityCheck(p, &bOk);
assert( pVtab->zErrMsg==0 || rc!=SQLITE_OK );
assert( rc!=SQLITE_CORRUPT_VTAB );
if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){
*pzErr = sqlite3_mprintf("unable to validate the inverted index for"
+1 -19
View File
@@ -203,16 +203,7 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
#if !defined(deliberate_fall_through)
# if defined(__has_attribute)
# if __has_attribute(fallthrough)
# define deliberate_fall_through __attribute__((fallthrough));
# endif
# endif
#endif
#if !defined(deliberate_fall_through)
# define deliberate_fall_through
#endif
#define deliberate_fall_through
/*
** Macros needed to provide flexible arrays in a portable way
@@ -610,15 +601,6 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
(*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \
)
int sqlite3Fts3PrepareStmt(
Fts3Table *p, /* Prepare for this connection */
const char *zSql, /* SQL to prepare */
int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */
int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */
sqlite3_stmt **pp /* OUT: Prepared statement */
);
/* fts3.c */
void sqlite3Fts3ErrMsg(char**,const char*,...);
int sqlite3Fts3PutVarint(char *, sqlite3_int64);
+2 -2
View File
@@ -325,7 +325,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
pCsr->aStat[1].nDoc++;
}
eState = 2;
/* no break */ deliberate_fall_through
/* fall through */
case 2:
if( v==0 ){ /* 0x00. Next integer will be a docid. */
@@ -341,7 +341,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
/* State 3. The integer just read is a column number. */
default: assert( eState==3 );
iCol = (int)v;
if( iCol<1 || iCol>(pFts3->nColumn+1) ){
if( iCol<1 ){
rc = SQLITE_CORRUPT_VTAB;
break;
}
-1
View File
@@ -471,7 +471,6 @@ static int getNextNode(
assert( nKey==4 );
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
if( nNear>=1000000000 ) nNear = 1000000000;
}
}
+11 -10
View File
@@ -132,9 +132,10 @@ struct StrBuffer {
/*
** Allocate a two-slot MatchinfoBuffer object.
*/
static MatchinfoBuffer *fts3MIBufferNew(i64 nElem, const char *zMatchinfo){
static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
MatchinfoBuffer *pRet;
sqlite3_int64 nByte = sizeof(u32) * (2*(i64)nElem+1) + SZ_MATCHINFOBUFFER(1);
sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1)
+ SZ_MATCHINFOBUFFER(1);
sqlite3_int64 nStr = strlen(zMatchinfo);
pRet = sqlite3Fts3MallocZero(nByte + nStr+1);
@@ -886,7 +887,7 @@ static int fts3ExprLHits(
if( p->flag==FTS3_MATCHINFO_LHITS ){
p->aMatchinfo[iStart + iCol] = (u32)nHit;
}else if( nHit ){
p->aMatchinfo[iStart + iCol/32] |= (1U << (iCol&0x1F));
p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F));
}
}
assert( *pIter==0x00 || *pIter==0x01 );
@@ -1005,8 +1006,8 @@ static int fts3MatchinfoCheck(
return SQLITE_ERROR;
}
static i64 fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
i64 nVal; /* Number of integers output by cArg */
static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
size_t nVal; /* Number of integers output by cArg */
switch( cArg ){
case FTS3_MATCHINFO_NDOC:
@@ -1022,16 +1023,16 @@ static i64 fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
break;
case FTS3_MATCHINFO_LHITS:
nVal = (i64)pInfo->nCol * pInfo->nPhrase;
nVal = (size_t)pInfo->nCol * pInfo->nPhrase;
break;
case FTS3_MATCHINFO_LHITS_BM:
nVal = (i64)pInfo->nPhrase * ((pInfo->nCol + 31) / 32);
nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32);
break;
default:
assert( cArg==FTS3_MATCHINFO_HITS );
nVal = (i64)pInfo->nCol * pInfo->nPhrase * 3;
nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3;
break;
}
@@ -1313,7 +1314,7 @@ static int fts3MatchinfoValues(
case FTS3_MATCHINFO_LHITS_BM:
case FTS3_MATCHINFO_LHITS: {
i64 nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
memset(pInfo->aMatchinfo, 0, nZero);
rc = fts3ExprLHitGather(pCsr->pExpr, pInfo);
break;
@@ -1382,7 +1383,7 @@ static void fts3GetMatchinfo(
** initialize those elements that are constant for every row.
*/
if( pCsr->pMIBuffer==0 ){
i64 nMatchinfo = 0; /* Number of u32 elements in match-info */
size_t nMatchinfo = 0; /* Number of u32 elements in match-info */
int i; /* Used to iterate through zArg */
/* Determine the number of phrases in the query */
+11 -37
View File
@@ -98,9 +98,9 @@ typedef struct SegmentWriter SegmentWriter;
** incrementally. See function fts3PendingListAppend() for details.
*/
struct PendingList {
sqlite3_int64 nData;
int nData;
char *aData;
sqlite3_int64 nSpace;
int nSpace;
sqlite3_int64 iLastDocid;
sqlite3_int64 iLastCol;
sqlite3_int64 iLastPos;
@@ -273,24 +273,6 @@ struct SegmentNode {
#define SQL_UPDATE_LEVEL_IDX 38
#define SQL_UPDATE_LEVEL 39
/*
** Wrapper around sqlite3_prepare_v3() to ensure that SQLITE_PREPARE_FROM_DDL
** is always set.
*/
int sqlite3Fts3PrepareStmt(
Fts3Table *p, /* Prepare for this connection */
const char *zSql, /* SQL to prepare */
int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */
int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */
sqlite3_stmt **pp /* OUT: Prepared statement */
){
int f = SQLITE_PREPARE_FROM_DDL
|((bAllowVtab==0) ? SQLITE_PREPARE_NO_VTAB : 0)
|(bPersist ? SQLITE_PREPARE_PERSISTENT : 0);
return sqlite3_prepare_v3(p->db, zSql, -1, f, pp, NULL);
}
/*
** This function is used to obtain an SQLite prepared statement handle
** for the statement identified by the second argument. If successful,
@@ -416,12 +398,12 @@ static int fts3SqlStmt(
pStmt = p->aStmt[eStmt];
if( !pStmt ){
int bAllowVtab = 0;
int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
char *zSql;
if( eStmt==SQL_CONTENT_INSERT ){
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
}else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
bAllowVtab = 1;
f &= ~SQLITE_PREPARE_NO_VTAB;
zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
}else{
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
@@ -429,7 +411,7 @@ static int fts3SqlStmt(
if( !zSql ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3Fts3PrepareStmt(p, zSql, 1, bAllowVtab, &pStmt);
rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL);
sqlite3_free(zSql);
assert( rc==SQLITE_OK || pStmt==0 );
p->aStmt[eStmt] = pStmt;
@@ -778,9 +760,7 @@ static int fts3PendingTermsAddOne(
pList = (PendingList *)fts3HashFind(pHash, zToken, nToken);
if( pList ){
assert( (i64)pList->nData+(i64)nToken+(i64)sizeof(Fts3HashElem)
<= (i64)p->nPendingData );
p->nPendingData -= (int)(pList->nData + nToken + sizeof(Fts3HashElem));
p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem));
}
if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){
if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){
@@ -793,9 +773,7 @@ static int fts3PendingTermsAddOne(
}
}
if( rc==SQLITE_OK ){
assert( (i64)p->nPendingData + pList->nData + nToken
+ sizeof(Fts3HashElem) <= 0x3fffffff );
p->nPendingData += (int)(pList->nData + nToken + sizeof(Fts3HashElem));
p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem));
}
return rc;
}
@@ -3129,10 +3107,6 @@ static void fts3ReadEndBlockField(
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
/* This if() clause is just to avoid an integer overflow. The record is
** corrupt in this case. */
if( (i64)iVal==SMALLEST_INT64 ) iMul = 1;
*pnByte = ((i64)iVal * (i64)iMul);
}
}
@@ -3600,7 +3574,7 @@ static int fts3DoRebuild(Fts3Table *p){
if( !zSql ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
}
@@ -4359,7 +4333,7 @@ static int fts3IncrmergeLoad(
return FTS_CORRUPT_VTAB;
}
pWriter->nLeafEst = (int)(((iEnd - iStart)+1)/FTS_MAX_APPENDABLE_HEIGHT);
pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
pWriter->iStart = iStart;
pWriter->iEnd = iEnd;
pWriter->iAbsLevel = iAbsLevel;
@@ -5353,7 +5327,7 @@ int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){
if( !zSql ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
}
@@ -5483,7 +5457,7 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
v = atoi(&zVal[9]);
if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v;
rc = SQLITE_OK;
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 11) ){
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
v = atoi(&zVal[11]);
if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v;
rc = SQLITE_OK;
+1 -7
View File
@@ -81,13 +81,7 @@ typedef sqlite3_uint64 u64;
# define FLEXARRAY 1
#endif
#endif /* SQLITE_AMALGAMATION */
/*
** Constants for the largest and smallest possible 32-bit signed integers.
*/
# define LARGEST_INT32 ((int)(0x7fffffff))
# define SMALLEST_INT32 ((int)((-1) - LARGEST_INT32))
#endif
/* Truncate very long tokens to this many bytes. Hard limit is
** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
+3 -3
View File
@@ -426,7 +426,7 @@ static void fts5SnippetFunction(
int rc = SQLITE_OK; /* Return code */
int iCol; /* 1st argument to snippet() */
const char *zEllips; /* 4th argument to snippet() */
i64 nToken; /* 5th argument to snippet() */
int nToken; /* 5th argument to snippet() */
int nInst = 0; /* Number of instance matches this row */
int i; /* Used to iterate through instances */
int nPhrase; /* Number of phrases in query */
@@ -451,11 +451,11 @@ static void fts5SnippetFunction(
ctx.zClose = fts5ValueToText(apVal[2]);
ctx.iRangeEnd = -1;
zEllips = fts5ValueToText(apVal[3]);
nToken = (int)(MIN( MAX(sqlite3_value_int64(apVal[4]), 0), 64));
nToken = sqlite3_value_int(apVal[4]);
iBestCol = (iCol>=0 ? iCol : 0);
nPhrase = pApi->xPhraseCount(pFts);
aSeen = sqlite3_malloc64(nPhrase);
aSeen = sqlite3_malloc(nPhrase);
if( aSeen==0 ){
rc = SQLITE_NOMEM;
}
+1 -1
View File
@@ -288,7 +288,7 @@ char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
if( nIn<0 ){
nIn = (int)strlen(pIn);
}
zRet = (char*)sqlite3_malloc64((i64)nIn+1);
zRet = (char*)sqlite3_malloc(nIn+1);
if( zRet ){
memcpy(zRet, pIn, nIn);
zRet[nIn] = '\0';
+3 -1
View File
@@ -576,7 +576,7 @@ int sqlite3Fts5ConfigParse(
sqlite3_int64 nByte;
int bUnindexed = 0; /* True if there are one or more UNINDEXED */
*ppOut = pRet = (Fts5Config*)sqlite3_malloc64(sizeof(Fts5Config));
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
if( pRet==0 ) return SQLITE_NOMEM;
memset(pRet, 0, sizeof(Fts5Config));
pRet->pGlobal = pGlobal;
@@ -1123,3 +1123,5 @@ void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){
va_end(ap);
}
+4 -4
View File
@@ -314,7 +314,7 @@ int sqlite3Fts5ExprNew(
assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
if( sParse.rc==SQLITE_OK ){
*ppNew = pNew = sqlite3_malloc64(sizeof(Fts5Expr));
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
if( pNew==0 ){
sParse.rc = SQLITE_NOMEM;
sqlite3Fts5ParseNodeFree(sParse.pExpr);
@@ -466,7 +466,7 @@ int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
p2->pRoot = 0;
if( sParse.rc==SQLITE_OK ){
Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc64(
Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc(
p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*)
);
if( ap==0 ){
@@ -807,7 +807,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
i64 iPos = a[i].reader.iPos;
Fts5PoslistWriter *pWriter = &a[i].writer;
if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){
sqlite3Fts5PoslistSafeAppend(a[i].pOut, &pWriter->iPrev, iPos);
sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos);
}
}
@@ -1758,10 +1758,10 @@ static int fts5ParseTokenize(
memset(pSyn, 0, (size_t)nByte);
pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
memcpy(pSyn->pTerm, pToken, nToken);
if( pCtx->pConfig->bTokendata ){
pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
}
memcpy(pSyn->pTerm, pToken, nToken);
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
}
+2 -2
View File
@@ -91,7 +91,7 @@ int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
int rc = SQLITE_OK;
Fts5Hash *pNew;
*ppNew = pNew = (Fts5Hash*)sqlite3_malloc64(sizeof(Fts5Hash));
*ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash));
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -323,7 +323,7 @@ int sqlite3Fts5HashWrite(
** + 5 bytes for the new position offset (32-bit max).
*/
if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
sqlite3_int64 nNew = (i64)p->nAlloc * 2;
sqlite3_int64 nNew = p->nAlloc * 2;
Fts5HashEntry *pNew;
Fts5HashEntry **pp;
pNew = (Fts5HashEntry*)sqlite3_realloc64(p, nNew);
+54 -76
View File
@@ -922,7 +922,7 @@ static void fts5DataRelease(Fts5Data *pData){
static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){
Fts5Data *pRet = fts5DataRead(p, iRowid);
if( pRet ){
if( pRet->szLeaf<4 || pRet->szLeaf>pRet->nn ){
if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){
FTS5_CORRUPT_ROWID(p, iRowid);
fts5DataRelease(pRet);
pRet = 0;
@@ -1166,7 +1166,7 @@ static int fts5StructureDecode(
i += fts5GetVarint32(&pData[i], nTotal);
if( nTotal<pLvl->nMerge ) rc = FTS5_CORRUPT;
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
(i64)nTotal * sizeof(Fts5StructureSegment)
nTotal * sizeof(Fts5StructureSegment)
);
nSegment -= nTotal;
}
@@ -1695,7 +1695,6 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
pLvl->bEof = 1;
}else{
u8 *a = pLvl->pData->p;
int nn = pLvl->pData->nn;
pLvl->iOff = 0;
fts5DlidxLvlNext(pLvl);
@@ -1704,7 +1703,7 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
int ii = pLvl->iOff;
u64 delta = 0;
while( ii<nn && a[ii]==0 ){
while( a[ii]==0 ){
nZero++;
ii++;
}
@@ -2075,7 +2074,6 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
while( 1 ){
u64 iDelta = 0;
if( i>=n ) break;
if( eDetail==FTS5_DETAIL_NONE ){
/* todo */
if( i<n && a[i]==0 ){
@@ -2094,7 +2092,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
/* If necessary, grow the pIter->aRowidOffset[] array. */
if( iRowidOffset>=pIter->nRowidOffset ){
i64 nNew = pIter->nRowidOffset + 8;
int nNew = pIter->nRowidOffset + 8;
int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int));
if( aNew==0 ){
p->rc = SQLITE_NOMEM;
@@ -2123,7 +2121,7 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){
Fts5Data *pNew;
pIter->iLeafPgno--;
pNew = fts5LeafRead(p, FTS5_SEGMENT_ROWID(
pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID(
pIter->pSeg->iSegid, pIter->iLeafPgno
));
if( pNew ){
@@ -2577,10 +2575,6 @@ static void fts5LeafSeek(
if( nKeep<nMatch ){
goto search_failed;
}
if( (iOff+nNew)>n ){
FTS5_CORRUPT_ITER(p, pIter);
return;
}
assert( nKeep>=nMatch );
if( nKeep==nMatch ){
@@ -3557,7 +3551,8 @@ static void fts5PoslistFilterCallback(
do {
while( i<nChunk && pChunk[i]!=0x01 ){
fts5IndexSkipVarint(pChunk, i);
while( pChunk[i] & 0x80 ) i++;
i++;
}
if( pCtx->eState ){
fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
@@ -3706,7 +3701,7 @@ static void fts5IndexExtractColset(
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
while( p<pEnd && *p!=0x01 ){
while( p<pEnd && (*p++ & 0x80) );
while( *p++ & 0x80 );
}
if( pColset->aiCol[i]==iCurrent ){
@@ -3803,11 +3798,8 @@ static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
assert( pIter->pColset );
assert( pIter->poslist.nSpace>=pIter->pIndex->pConfig->nCol );
if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf
|| pSeg->nPos>pIter->pIndex->pConfig->nCol
){
if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){
fts5IterSetOutputs_Col(pIter, pSeg);
}else{
u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset];
@@ -5247,7 +5239,7 @@ static void fts5DoSecureDelete(
int iSegid = pSeg->pSeg->iSegid;
u8 *aPg = pSeg->pLeaf->p;
int nPg = pSeg->pLeaf->nn;
int iPgIdx = pSeg->pLeaf->szLeaf; /* Offset of page footer */
int iPgIdx = pSeg->pLeaf->szLeaf;
u64 iDelta = 0;
int iNextOff = 0;
@@ -5301,11 +5293,6 @@ static void fts5DoSecureDelete(
}else{
iStart = fts5GetU16(&aPg[0]);
}
if( iStart>nPg ){
FTS5_CORRUPT_IDX(p);
sqlite3_free(aIdx);
return;
}
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
assert_nc( iSOP<=pSeg->iLeafOffset );
@@ -5331,7 +5318,7 @@ static void fts5DoSecureDelete(
iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
}
assert_nc( iSOP==pSeg->iLeafOffset );
iNextOff = iSOP + pSeg->nPos;
iNextOff = pSeg->iLeafOffset + pSeg->nPos;
}
}
@@ -5411,31 +5398,31 @@ static void fts5DoSecureDelete(
** is another term following it on this page. So the subsequent term
** needs to be moved to replace the term associated with the entry
** being removed. */
u64 nPrefix = 0;
u64 nSuffix = 0;
u64 nPrefix2 = 0;
u64 nSuffix2 = 0;
int nPrefix = 0;
int nSuffix = 0;
int nPrefix2 = 0;
int nSuffix2 = 0;
iDelKeyOff = iNextOff;
iNextOff += fts5GetVarint(&aPg[iNextOff], &nPrefix2);
iNextOff += fts5GetVarint(&aPg[iNextOff], &nSuffix2);
iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
if( iKey!=1 ){
iKeyOff += fts5GetVarint(&aPg[iKeyOff], &nPrefix);
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
}
iKeyOff += fts5GetVarint(&aPg[iKeyOff], &nSuffix);
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
nPrefix = MIN(nPrefix, nPrefix2);
nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
if( (iKeyOff+nSuffix)>(u64)iPgIdx || (iNextOff+nSuffix2)>(u64)iPgIdx ){
if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
FTS5_CORRUPT_IDX(p);
}else{
if( iKey!=1 ){
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
}
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
if( nPrefix2>(u64)pSeg->term.n ){
if( nPrefix2>pSeg->term.n ){
FTS5_CORRUPT_IDX(p);
}else if( nPrefix2>nPrefix ){
memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
@@ -5466,7 +5453,7 @@ static void fts5DoSecureDelete(
u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
int nTermIdx = pTerm->nn - pTerm->szLeaf;
int iTermIdx = 0;
i64 iTermOff = 0;
int iTermOff = 0;
while( 1 ){
u32 iVal = 0;
@@ -5477,15 +5464,12 @@ static void fts5DoSecureDelete(
}
nTermIdx = iTermIdx;
if( iTermOff>pTerm->szLeaf ){
FTS5_CORRUPT_IDX(p);
}else{
memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
fts5PutU16(&pTerm->p[2], iTermOff);
fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
if( nTermIdx==0 ){
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
}
memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
fts5PutU16(&pTerm->p[2], iTermOff);
fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
if( nTermIdx==0 ){
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
}
}
fts5DataRelease(pTerm);
@@ -5508,9 +5492,7 @@ static void fts5DoSecureDelete(
int iPrevKeyOut = 0;
int iKeyIn = 0;
if( nMove>0 ){
memmove(&aPg[iOff], &aPg[iNextOff], nMove);
}
memmove(&aPg[iOff], &aPg[iNextOff], nMove);
iPgIdx -= nShift;
nPg = iPgIdx;
fts5PutU16(&aPg[2], iPgIdx);
@@ -5948,7 +5930,7 @@ int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
fts5StructureRelease(pStruct);
pStruct = pNew;
nMin = 1;
nMerge = (nMerge==SMALLEST_INT32 ? LARGEST_INT32 : (nMerge*-1));
nMerge = nMerge*-1;
}
if( pStruct && pStruct->nLevel ){
if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
@@ -6430,16 +6412,16 @@ struct Fts5TokenDataMap {
** aMap[] variables.
*/
struct Fts5TokenDataIter {
i64 nMapAlloc; /* Allocated size of aMap[] in entries */
i64 nMap; /* Number of valid entries in aMap[] */
int nMapAlloc; /* Allocated size of aMap[] in entries */
int nMap; /* Number of valid entries in aMap[] */
Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */
/* The following are used for prefix-queries only. */
Fts5Buffer terms;
/* The following are used for other full-token tokendata queries only. */
i64 nIter;
i64 nIterAlloc;
int nIter;
int nIterAlloc;
Fts5PoslistReader *aPoslistReader;
int *aPoslistToIter;
Fts5Iter *apIter[FLEXARRAY];
@@ -6495,11 +6477,11 @@ static void fts5TokendataIterAppendMap(
){
if( p->rc==SQLITE_OK ){
if( pT->nMap==pT->nMapAlloc ){
i64 nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
i64 nAlloc = nNew * sizeof(Fts5TokenDataMap);
int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
int nAlloc = nNew * sizeof(Fts5TokenDataMap);
Fts5TokenDataMap *aNew;
aNew = (Fts5TokenDataMap*)sqlite3_realloc64(pT->aMap, nAlloc);
aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc);
if( aNew==0 ){
p->rc = SQLITE_NOMEM;
return;
@@ -6525,7 +6507,7 @@ static void fts5TokendataIterAppendMap(
*/
static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
Fts5TokenDataMap *aTmp = 0;
i64 nByte = pT->nMap * sizeof(Fts5TokenDataMap);
int nByte = pT->nMap * sizeof(Fts5TokenDataMap);
aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( aTmp ){
@@ -7059,10 +7041,9 @@ static Fts5TokenDataIter *fts5AppendTokendataIter(
if( p->rc==SQLITE_OK ){
if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
i64 nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
i64 nByte = SZ_FTS5TOKENDATAITER(nAlloc+1);
Fts5TokenDataIter *pNew;
pNew = (Fts5TokenDataIter*)sqlite3_realloc64(pIn, nByte);
int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1);
Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);
if( pNew==0 ){
p->rc = SQLITE_NOMEM;
@@ -7159,8 +7140,8 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
/* Ensure the token-mapping is large enough */
if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){
i64 nNew = (pT->nMapAlloc + nByte) * 2;
Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc64(
int nNew = (pT->nMapAlloc + nByte) * 2;
Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc(
pT->aMap, nNew*sizeof(Fts5TokenDataMap)
);
if( aNew==0 ){
@@ -7991,8 +7972,8 @@ static void fts5IndexTombstoneRebuild(
){
const int MINSLOT = 32;
int nSlotPerPage = MAX(MINSLOT, (p->pConfig->pgsz - 8) / szKey);
i64 nSlot = 0; /* Number of slots in each output page */
i64 nOut = 0;
int nSlot = 0; /* Number of slots in each output page */
int nOut = 0;
/* Figure out how many output pages (nOut) and how many slots per
** page (nSlot). There are three possibilities:
@@ -8017,26 +7998,23 @@ static void fts5IndexTombstoneRebuild(
nSlot = MINSLOT;
}else if( pSeg->nPgTombstone==1 ){
/* Case 2. */
u32 nElem = fts5GetU32(&pData1->p[4]);
int nElem = (int)fts5GetU32(&pData1->p[4]);
assert( pData1 && iPg1==0 );
if( nElem>((u32)nSlotPerPage/4) ){
nOut = 0;
}else{
nOut = 1;
nSlot = MAX((i64)nElem*4, MINSLOT);
}
nOut = 1;
nSlot = MAX(nElem*4, MINSLOT);
if( nSlot>nSlotPerPage ) nOut = 0;
}
if( nOut==0 ){
/* Case 3. */
nOut = ((i64)pSeg->nPgTombstone * 2 + 1);
nOut = (pSeg->nPgTombstone * 2 + 1);
nSlot = nSlotPerPage;
}
/* Allocate the required array and output pages */
while( 1 ){
int res = 0;
i64 ii = 0;
i64 szPage = 0;
int ii = 0;
int szPage = 0;
Fts5Data **apOut = 0;
/* Allocate space for the new hash table */
@@ -8574,7 +8552,7 @@ static void fts5IndexIntegrityCheckSegment(
/* Check any rowid-less pages that occur before the current leaf. */
for(iPg=iPrevLeaf+1; iPg<fts5DlidxIterPgno(pDlidx); iPg++){
iKey = FTS5_SEGMENT_ROWID(iSegid, iPg);
pLeaf = fts5LeafRead(p, iKey);
pLeaf = fts5DataRead(p, iKey);
if( pLeaf ){
if( fts5LeafFirstRowidOff(pLeaf)!=0 ) FTS5_CORRUPT_ROWID(p, iKey);
fts5DataRelease(pLeaf);
@@ -8585,7 +8563,7 @@ static void fts5IndexIntegrityCheckSegment(
/* Check that the leaf page indicated by the iterator really does
** contain the rowid suggested by the same. */
iKey = FTS5_SEGMENT_ROWID(iSegid, iPrevLeaf);
pLeaf = fts5LeafRead(p, iKey);
pLeaf = fts5DataRead(p, iKey);
if( pLeaf ){
i64 iRowid;
int iRowidOff = fts5LeafFirstRowidOff(pLeaf);
+22 -48
View File
@@ -517,7 +517,7 @@ static void fts5SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
if( sqlite3_libversion_number()>=3008002 )
#endif
{
pIdxInfo->estimatedRows = MAX(1, nRow);
pIdxInfo->estimatedRows = nRow;
}
#endif
}
@@ -586,30 +586,19 @@ static int fts5UsePatternMatch(
** a) If a MATCH operator is present, the cost depends on the other
** constraints also present. As follows:
**
** * No other constraints: cost=50000.0
** * One rowid range constraint: cost=37500.0
** * Both rowid range constraints: cost=30000.0
** * An == rowid constraint: cost=25000.0
** * No other constraints: cost=1000.0
** * One rowid range constraint: cost=750.0
** * Both rowid range constraints: cost=500.0
** * An == rowid constraint: cost=100.0
**
** b) Otherwise, if there is no MATCH:
**
** * No other constraints: cost=3000000.0
** * One rowid range constraints: cost=2250000.0
** * Both rowid range constraint: cost=750000.0
** * An == rowid constraint: cost=25.0
** * No other constraints: cost=1000000.0
** * One rowid range constraint: cost=750000.0
** * Both rowid range constraints: cost=250000.0
** * An == rowid constraint: cost=10.0
**
** Costs are not modified by the ORDER BY clause.
**
** The ratios used in case (a) are based on informal results obtained from
** the tool/fts5cost.tcl script. The "MATCH and ==" combination has the
** cost set quite high because the query may be a prefix query. Unless
** there is a prefix index, prefix queries with rowid constraints are much
** more expensive than non-prefix queries with rowid constraints.
**
** The estimated rows returned is set to the cost/40. For simple queries,
** experimental results show that cost/4 might be about right. But for
** more complex queries that use multiple terms the number of rows might
** be far fewer than this. So we compromise and use cost/40.
*/
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
Fts5Table *pTab = (Fts5Table*)pVTab;
@@ -642,7 +631,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
return SQLITE_ERROR;
}
idxStr = (char*)sqlite3_malloc64((i64)pInfo->nConstraint * 8 + 1);
idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1);
if( idxStr==0 ) return SQLITE_NOMEM;
pInfo->idxStr = idxStr;
pInfo->needToFreeIdxStr = 1;
@@ -735,35 +724,21 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
/* Calculate the estimated cost based on the flags set in idxFlags. */
if( bSeenEq ){
pInfo->estimatedCost = nSeenMatch ? 25000.0 : 25.0;
fts5SetEstimatedRows(pInfo, 1);
pInfo->estimatedCost = nSeenMatch ? 1000.0 : 25.0;
fts5SetUniqueFlag(pInfo);
fts5SetEstimatedRows(pInfo, 1);
}else{
i64 nEstRows;
if( nSeenMatch ){
if( bSeenLt && bSeenGt ){
pInfo->estimatedCost = 50000.0;
}else if( bSeenLt || bSeenGt ){
pInfo->estimatedCost = 37500.0;
}else{
pInfo->estimatedCost = 50000.0;
}
nEstRows = (i64)(pInfo->estimatedCost / 40.0);
for(i=1; i<nSeenMatch; i++){
pInfo->estimatedCost *= 2.5;
nEstRows = nEstRows / 2;
}
if( bSeenLt && bSeenGt ){
pInfo->estimatedCost = nSeenMatch ? 5000.0 : 750000.0;
}else if( bSeenLt || bSeenGt ){
pInfo->estimatedCost = nSeenMatch ? 7500.0 : 2250000.0;
}else{
if( bSeenLt && bSeenGt ){
pInfo->estimatedCost = 750000.0;
}else if( bSeenLt || bSeenGt ){
pInfo->estimatedCost = 2250000.0;
}else{
pInfo->estimatedCost = 3000000.0;
}
nEstRows = (i64)(pInfo->estimatedCost / 4.0);
pInfo->estimatedCost = nSeenMatch ? 10000.0 : 3000000.0;
}
fts5SetEstimatedRows(pInfo, nEstRows);
for(i=1; i<nSeenMatch; i++){
pInfo->estimatedCost *= 0.4;
}
fts5SetEstimatedRows(pInfo, (i64)(pInfo->estimatedCost / 4.0));
}
pInfo->idxNum = idxFlags;
@@ -2106,7 +2081,6 @@ static int fts5UpdateMethod(
}
update_out:
sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -3788,7 +3762,7 @@ static int fts5Init(sqlite3 *db){
int rc;
Fts5Global *pGlobal = 0;
pGlobal = (Fts5Global*)sqlite3_malloc64(sizeof(Fts5Global));
pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
if( pGlobal==0 ){
rc = SQLITE_NOMEM;
}else{
+23 -20
View File
@@ -365,31 +365,34 @@ int sqlite3Fts5StorageOpen(
if( pConfig->eContent==FTS5_CONTENT_NORMAL
|| pConfig->eContent==FTS5_CONTENT_UNINDEXED
){
int i = 0;
char *zDefn = 0;
sqlite3_str *pDefn = sqlite3_str_new(pConfig->db);
sqlite3_str_appendf(pDefn, "id INTEGER PRIMARY KEY");
for(i=0; i<pConfig->nCol; i++){
if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->abUnindexed[i] ){
sqlite3_str_appendf(pDefn, ", c%d", i);
}
}
if( pConfig->bLocale ){
int nDefn = 32 + pConfig->nCol*10;
char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20);
if( zDefn==0 ){
rc = SQLITE_NOMEM;
}else{
int i;
int iOff;
sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
iOff = (int)strlen(zDefn);
for(i=0; i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i]==0 ){
sqlite3_str_appendf(pDefn, ", l%d", i);
if( pConfig->eContent==FTS5_CONTENT_NORMAL
|| pConfig->abUnindexed[i]
){
sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
iOff += (int)strlen(&zDefn[iOff]);
}
}
if( pConfig->bLocale ){
for(i=0; i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i]==0 ){
sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i);
iOff += (int)strlen(&zDefn[iOff]);
}
}
}
}
zDefn = sqlite3_str_finish(pDefn);
if( zDefn ){
rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
sqlite3_free(zDefn);
}else{
rc = SQLITE_NOMEM;
}
sqlite3_free(zDefn);
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
+4 -4
View File
@@ -391,7 +391,7 @@ static int SQLITE_TCLAPI xF5tApi(
break;
}
CASE(12, "xSetAuxdata") {
F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc64(sizeof(F5tAuxData));
F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData));
if( pData==0 ){
Tcl_AppendResult(interp, "out of memory", (char*)0);
return TCL_ERROR;
@@ -780,7 +780,7 @@ static int SQLITE_TCLAPI f5tTokenize(
}
if( nText>0 ){
pCopy = sqlite3_malloc64(nText);
pCopy = sqlite3_malloc(nText);
if( pCopy==0 ){
tokenizer.xDelete(pTok);
Tcl_AppendResult(interp, "error in sqlite3_malloc()", (char*)0);
@@ -1420,7 +1420,7 @@ static int f5tOrigintextCreate(
void *pTokCtx = 0;
int rc = SQLITE_OK;
pTok = (OriginTextTokenizer*)sqlite3_malloc64(sizeof(OriginTextTokenizer));
pTok = (OriginTextTokenizer*)sqlite3_malloc(sizeof(OriginTextTokenizer));
if( pTok==0 ){
rc = SQLITE_NOMEM;
}else if( nArg<1 ){
@@ -1480,7 +1480,7 @@ static int xOriginToken(
int nReq = nToken + 1 + (iEnd-iStart);
if( nReq>p->nBuf ){
sqlite3_free(p->aBuf);
p->aBuf = sqlite3_malloc64(nReq*2);
p->aBuf = sqlite3_malloc(nReq*2);
if( p->aBuf==0 ) return SQLITE_NOMEM;
p->nBuf = nReq*2;
}
+5 -5
View File
@@ -194,7 +194,7 @@ static int fts5tokConnectMethod(
}
if( rc==SQLITE_OK ){
pTab = (Fts5tokTable*)sqlite3_malloc64(sizeof(Fts5tokTable));
pTab = (Fts5tokTable*)sqlite3_malloc(sizeof(Fts5tokTable));
if( pTab==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -275,7 +275,7 @@ static int fts5tokBestIndexMethod(
static int fts5tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
Fts5tokCursor *pCsr;
pCsr = (Fts5tokCursor *)sqlite3_malloc64(sizeof(Fts5tokCursor));
pCsr = (Fts5tokCursor *)sqlite3_malloc(sizeof(Fts5tokCursor));
if( pCsr==0 ){
return SQLITE_NOMEM;
}
@@ -347,7 +347,7 @@ static int fts5tokCb(
if( pCsr->nRow ){
pRow->iPos = pRow[-1].iPos + ((tflags & FTS5_TOKEN_COLOCATED) ? 0 : 1);
}
pRow->zToken = sqlite3_malloc64((sqlite3_int64)nToken+1);
pRow->zToken = sqlite3_malloc(nToken+1);
if( pRow->zToken==0 ) return SQLITE_NOMEM;
memcpy(pRow->zToken, pToken, nToken);
pRow->zToken[nToken] = 0;
@@ -373,8 +373,8 @@ static int fts5tokFilterMethod(
fts5tokResetCursor(pCsr);
if( idxNum==1 ){
const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]);
pCsr->zInput = sqlite3_malloc64(nByte+1);
int nByte = sqlite3_value_bytes(apVal[0]);
pCsr->zInput = sqlite3_malloc(nByte+1);
if( pCsr->zInput==0 ){
rc = SQLITE_NOMEM;
}else{
+8 -14
View File
@@ -72,7 +72,7 @@ static int fts5AsciiCreate(
if( nArg%2 ){
rc = SQLITE_ERROR;
}else{
p = sqlite3_malloc64(sizeof(AsciiTokenizer));
p = sqlite3_malloc(sizeof(AsciiTokenizer));
if( p==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -367,7 +367,7 @@ static int fts5UnicodeCreate(
if( nArg%2 ){
rc = SQLITE_ERROR;
}else{
p = (Unicode61Tokenizer*)sqlite3_malloc64(sizeof(Unicode61Tokenizer));
p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer));
if( p ){
const char *zCat = "L* N* Co";
int i;
@@ -586,17 +586,11 @@ static int fts5PorterCreate(
const char *zBase = "unicode61";
fts5_tokenizer_v2 *pV2 = 0;
while( nArg>0 ){
if( sqlite3_stricmp(azArg[0],"porter")==0 ){
nArg--;
azArg++;
}else{
zBase = azArg[0];
break;
}
if( nArg>0 ){
zBase = azArg[0];
}
pRet = (PorterTokenizer*)sqlite3_malloc64(sizeof(PorterTokenizer));
pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
if( pRet ){
memset(pRet, 0, sizeof(PorterTokenizer));
rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2);
@@ -718,9 +712,9 @@ static int fts5Porter_Ostar(char *zStem, int nStem){
for(i=0; i<nStem; i++){
bCons = !fts5PorterIsVowel(zStem[i], bCons);
assert( bCons==0 || bCons==1 );
mask = ((mask << 1) + bCons) & 0x0007;
mask = (mask << 1) + bCons;
}
return (mask==0x0005);
return ((mask & 0x0007)==0x0005);
}
}
@@ -1303,7 +1297,7 @@ static int fts5TriCreate(
rc = SQLITE_ERROR;
}else{
int i;
pNew = (TrigramTokenizer*)sqlite3_malloc64(sizeof(*pNew));
pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
+1 -12
View File
@@ -396,12 +396,7 @@ static int fts5VocabOpenMethod(
return rc;
}
/*
** Restore cursor pCsr to the state it was in immediately after being
** created by the xOpen() method.
*/
static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
int nCol = pCsr->pFts5->pConfig->nCol;
pCsr->rowid = 0;
sqlite3Fts5IterClose(pCsr->pIter);
sqlite3Fts5StructureRelease(pCsr->pStruct);
@@ -411,12 +406,6 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
pCsr->nLeTerm = -1;
pCsr->zLeTerm = 0;
pCsr->bEof = 0;
pCsr->iCol = 0;
pCsr->iInstPos = 0;
pCsr->iInstOff = 0;
pCsr->colUsed = 0;
memset(pCsr->aCnt, 0, sizeof(i64)*nCol);
memset(pCsr->aDoc, 0, sizeof(i64)*nCol);
}
/*
@@ -666,7 +655,7 @@ static int fts5VocabFilterMethod(
const char *zCopy = (const char *)sqlite3_value_text(pLe);
if( zCopy==0 ) zCopy = "";
pCsr->nLeTerm = sqlite3_value_bytes(pLe);
pCsr->zLeTerm = sqlite3_malloc64((i64)pCsr->nLeTerm+1);
pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
if( pCsr->zLeTerm==0 ){
rc = SQLITE_NOMEM;
}else{
-23
View File
@@ -191,29 +191,6 @@ do_execsql_test 5.6 {
SELECT snippet(p1, 0, '[', NULL, '...', 6) FROM p1('x OR ' || x'DB');
} {{[x a a a a a...}}
do_execsql_test 5.7.1 {
SELECT snippet(p1, 0, '[', NULL, '...', -2147483647) FROM p1('x OR ' || x'DB')
} {{[x...}}
do_execsql_test 5.7.2 {
SELECT snippet(p1, 0, '[', NULL, '...', -2147483648) FROM p1('x OR ' || x'DB')
} {{[x...}}
do_execsql_test 5.7.3 {
SELECT snippet(p1, 0, '[', NULL, '...', -2147483649) FROM p1('x OR ' || x'DB')
} {{[x...}}
do_execsql_test 5.7.4 {
SELECT snippet(p1, 0, '[', NULL, '...', 0) FROM p1('x OR ' || x'DB')
} {{[x...}}
do_execsql_test 5.8.1 {
SELECT snippet(p1, 0, '[', NULL, '...', 2147483647) FROM p1('x OR ' || x'DB')
} {{[x a a a a a a a a a a}}
do_execsql_test 5.8.2 {
SELECT snippet(p1, 0, '[', NULL, '...', 2147483648) FROM p1('x OR ' || x'DB')
} {{[x a a a a a a a a a a}}
do_execsql_test 5.8.3 {
SELECT snippet(p1, 0, '[', NULL, '...', 2147483649) FROM p1('x OR ' || x'DB')
} {{[x a a a a a a a a a a}}
} ;# foreach_detail_mode
reset_db
-28
View File
@@ -1,28 +0,0 @@
# 2026 June 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 implements regression tests for SQLite library. The
# focus of this script is testing the FTS5 module.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5bigtok2
return_if_no_fts5
set big [string repeat a 1080000000]
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t USING fts5(x);
}
do_catchsql_test 1.1 { INSERT INTO t VALUES($big); } {1 {out of memory}}
set big {}
finish_test
+2 -364
View File
@@ -15153,9 +15153,9 @@ do_execsql_test 78.1 {
CREATE VIRTUAL TABLE t3 USING fts5vocab('t1','col');
}
do_catchsql_test 78.2 {
do_execsql_test 78.2 {
SELECT count(rowid) FROM t3 WHERE term>='nsocse';
} {1 {database disk image is malformed}}
} 2
#-------------------------------------------------------------------------
reset_db
@@ -16124,367 +16124,5 @@ do_catchsql_test 83.1 {
SELECT * FROM t1('R*R*R*R*R*R*R*R*') WHERE (a,b)<=(current_date,0 BETWEEN 'a'<>11 AND '') ORDER BY rowid DESC;
} {/.*fts5: corruption found/}
#-------------------------------------------------------------------------
reset_db
do_test 84.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 53248 pagesize 4096 filename c1a.txt.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 0d .....@ ........
| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............
| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
| 3488: 32 74 32 0d 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i....
| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
| 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9.....
| page 3 offset 8192
| 0: 05 00 00 00 02 0f f1 00 00 00 00 0c 0f fb 0f f1 ................
| 4064: 00 00 0b 01 03 00 1c 81 3a 84 5e 81 3a 81 3a 0a ........:.^.:.:.
| 4080: 0a 00 00 00 0b 84 80 80 80 80 01 00 00 00 0a 0a ................
| page 4 offset 12288
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 7 offset 24576
| 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 10 offset 36864
| 0: 0d 00 00 00 02 0f e2 00 0f e2 0f ef 00 00 00 00 ................
| 4064: 00 00 0b 01 03 00 1c 81 3a 84 5e 81 3a 81 3a 0f ........:.^.:.:.
| 4080: 0a 03 00 24 00 00 00 00 01 01 02 00 01 01 01 09 ...$............
| page 11 offset 40960
| 0: 0d 00 00 00 01 00 22 00 00 22 00 00 00 00 00 00 ................
| 32: 00 00 9f 56 84 80 80 80 80 01 04 00 bf 30 00 00 ...V.........0..
| 48: 0f 58 02 30 30 19 02 05 01 02 05 01 02 05 16 02 .X.00...........
| 64: 05 01 02 05 01 02 05 61 02 05 01 02 05 01 02 05 .......a........
| 80: 13 02 05 01 02 05 01 02 05 0d 02 03 01 02 03 01 ................
| 96: 02 03 02 09 78 66 66 66 66 66 66 66 65 81 17 02 ....xfffffffe...
| 112: 05 01 02 05 01 02 05 01 01 31 04 02 04 01 02 04 .........1......
| 128: 01 02 04 01 02 05 01 02 05 01 02 05 0d 02 06 01 ................
| 144: 02 06 01 02 06 02 01 30 79 02 04 01 02 04 01 02 .......0y.......
| 160: 04 03 02 30 30 2b 02 05 01 02 05 01 02 05 58 02 ...00+........X.
| 176: 05 01 02 05 01 02 05 01 02 05 01 02 05 01 02 05 ................
| 192: 16 02 05 01 02 05 01 02 05 05 06 30 30 30 30 30 ...........00000
| 208: 30 81 0b 02 04 01 02 04 01 02 04 10 02 05 01 02 0...............
| 224: 05 01 02 05 03 02 32 34 76 02 05 01 02 05 01 02 ......24v.......
| 240: 05 02 01 38 07 02 04 01 02 04 01 02 04 01 01 32 ...8...........2
| 256: 28 02 04 01 02 04 01 02 04 04 02 05 01 02 05 01 (...............
| 272: 02 05 02 01 30 1f 02 05 01 02 05 01 02 05 03 02 ....0...........
| 288: 30 30 10 02 05 01 02 05 01 02 05 6a 02 04 01 02 00.........j....
| 304: 04 01 02 04 02 08 35 30 30 30 30 30 30 30 81 26 ......50000000.&
| 320: 02 05 01 02 05 01 02 05 01 01 33 07 02 06 01 02 ..........3.....
| 336: 06 01 02 06 81 2c 02 04 01 02 04 01 02 04 02 04 .....,..........
| 352: 32 37 36 36 81 23 02 05 01 02 05 01 02 05 01 01 2766.#..........
| 368: 34 13 02 05 01 02 05 01 02 05 02 03 30 39 36 1c 4...........096.
| 384: 02 05 01 02 05 01 02 05 07 02 05 01 02 05 01 02 ................
| 400: 05 01 03 35 30 30 7f 02 05 01 02 05 01 02 05 04 ...500..........
| 416: 02 30 30 81 0e 02 06 01 02 06 01 02 06 06 03 30 .00............0
| 432: 30 30 81 11 02 04 01 02 04 01 02 04 01 05 36 35 00............65
| 448: 35 33 36 81 1a 02 05 01 02 05 01 02 05 01 04 38 536............8
| 464: 31 39 32 81 02 02 06 01 02 06 01 02 06 01 05 61 192............a
| 480: 6c 6c 6f 77 01 02 02 01 02 02 01 02 02 02 02 72 llow...........r
| 496: 67 81 08 02 04 01 02 04 01 02 04 02 05 74 6f 6d g............tom
| 512: 69 63 04 02 02 01 02 02 01 02 02 03 06 74 61 63 ic...........tac
| 528: 68 65 64 79 02 03 01 02 03 01 02 03 02 0d 75 74 hedy..........ut
| 544: 6f 63 68 65 63 6b 70 6f 69 6e 74 2b 02 04 01 02 ocheckpoint+....
| 560: 04 01 02 04 05 06 76 61 63 75 75 6d 0d 02 03 01 ......vacuum....
| 576: 02 03 01 02 03 01 06 62 69 6e 61 72 79 03 06 01 .......binary...
| 592: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 608: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 624: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 640: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 656: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 672: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 688: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 704: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 720: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 736: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 752: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 768: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 784: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 800: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 816: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 832: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 848: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 864: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 880: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 896: 01 02 02 02 07 79 74 65 63 6f 64 65 37 02 03 01 .....ytecode7...
| 912: 02 03 01 02 03 01 05 63 61 63 68 65 10 02 03 01 .......cache....
| 928: 02 03 01 01 03 02 04 6c 61 6e 67 07 02 03 01 02 .......lang.....
| 944: 03 01 02 03 02 05 6f 6c 75 6d 6e 7c 02 03 01 02 ......olumn|....
| 960: 03 01 02 03 03 06 6d 6d 65 6e 74 73 43 02 04 01 ......mmentsC...
| 976: 02 04 01 02 04 04 05 70 69 6c 65 72 07 02 02 01 .......piler....
| 992: 02 02 01 02 02 05 04 6f 75 6e 64 7f 02 03 01 02 .......ound.....
| 1008: 03 01 02 03 03 03 75 6e 74 81 17 02 04 01 02 04 ......unt.......
| 1024: 01 02 04 02 05 75 72 73 6f 72 3a 02 03 01 02 03 .....ursor:.....
| 1040: 01 02 03 01 06 64 62 70 61 67 65 3d 02 03 01 02 .....dbpage=....
| 1056: 03 01 02 03 03 04 73 74 61 74 40 02 03 01 02 03 ......stat@.....
| 1072: 01 02 03 02 04 65 62 75 67 0a 02 02 01 02 02 01 .....ebug.......
| 1088: 02 02 03 05 66 61 75 6c 74 0d 02 02 01 02 02 01 ....fault.......
| 1104: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 1120: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 1136: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 1152: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 1168: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 1184: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 1200: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 4f 02 ..............O.
| 1216: 03 01 02 03 01 02 03 03 03 70 74 68 81 05 02 04 .........pth....
| 1232: 01 02 04 01 02 04 19 02 04 01 02 04 01 02 04 02 ................
| 1248: 05 69 72 65 63 74 34 02 02 01 02 02 01 02 02 01 .irect4.........
| 1264: 06 65 6e 61 62 6c 65 37 02 02 01 02 02 01 02 02 .enable7........
| 1280: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 1296: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 1312: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 1328: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 1344: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 1360: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 1376: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 1392: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 1408: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 1424: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 1440: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 1456: 02 01 02 02 02 06 78 70 6c 61 69 6e 43 02 03 01 ......xplainC...
| 1472: 02 03 01 02 03 04 01 72 81 05 02 03 01 02 03 01 .......r........
| 1488: 02 03 03 07 74 65 6e 73 69 6f 6e 81 2f 02 04 01 ....tension./...
| 1504: 02 04 01 02 04 01 04 66 69 6c 65 13 02 03 01 02 .......file.....
| 1520: 03 01 02 03 02 05 6f 72 6d 61 74 13 02 04 01 02 ......ormat.....
| 1536: 04 01 02 04 02 03 74 73 33 46 02 03 01 02 03 01 ......ts3F......
| 1552: 02 03 01 02 03 01 02 03 01 02 03 04 01 34 4c 02 .............4L.
| 1568: 03 01 02 03 01 02 03 04 01 35 4f 02 03 01 02 03 .........5O.....
| 1584: 01 02 03 02 03 75 6e 63 5e 02 05 01 02 05 01 02 .....unc^.......
| 1600: 05 05 04 74 69 6f 6e 73 02 05 01 02 05 01 02 05 ...tions........
| 1616: 13 02 03 01 02 03 01 02 03 09 01 73 55 02 04 01 ...........sU...
| 1632: 02 04 01 02 04 01 07 67 65 6f 70 6f 6c 79 52 02 .......geopolyR.
| 1648: 03 01 02 03 01 02 03 01 05 68 69 6e 74 73 3a 02 .........hints:.
| 1664: 04 01 02 04 01 02 04 02 03 6f 6f 6b 61 02 04 01 .........ooka...
| 1680: 02 04 01 02 04 01 02 69 6e 01 02 04 01 02 04 01 .......in.......
| 1696: 02 04 03 04 69 74 73 7a 1f 02 04 01 02 04 01 02 ....itsz........
| 1712: 04 03 08 74 72 69 6e 73 69 63 73 04 02 03 01 02 ...trinsics.....
| 1728: 03 01 02 03 01 07 6a 6f 75 72 6e 61 6c 16 02 03 ......journal...
| 1744: 01 02 03 01 02 03 01 06 6c 65 6e 67 74 68 81 0b ........length..
| 1760: 02 03 01 02 03 01 02 03 01 02 05 01 02 05 01 02 ................
| 1776: 05 0d 02 04 01 02 04 01 02 04 02 03 69 6b 65 81 ............ike.
| 1792: 0e 02 03 01 02 03 01 02 03 03 03 6d 69 74 16 02 ...........mit..
| 1808: 05 01 02 05 01 02 05 5e 02 04 01 02 04 01 02 04 .......^........
| 1824: 02 03 6f 61 64 81 2f 02 03 01 02 03 01 02 03 01 ..oad./.........
| 1840: 06 6d 61 6c 6c 6f 63 76 02 02 01 02 02 01 02 02 .mallocv........
| 1856: 3a 02 03 01 02 03 01 02 03 03 02 74 68 55 02 03 :..........thU..
| 1872: 01 02 03 01 02 03 03 01 78 79 02 02 01 02 02 01 ........xy......
| 1888: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 1904: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 1920: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 1936: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 1952: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 1968: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 1984: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 2000: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 2016: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 2032: 02 02 02 05 65 6d 6f 72 79 81 11 02 03 01 02 03 ....emory.......
| 2048: 01 02 03 04 04 73 79 73 35 58 02 03 01 02 03 01 .....sys5X......
| 2064: 02 03 02 03 6d 61 70 19 02 03 01 02 03 01 02 03 ....map.........
| 2080: 79 02 03 01 02 03 01 02 03 02 04 75 74 65 78 81 y..........utex.
| 2096: 2c 02 02 01 02 02 01 02 02 01 06 6e 6f 63 61 73 ,..........nocas
| 2112: 65 02 06 01 02 02 03 06 01 02 02 03 06 01 02 02 e...............
| 2128: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 2144: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 2160: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 2176: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 2192: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 2208: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 2224: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 2240: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 2256: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 2272: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 2288: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 2304: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 2320: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 2336: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 2352: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 2368: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 2384: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 2400: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 2416: 02 02 03 06 01 02 02 03 07 72 6d 61 6c 69 7a 65 .........rmalize
| 2432: 5b 02 03 01 02 03 01 02 03 02 05 75 6d 62 65 72 [..........umber
| 2448: 81 23 02 04 01 02 04 01 02 04 01 06 6f 66 66 73 .#..........offs
| 2464: 65 74 5e 02 03 01 02 03 01 02 03 02 03 6d 69 74 et^..........mit
| 2480: 81 2c 02 03 01 02 03 01 02 03 01 02 02 01 02 02 .,..............
| 2496: 01 02 02 02 01 70 81 26 02 04 01 02 04 01 02 04 .....p.&........
| 2512: 02 07 76 65 72 66 6c 6f 77 34 02 03 01 02 03 01 ..verflow4......
| 2528: 02 03 01 04 70 61 67 65 1c 02 03 01 02 03 01 02 ....page........
| 2544: 03 64 02 04 01 02 04 01 02 04 13 02 03 01 02 03 .d..............
| 2560: 01 02 03 01 02 03 01 02 03 01 02 03 03 09 72 65 ..............re
| 2576: 6e 74 68 65 73 69 73 49 02 04 01 02 04 01 02 04 nthesisI........
| 2592: 03 05 74 74 65 72 6e 81 0e 02 04 01 02 04 01 02 ..ttern.........
| 2608: 04 02 05 63 61 63 68 65 1f 02 03 01 02 03 01 02 ...cache........
| 2624: 03 02 08 72 65 75 70 64 61 74 65 61 02 03 01 02 ...reupdatea....
| 2640: 03 01 02 03 01 04 72 65 61 64 34 02 04 01 02 04 ......read4.....
| 2656: 01 02 04 03 07 63 75 72 73 69 76 65 22 02 03 01 .....cursive....
| 2672: 02 03 01 02 03 02 04 6f 77 69 64 01 02 03 01 02 .......owid.....
| 2688: 03 01 02 03 02 04 74 72 65 65 64 02 03 01 02 03 ......treed.....
| 2704: 01 02 03 04 02 69 6d 01 06 01 02 02 03 06 01 02 .....im.........
| 2720: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 2736: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 2752: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 2768: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 2784: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 2800: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 2816: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 2832: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 2848: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 2864: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 2880: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 2896: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 2912: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 2928: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 2944: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 2960: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 2976: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
| 2992: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 3008: 01 02 02 03 06 01 02 02 03 06 01 02 02 01 0a 73 ...............s
| 3024: 63 61 6e 73 74 61 74 75 73 70 02 04 01 02 04 01 canstatusp......
| 3040: 02 04 02 05 65 63 74 6f 72 25 02 03 01 02 03 01 ....ector%......
| 3056: 02 03 03 04 6c 65 63 74 7f 02 04 01 02 04 01 02 ....lect........
| 3072: 04 03 05 73 73 69 6f 6e 67 02 03 01 02 03 01 02 ...ssiong.......
| 3088: 03 02 03 69 7a 65 10 02 04 01 02 04 01 02 04 04 ...ize..........
| 3104: 02 04 01 02 04 01 02 04 01 02 04 01 02 04 01 02 ................
| 3120: 04 01 02 04 01 02 04 01 02 04 07 02 04 01 02 04 ................
| 3136: 01 02 04 5b 02 05 01 02 05 01 02 05 10 02 04 01 ...[............
| 3152: 02 04 01 02 04 04 02 04 01 02 04 01 02 04 02 03 ................
| 3168: 6f 66 74 76 02 03 01 02 03 01 02 03 02 02 71 6c oftv..........ql
| 3184: 5e 02 04 01 02 04 01 02 04 13 02 04 01 02 04 01 ^...............
| 3200: 02 04 28 02 03 01 02 03 01 02 03 02 04 74 61 74 ..(..........tat
| 3216: 34 6a 02 03 01 02 03 01 02 03 03 02 6d 74 70 02 4j..........mtp.
| 3232: 03 01 02 03 01 02 03 05 04 76 74 61 62 6d 02 03 .........vtabm..
| 3248: 01 02 03 01 02 03 03 03 6f 72 65 81 35 02 03 01 ........ore.5...
| 3264: 02 03 01 02 03 02 0a 79 6e 63 68 72 6f 6e 6f 75 .......ynchronou
| 3280: 73 28 02 03 01 02 03 01 02 03 04 02 04 01 02 04 s(..............
| 3296: 01 02 04 03 04 73 74 65 6d 81 32 02 02 01 02 02 .....stem.2.....
| 3312: 01 02 02 01 04 74 65 6d 70 81 35 02 02 01 02 02 .....temp.5.....
| 3328: 01 02 02 02 06 68 72 65 61 64 73 31 02 04 01 02 .....hreads1....
| 3344: 04 01 02 04 76 02 04 01 02 04 01 02 04 08 03 61 ....v..........a
| 3360: 66 65 81 38 02 02 01 02 02 01 02 02 02 06 72 69 fe.8..........ri
| 3376: 67 67 65 72 81 20 02 03 01 02 03 01 02 03 08 01 gger. ..........
| 3392: 73 22 02 04 01 02 04 01 02 04 01 07 75 6e 6b 6e s...........unkn
| 3408: 6f 77 6e 73 02 03 01 02 03 01 02 03 01 08 76 61 owns..........va
| 3424: 72 69 61 62 6c 65 81 23 02 03 01 02 03 01 02 03 riable.#........
| 3440: 02 03 64 62 65 81 26 02 03 01 02 03 01 02 03 02 ..dbe.&.........
| 3456: 03 69 65 77 01 02 05 01 02 05 01 02 05 02 03 74 .iew...........t
| 3472: 61 62 37 02 04 01 02 04 01 02 04 04 02 04 01 02 ab7.............
| 3488: 04 01 02 04 01 02 04 01 02 04 01 02 04 01 03 77 ...............w
| 3504: 61 6c 2b 02 03 01 02 03 01 02 03 01 02 03 01 02 al+.............
| 3520: 03 01 02 03 02 05 6f 72 6b 65 72 31 02 03 01 02 ......orker1....
| 3536: 03 01 02 03 76 02 03 01 02 03 01 02 03 01 01 78 ....v..........x
| 3552: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3568: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3584: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3600: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3616: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3632: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3648: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3664: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3680: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3696: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3712: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3728: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3744: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3760: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3776: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3792: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3808: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3824: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3840: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3856: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3872: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3888: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3904: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3920: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3936: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3952: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3968: 06 01 01 02 01 06 04 30 15 1e 0c 28 1b 0d 0c 15 .......0...(....
| 3984: 0c 16 14 16 10 0c 17 0e 0e 0f 11 10 10 0e 10 11 ................
| 4000: 18 11 82 3e 12 10 0f 10 11 10 0f 0f 10 11 0f 0f ...>............
| 4016: 81 05 18 10 81 45 11 0d 13 0f 10 17 0c 0c 0e 18 .....E..........
| 4032: 0c 12 10 0e 0d 0f 13 12 24 0f 17 0f 1a 0d 81 1c ........$.......
| 4048: 11 0f 17 10 82 3e 12 11 11 18 0d 12 2a 14 11 10 .....>......*...
| 4064: 13 0f 12 0f 0f 82 3a 15 10 0f 10 4d 0e 1f 0f 0d ......:....M....
| 4080: 0f 0f 1e 10 10 1a 0f 12 0c 12 14 0f 0e 20 17 19 ............. ..
| page 12 offset 45056
| 0: 0d 00 00 00 01 0d f4 00 0d f4 00 00 00 00 00 00 ................
| 3568: 00 00 00 00 84 04 84 80 80 80 80 02 04 00 88 0c ................
| 3584: 00 07 02 00 01 01 02 56 06 01 01 02 01 06 01 01 .......V........
| 3600: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3616: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3632: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3648: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3664: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3680: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3696: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3712: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3728: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3744: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3760: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3776: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3792: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3808: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3824: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3840: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3856: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3872: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3888: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3904: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3920: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3936: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3952: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3968: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3984: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 4000: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 4016: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 4032: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 4048: 52 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 R...............
| 4064: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 4080: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| end c1a.txt.db
}]} {}
do_catchsql_test 84.1 {
SELECT * FROM t1('R*R*x') ORDER BY rowid DESC;
} {1 {fts5: corruption found reading blob 137438953475 from table "t1"}}
sqlite3_fts5_may_be_corrupt 0
finish_test
+1 -294
View File
@@ -1220,7 +1220,7 @@ do_test 8.0 {
do_catchsql_test 8.1 {
SELECT rowid FROM t1('a* NOT ý‘') ;
} {1 {fts5: corruption on page 1, segment 1, table "t1"}}
} {0 {1 2 3 4 5 6 7}}
#-------------------------------------------------------------------------
reset_db
@@ -1917,299 +1917,6 @@ do_catchsql_test 11.3 {
REPLACE INTO t1(rowid,b,a,rowid) VALUES(x'44023b9eb002d28b0ee90c',1,2,3);
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 12.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 24576 pagesize 4096 filename p.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 03 00 00 00 06 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
| 96: 00 2e 76 89 0d 00 00 00 06 0d ed 00 0f bb 0f 64 ..v............d
| 112: 0e f9 0e a2 0e 45 0d ed 00 00 00 00 00 00 00 00 .....E..........
| 3552: 00 00 00 00 00 00 00 00 00 00 00 00 00 56 06 06 .............V..
| 3568: 17 1f 1f 01 7d 74 61 62 6c 65 66 74 5f 63 6f 6e .....tableft_con
| 3584: 66 69 67 66 74 5f 63 6f 6e 66 69 67 06 43 52 45 figft_config.CRE
| 3600: 41 54 45 20 54 41 42 4c 45 20 27 66 74 5f 63 6f ATE TABLE 'ft_co
| 3616: 6e 66 69 67 27 28 6b 20 50 52 49 4d 41 52 59 20 nfig'(k PRIMARY
| 3632: 4b 45 59 2c 20 76 29 20 57 49 54 48 4f 55 54 20 KEY, v) WITHOUT
| 3648: 52 4f 57 49 44 5b 05 07 17 21 21 01 81 01 74 61 ROWID[...!!...ta
| 3664: 62 6c 65 66 74 5f 64 6f 63 73 69 7a 65 66 74 5f bleft_docsizeft_
| 3680: 64 6f 63 73 69 7a 65 05 43 52 45 41 54 45 20 54 docsize.CREATE T
| 3696: 41 42 4c 45 20 27 66 74 5f 64 6f 63 73 69 7a 65 ABLE 'ft_docsize
| 3712: 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 '(id INTEGER PRI
| 3728: 4d 41 52 59 20 4b 45 59 2c 20 73 7a 20 42 4c 4f MARY KEY, sz BLO
| 3744: 42 29 55 04 06 17 21 21 01 77 74 61 62 6c 65 66 B)U...!!.wtablef
| 3760: 74 5f 63 6f 6e 74 65 6e 74 66 74 5f 63 6f 6e 74 t_contentft_cont
| 3776: 65 6e 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE
| 3792: 20 27 66 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 'ft_content'(id
| 3808: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY
| 3824: 20 4b 45 59 2c 20 63 30 29 69 03 07 17 19 19 01 KEY, c0)i......
| 3840: 81 2d 74 61 62 6c 65 66 74 5f 69 64 78 66 74 5f .-tableft_idxft_
| 3856: 69 64 78 03 43 52 45 41 54 45 20 54 41 42 4c 45 idx.CREATE TABLE
| 3872: 20 27 66 74 5f 69 64 78 27 28 73 65 67 69 64 2c 'ft_idx'(segid,
| 3888: 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 term, pgno, PRI
| 3904: 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 MARY KEY(segid,
| 3920: 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 term)) WITHOUT R
| 3936: 4f 57 49 44 55 02 07 17 1b 1b 01 81 01 74 61 62 OWIDU........tab
| 3952: 6c 65 66 74 5f 64 61 74 61 66 74 5f 64 61 74 61 left_dataft_data
| 3968: 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 66 .CREATE TABLE 'f
| 3984: 74 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 t_data'(id INTEG
| 4000: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
| 4016: 62 6c 6f 63 6b 20 42 4c 4f 42 29 43 01 06 17 11 block BLOB)C....
| 4032: 11 08 75 74 61 62 6c 65 66 74 66 74 43 52 45 41 ..utableftftCREA
| 4048: 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 TE VIRTUAL TABLE
| 4064: 20 66 74 20 55 53 49 4e 47 20 66 74 73 35 28 61 ft USING fts5(a
| 4080: 2c 20 64 65 74 61 69 6c 3d 63 6f 6c 75 6d 6e 29 , detail=column)
| page 2 offset 4096
| 0: 0d 00 00 00 03 0f 7f 00 0f e8 0f ef 0f 7f 00 00 ................
| 3952: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 62 ...............b
| 3968: 84 80 80 80 80 01 04 00 81 48 00 00 00 54 04 30 .........H...T.0
| 3984: 61 61 61 01 81 02 02 02 02 02 02 02 02 02 02 02 aaa.............
| 4000: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
| 4016: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
| 4032: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
| 4048: 02 02 02 02 02 02 02 03 6a 6a 6a 01 02 02 04 08 ........jjj.....
| 4064: 08 08 08 08 08 08 08 08 05 01 03 00 10 01 0a 0f ................
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 3 offset 8192
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 01 0f d4 00 0f d4 00 00 00 00 00 00 ................
| 4048: 00 00 00 00 2a 01 03 00 5b 61 61 61 20 62 62 62 ....*...[aaa bbb
| 4064: 20 63 63 63 20 64 64 64 20 65 65 65 20 66 66 66 ccc ddd eee fff
| 4080: 20 67 67 67 20 68 68 68 20 69 69 69 20 6a 6a 6a ggg hhh iii jjj
| page 5 offset 16384
| 0: 0d 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 04 01 03 00 0e 0a ................
| 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.
| end p.db
}]} {}
do_catchsql_test 12.1 {
SELECT rowid FROM ft('a:aaa')
} {0 1}
#-------------------------------------------------------------------------
reset_db
do_test 13.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 24576 pagesize 4096 filename vuln_001.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 03 00 00 00 06 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
| 96: 00 2e 76 89 0d 00 00 00 06 0e 09 00 0f ca 0f 77 ..v............w
| 112: 0f 0f 0e b7 0e 5e 0e 09 00 00 00 00 00 00 00 00 .....^..........
| 3584: 00 00 00 00 00 00 00 00 00 53 06 06 17 1d 1d 01 .........S......
| 3600: 7b 74 61 62 6c 65 74 5f 63 6f 6e 66 69 67 74 5f .tablet_configt_
| 3616: 63 6f 6e 66 69 67 06 43 52 45 41 54 45 20 54 41 config.CREATE TA
| 3632: 42 4c 45 20 27 74 5f 63 6f 6e 66 69 67 27 28 6b BLE 't_config'(k
| 3648: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
| 3664: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 57 05 WITHOUT ROWIDW.
| 3680: 06 17 1f 1f 01 7f 74 61 62 6c 65 74 5f 64 6f 63 ......tablet_doc
| 3696: 73 69 7a 65 74 5f 64 6f 63 73 69 7a 65 05 43 52 sizet_docsize.CR
| 3712: 45 41 54 45 20 54 41 42 4c 45 20 27 74 5f 64 6f EATE TABLE 't_do
| 3728: 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 45 csize'(id INTEGE
| 3744: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 R PRIMARY KEY, s
| 3760: 7a 20 42 4c 4f 42 29 56 04 06 17 1f 1f 01 7d 74 z BLOB)V.......t
| 3776: 61 62 6c 65 74 5f 63 6f 6e 74 65 6e 74 74 5f 63 ablet_contentt_c
| 3792: 6f 6e 74 65 6e 74 04 43 52 45 41 54 45 20 54 41 ontent.CREATE TA
| 3808: 42 4c 45 20 27 74 5f 63 6f 6e 74 65 6e 74 27 28 BLE 't_content'(
| 3824: 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 id INTEGER PRIMA
| 3840: 52 59 20 4b 45 59 2c 20 63 30 2c 20 63 31 29 66 RY KEY, c0, c1)f
| 3856: 03 07 17 17 17 01 81 2b 74 61 62 6c 65 74 5f 69 .......+tablet_i
| 3872: 64 78 74 5f 69 64 78 03 43 52 45 41 54 45 20 54 dxt_idx.CREATE T
| 3888: 41 42 4c 45 20 27 74 5f 69 64 78 27 28 73 65 67 ABLE 't_idx'(seg
| 3904: 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 id, term, pgno,
| 3920: 50 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 PRIMARY KEY(segi
| 3936: 64 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 d, term)) WITHOU
| 3952: 54 20 52 4f 57 49 44 51 02 06 17 19 19 01 7f 74 T ROWIDQ.......t
| 3968: 61 62 6c 65 74 5f 64 61 74 61 74 5f 64 61 74 61 ablet_datat_data
| 3984: 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
| 4000: 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 45 _data'(id INTEGE
| 4016: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 R PRIMARY KEY, b
| 4032: 6c 6f 63 6b 20 42 4c 4f 42 29 34 01 06 17 0f 0f lock BLOB)4.....
| 4048: 08 5b 74 61 62 6c 65 74 74 43 52 45 41 54 45 20 .[tablettCREATE
| 4064: 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 20 VIRTUAL TABLE t
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
| page 2 offset 4096
| 0: 0d 00 00 00 04 0b da 00 0f e7 0f ef 0f ce 0b da ................
| 3024: 00 00 00 00 00 00 00 00 00 00 87 6c 84 80 80 80 ...........l....
| 3040: 80 02 04 00 8f 5c 00 00 03 e8 80 80 80 80 80 80 ................
| 3056: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3072: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3088: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3104: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3120: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3136: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3152: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3168: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3184: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3200: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3216: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3232: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3248: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3264: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3280: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3296: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3312: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3328: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3344: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3360: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3376: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3392: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3408: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3424: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3440: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3456: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3472: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3488: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3504: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3520: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3536: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3552: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3568: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3584: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3600: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3616: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3632: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3648: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3664: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3680: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3696: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3712: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3728: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3744: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3760: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3776: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3792: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3808: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3824: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3840: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3856: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3872: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3888: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3904: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3920: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3936: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3952: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3968: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 3984: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 4000: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 4016: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
| 4032: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 12 84 ................
| 4048: 80 80 80 80 01 03 00 2a 00 0b 00 0e 06 30 68 65 .......*.....0he
| 4064: 6c 6c 6f 01 04 04 04 06 01 03 00 12 01 02 02 0f llo.............
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 02 ...$............
| page 3 offset 8192
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 01 0f e8 00 0f e8 00 00 00 00 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 16 01 04 00 23 1b 68 65 ............#.he
| 4080: 6c 6c 6f 20 77 6f 72 6c 64 66 6f 6f 20 62 61 72 llo worldfoo bar
| page 5 offset 16384
| 0: 0d 00 00 00 01 0f f9 00 0f f9 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 05 01 03 00 10 02 02 ................
| 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.
| end vuln_001.db
}]} {}
do_catchsql_test 13.1 {
SELECT * FROM t('a:hello')
} {0 {{hello world} {foo bar}}}
#-------------------------------------------------------------------------
reset_db
#-------------------------------------------------------------------------
reset_db
do_test 14.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 24576 pagesize 4096 filename vuln_001.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 03 00 00 00 06 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
| 96: 00 2e 76 89 0d 00 00 00 06 0e 0a 00 0f c7 0f 74 ..v............t
| 112: 0f 0c 0e b8 0e 5f 0e 0a 00 00 00 00 00 00 00 00 ....._..........
| 3584: 00 00 00 00 00 00 00 00 00 00 53 06 06 17 1d 1d ..........S.....
| 3600: 01 7b 74 61 62 6c 65 74 5f 63 6f 6e 66 69 67 74 ..tablet_configt
| 3616: 5f 63 6f 6e 66 69 67 06 43 52 45 41 54 45 20 54 _config.CREATE T
| 3632: 41 42 4c 45 20 27 74 5f 63 6f 6e 66 69 67 27 28 ABLE 't_config'(
| 3648: 6b 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 k PRIMARY KEY, v
| 3664: 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 57 ) WITHOUT ROWIDW
| 3680: 05 06 17 1f 1f 01 7f 74 61 62 6c 65 74 5f 64 6f .......tablet_do
| 3696: 63 73 69 7a 65 74 5f 64 6f 63 73 69 7a 65 05 43 csizet_docsize.C
| 3712: 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 5f 64 REATE TABLE 't_d
| 3728: 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 ocsize'(id INTEG
| 3744: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
| 3760: 73 7a 20 42 4c 4f 42 29 52 04 06 17 1f 1f 01 75 sz BLOB)R......u
| 3776: 74 61 62 6c 65 74 5f 63 6f 6e 74 65 6e 74 74 5f tablet_contentt_
| 3792: 63 6f 6e 74 65 6e 74 04 43 52 45 41 54 45 20 54 content.CREATE T
| 3808: 41 42 4c 45 20 27 74 5f 63 6f 6e 74 65 6e 74 27 ABLE 't_content'
| 3824: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 3840: 41 52 59 20 4b 45 59 2c 20 63 30 29 66 03 07 17 ARY KEY, c0)f...
| 3856: 17 17 01 81 2b 74 61 62 6c 65 74 5f 69 64 78 74 ....+tablet_idxt
| 3872: 5f 69 64 78 03 43 52 45 41 54 45 20 54 41 42 4c _idx.CREATE TABL
| 3888: 45 20 27 74 5f 69 64 78 27 28 73 65 67 69 64 2c E 't_idx'(segid,
| 3904: 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 term, pgno, PRI
| 3920: 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 MARY KEY(segid,
| 3936: 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 term)) WITHOUT R
| 3952: 4f 57 49 44 51 02 06 17 19 19 01 7f 74 61 62 6c OWIDQ.......tabl
| 3968: 65 74 5f 64 61 74 61 74 5f 64 61 74 61 02 43 52 et_datat_data.CR
| 3984: 45 41 54 45 20 54 41 42 4c 45 20 27 74 5f 64 61 EATE TABLE 't_da
| 4000: 74 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 ta'(id INTEGER P
| 4016: 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 RIMARY KEY, bloc
| 4032: 6b 20 42 4c 4f 42 29 37 01 06 17 0f 0f 08 61 74 k BLOB)7......at
| 4048: 61 62 6c 65 74 74 43 52 45 41 54 45 20 56 49 52 ablettCREATE VIR
| 4064: 54 55 41 4c 20 54 41 42 4c 45 20 74 20 55 53 49 TUAL TABLE t 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 0f ef 00 03 0f ac 00 0f e8 0f ac 0f c4 00 00 ................
| 4000: 00 00 00 00 00 00 00 00 00 00 00 00 16 0a 03 00 ................
| 4016: 32 01 00 00 00 01 01 01 00 d5 aa d5 2b 01 01 01 2...........+...
| 4032: 83 74 01 01 1d 84 80 80 80 80 01 03 00 40 00 00 .t...........@..
| 4048: 00 18 06 30 68 65 6c 6c 6f 01 02 02 01 05 77 6f ...0hello.....wo
| 4064: 72 6c 64 01 02 03 04 0a 05 01 03 00 10 01 02 00 rld.............
| 4080: 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| page 3 offset 8192
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 01 0f f0 00 0f f0 00 00 00 00 00 00 ................
| 4080: 0e 01 03 00 23 68 65 6c 6c 6f 20 77 6f 72 6c 64 ....#hello world
| page 5 offset 16384
| 0: 0d 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 04 01 03 00 0e 02 ................
| 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.
| end vuln_001.db
}]} {}
do_catchsql_test 14.1 {
SELECT * FROM t('hello');
} {1 {out of memory}}
sqlite3_fts5_may_be_corrupt 0
finish_test
-36
View File
@@ -125,40 +125,4 @@ do_catchsql_test 2.3 {
DELETE FROM t1 WHERE rowid = 1
} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
PRAGMA page_size=4096;
PRAGMA journal_mode=DELETE;
CREATE VIRTUAL TABLE t USING fts5(x, detail=none);
WITH s(i) AS (
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<5000
)
INSERT INTO t(rowid, x) SELECT i, 'vulnerabilitytest' FROM s;
INSERT INTO t(t) VALUES('optimize');
INSERT INTO t(t, rank) VALUES('secure-delete', 1);
} {delete}
do_test 3.1 {
db eval { SELECT rowid AS rowid, block FROM t_data ORDER BY rowid } {
if {$rowid>=10 && [string length $block]>=4} {
binary scan $block Su first_rowid_off
set pgno [expr ($rowid & 0x7FFFFFFF)]
if {$pgno>=2 && $first_rowid_off>0} break
}
}
set bad [binary format a*a* "\xFF\xFF" [string range $block 2 end]]
db eval {
UPDATE t_data SET block = $bad WHERE rowid=$rowid
}
} {}
do_catchsql_test 3.2 {
DELETE FROM t WHERE rowid=4500;
} {1 {fts5: corruption in table "t"}}
finish_test
File diff suppressed because one or more lines are too long
-273
View File
@@ -1,273 +0,0 @@
# 2026 May 11
#
# 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 fts5corruptA
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
sqlite3_fts5_may_be_corrupt 1
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t USING fts5(x, detail='full');
INSERT INTO t(t, rank) VALUES('pgsz', 32);
}
set big [string repeat "a " 200]
do_execsql_test 1.1 {
INSERT INTO t(rowid, x) VALUES(1, $big)
}
do_test 1.2 {
db eval {
SELECT min(rowid) AS base_rowid, count(*) AS page_count FROM t_data
WHERE rowid>1000
} {}
} {}
do_test 1.3 {
for {set ii 0} {$ii < 5} {incr ii} {
db eval {
INSERT INTO t_data(rowid, block)
VALUES( $base_rowid + $page_count + $ii, zeroblob(4) );
}
}
db eval {
INSERT INTO t_data(rowid, block)
VALUES( $base_rowid + $page_count + 5,
unhex('00000080' || 'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC') );
}
set {} {}
} {}
db close
do_test 1.4 {
set hex [hexio_read test.db 0 [file size test.db]]
set off [string first "023061018310" $hex]
set hex [string replace $hex $off [expr $off+11] 023061018370]
hexio_write test.db 0 $hex
} {6144}
sqlite3 db test.db
do_catchsql_test 1.5 {
SELECT rowid FROM t WHERE t MATCH 'a'
} {1 {fts5: corruption found reading blob 137438953481 from table "t"}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a);
BEGIN;
INSERT INTO t1(rowid, a) VALUES(1, 'aaaa');
INSERT INTO t1(rowid, a) VALUES(2, 'bbbb');
INSERT INTO t1(rowid, a) VALUES(3, 'cccc');
COMMIT;
}
db close
do_test 2.1 {
set hex [hexio_read test.db 0 [file size test.db]]
set off [string first "010463636363" $hex]
set hex [string replace $hex $off [expr $off+11] 017F63636363]
hexio_write test.db 0 $hex
set {} {}
} {}
sqlite3 db test.db
do_catchsql_test 2.2 {
SELECT rowid FROM t1('cccccccccccccccccccccccccccccccccccccccccccccccc');
} {1 {fts5: corruption on page 1, segment 1, table "t1"}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
INSERT INTO t1 VALUES(
'hello',
'alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo lima mike november oscar papa quebec romeo sierra tango uniform victor whiskey xray yankee zulu',
'ant bear cat dog elephant fox gorilla hippo iguana jaguar kangaroo lion monkey newt octopus panda quail rabbit snake turtle unicorn vulture walrus xerus yak zebra'
);
UPDATE t1_data SET block = unhex(
-- Preserve bytes 0-168: header through hello's nSz field
hex(substr(block, 1, 169))
-- Inject 448 bytes of 0xFF: corrupted poslist + subsequent term data
|| replace(hex(zeroblob(448)), '00', 'FF')
-- Preserve 16 bytes of page index needed for hello lookup
|| hex(substr(block, 618, 16))
-- Corrupt remaining 37 footer bytes (not needed for hello lookup)
|| replace(hex(zeroblob(37)), '00', 'FF')
)
WHERE id = 137438953473;
}
do_test 3.1 {
execsql { SELECT * FROM t1 WHERE t1 MATCH '{a b}: hello' }
set {} {}
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t1 USING fts5(content);
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
BEGIN;
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<5000
)
INSERT INTO t1(content) SELECT 'xyzterm' FROM s;
COMMIT;
INSERT INTO t1(t1) VALUES('optimize');
}
do_test 4.1 {
db eval {
SELECT rowid AS a, hex(block) AS block FROM t1_data
WHERE ((rowid>>36) & 0x01)==1
AND ((rowid>>31) & 0x1F)==0
} {
set n [string length $block]
set block [string range $block 0 11]
append block [string repeat "00" [expr ($n/2)-7-2]]
append block "8080"
db eval {
UPDATE t1_data SET block = unhex($block) WHERE rowid = $a
}
}
} {}
do_catchsql_test 4.2 {
SELECT count(*) FROM (
SELECT rowid FROM t1 WHERE t1 MATCH 'xyzterm' ORDER BY rowid ASC
)
} {0 5000}
do_catchsql_test 4.3 {
SELECT count(*) FROM (
SELECT rowid FROM t1 WHERE t1 MATCH 'xyzterm' ORDER BY rowid DESC
)
} {0 4987}
do_test 4.4 {
db eval {
SELECT rowid AS a, hex(block) AS block FROM t1_data
WHERE ((rowid>>36) & 0x01)==1
AND ((rowid>>31) & 0x1F)==0
} {
set n [string length $block]
set block [string range $block 0 $n-5]
append block [string repeat "00" 2]
db eval {
UPDATE t1_data SET block = unhex($block) WHERE rowid = $a
}
}
} {}
do_catchsql_test 4.5 {
SELECT count(*) FROM (
SELECT rowid FROM t1 WHERE t1 MATCH 'xyzterm' ORDER BY rowid ASC
)
} {0 5000}
do_catchsql_test 4.6 {
SELECT count(*) FROM (
SELECT rowid FROM t1 WHERE t1 MATCH 'xyzterm' ORDER BY rowid DESC
)
} {0 4879}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
CREATE VIRTUAL TABLE t USING fts5(x);
INSERT INTO t(t,rank) VALUES('pgsz', 64);
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<80
)
INSERT INTO t SELECT 'shared word' || (i%10) || ' shared shared' FROM s;
INSERT INTO t(t) VALUES('optimize');
}
set lLeaf [db eval { SELECT id FROM t_data }]
db_save_and_close
foreach leaf $lLeaf {
db_restore_and_reopen
set leaf [expr $leaf]
set hex [db one {
SELECT hex(block) FROM t_data WHERE id=$leaf
}]
# Replace the first 4 bytes of each leaf page with the size of the leaf in
# bytes plus 50 as a 2 byte integer, followed by 0x7FFF.
#
set nn [expr [string length $hex]/2]
set first "[format %.4x [expr $nn+50]]7FFF"
set hex [string replace $hex 0 7 $first]
db eval { UPDATE t_data SET block=unhex($hex) WHERE id=$leaf }
do_test 5.1.$leaf {
catchsql {
SELECT rowid FROM t WHERE t MATCH 'shared' ORDER BY rowid DESC;
}
set {} {}
} {}
do_test 5.1.$leaf.2 {
catchsql {
PRAGMA integrity_check;
}
set {} {}
} {}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE t USING fts5(x, content='', contentless_delete=1);
INSERT INTO t(rowid,x)
VALUES(1,'a b'), (2,'c d'), (3,'e f'), (4,'g h'), (5,'i j');
INSERT INTO t(t) VALUES('optimize');
DELETE FROM t WHERE rowid=2;
}
do_test 6.1 {
db eval {
SELECT rowid AS rid, hex(block) AS blk
FROM t_data WHERE rowid>1_000_000_000_000
} {}
set blk [string replace $blk 8 15 20000000]
execsql {
UPDATE t_data SET block = unhex($blk) WHERE rowid=$rid
}
} {}
do_execsql_test 6.2 {
DELETE FROM t WHERE rowid=3;
}
sqlite3_fts5_may_be_corrupt 0
finish_test
+3
View File
@@ -379,6 +379,9 @@ do_execsql_test 12.2 {
db close
sqlite3 db test.db -readonly 1
explain_i {
PRAGMA integrity_check
}
do_execsql_test 12.3 {
PRAGMA integrity_check
} {ok}
-17
View File
@@ -64,21 +64,4 @@ foreach {tn sql} {
}
}
#-------------------------------------------------------------------------
# Verify that https://sqlite.org/forum/forumpost/95413eb410 has been
# fixed.
#
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE f1 USING fts5(x);
BEGIN TRANSACTION;
INSERT INTO f1(x) VALUES('abc def ghi');
}
do_test 2.1 {
sqlite3_interrupt db
} {}
do_execsql_test 2.2 {
ROLLBACK
}
finish_test
-9
View File
@@ -65,14 +65,5 @@ do_eqp_test 1.4 {
`--SCAN vt VIRTUAL TABLE INDEX 0:=
}
do_eqp_test 1.5 {
SELECT * FROM vt, t1
WHERE vt.rowid = t1.rowid AND vt MATCH ? AND b = ?
} {
QUERY PLAN
|--SCAN vt VIRTUAL TABLE INDEX 0:M1
`--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?)
}
finish_test
-13
View File
@@ -743,19 +743,6 @@ do_execsql_test 15.4 {
SELECT c, fts5_columnlocale(ft, 2) FROM ft
} {three {} three loc}
#-------------------------------------------------------------------------
#
set nMaxCol 500
set nStep 20
for {set ii $nStep} {$ii <= $nMaxCol} {incr ii $nStep} {
set C [list]
for {set iCol 0} {$iCol<$ii} {incr iCol} {
lappend C col$iCol
}
set ct "CREATE VIRTUAL TABLE t$ii USING fts5([join $C ,], locale=1)"
do_execsql_test 16.$ii $ct
}
finish_test
-16
View File
@@ -238,22 +238,6 @@ do_execsql_test 6.3 {
INSERT INTO g1(g1) VALUES('integrity-check');
}
#--------------------------------------------------------------------------
# Check that passing -2147483648 as the parameter to a merge command
# does not cause a signed integer overflow error.
#
reset_db
do_execsql_test 7.0 {
CREATE VIRTUAL TABLE f1 USING fts5(a);
}
do_execsql_test 7.1 {
INSERT INTO f1 VALUES('one two three');
INSERT INTO f1 VALUES('four five six');
INSERT INTO f1 VALUES('seven eight nine');
}
do_execsql_test 7.2 {
INSERT INTO f1(f1, rank) VALUES('merge', -2147483648);
}
finish_test
-13
View File
@@ -66,18 +66,5 @@ do_near_test 1.23 "a b c d e f g h i" { NEAR(a+b+c+d i b+c, 4) } 0
do_near_test 1.24 "a b c d e f g h i" { NEAR(i a+b+c+d b+c, 5) } 1
do_near_test 1.25 "a b c d e f g h i" { NEAR(i a+b+c+d b+c, 4) } 0
#-------------------------------------------------------------------------
# Check that https://sqlite.org/bugs/forumpost/16bb36f7e8 is fixed.
#
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t USING fts5(x, tokenize=trigram);
INSERT INTO t
VALUES('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
}
do_execsql_test 2.1 {
SELECT count(*) FROM t WHERE t MATCH 'NEAR(aaa aaa, 4)';
} {1}
finish_test
-8
View File
@@ -65,13 +65,5 @@ foreach {in out} $test_vocab {
incr i
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE tbl USING fts5(t, tokenize='porter unicode61');
INSERT INTO tbl VALUES(' andeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee');
}
finish_test
-28
View File
@@ -418,34 +418,6 @@ do_execsql_test 7.1.2 {
INSERT INTO t2(t2) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
reset_db
fts5_aux_test_functions db
proc tcl_create {args} { return "tcl_tokenize" }
sqlite3_fts5_create_tokenizer db tcl tcl_create
proc tcl_tokenize {tflags text} {
foreach {w iStart iEnd} [fts5_tokenize_split $text] {
sqlite3_fts5_token $w $iStart $iEnd
if {$w=="usa"} {
sqlite3_fts5_token -colo "united" $iStart $iEnd
}
}
}
do_execsql_test 8.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize='tcl', tokendata=1);
INSERT INTO t1 VALUES('usa is great');
INSERT INTO t1 VALUES('canada is cool');
INSERT INTO t1 VALUES('australia is what matters');
}
do_execsql_test 8.1 {
SELECT * FROM t1 WHERE t1 MATCH 'usa*';
} {{usa is great}}
} ;# foreach_detail_mode
finish_test
-10
View File
@@ -371,14 +371,4 @@ do_execsql_test 10.10 {
a 2 2 b 2 2 c 2 2 d 1 1 e 1 1 f 1 1
}
# Bug report 2026-05-18T05:19:01Z
#
set manyporters {porter Porter}
for {set i 0} {$i<18} {incr i} {
set manyporters "$manyporters $manyporters"
}
do_execsql_test 11.1 "
CREATE VIRTUAL TABLE t11 USING fts5(a,b,tokenize=\"$manyporters\");
" {}
finish_test
-22
View File
@@ -305,28 +305,6 @@ do_catchsql_test 6.2 {
sqlite3_fts5_may_be_corrupt 0
#-------------------------------------------------------------------------
reset_db
do_execsql_test 7.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b);
CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, col);
INSERT INTO t1 VALUES('xx', 'xx');
CREATE TABLE x1(t);
INSERT INTO x1 VALUES('xx');
INSERT INTO x1 VALUES('xx');
SELECT term, col FROM v1;
} {
xx a xx b
}
do_execsql_test 7.1 {
SELECT * FROM x1 WHERE 'a'=(SELECT col FROM v1 WHERE term=t)
} {xx xx}
finish_test
-153
View File
@@ -1,153 +0,0 @@
#
# 2026 March 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 script extracts the documentation for the API used by fts5 auxiliary
# functions from header file fts5.h. It outputs html text on stdout that
# is included in the documentation on the web.
#
sqlite3 db fts5cost.db
# Create an IPK table with 1,000,000 entries. Short records.
#
set res [list [catch { db eval {SELECT count(*) FROM t1} } msg] $msg]
if {$res!="0 1000000"} {
db eval {
PRAGMA mmap_size = 1000000000; -- 1GB
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
)
INSERT INTO t1 SELECT i, hex(randomblob(8)) FROM s;
}
}
# Create an FTS5 table with 1,000,000 entries. Each row contains a single
# column containing a document of 100 terms chosen pseudo-randomly from
# a vocabularly of 2000.
set res [list [catch { db eval {SELECT count(*) FROM f1} } msg] $msg]
if {$res!="0 1000000"} {
set nVocab 2000
set nTerm 100
db eval {
BEGIN;
DROP TABLE IF EXISTS vocab1;
CREATE TABLE vocab1(w);
}
for {set ii 0} {$ii<$nVocab} {incr ii} {
set word [format %06x [expr {int(abs(rand()) * 0xFFFFFF)}]]
db eval { INSERT INTO vocab1 VALUES($word) }
lappend lVocab $word
}
db func doc doc
proc doc {} {
for {set ii 0} {$ii<$::nTerm} {incr ii} {
lappend ret [lindex $::lVocab [expr int(abs(rand())*$::nVocab)]]
}
set ret
}
db eval {
DROP TABLE IF EXISTS f1;
CREATE VIRTUAL TABLE f1 USING fts5(x);
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
)
INSERT INTO f1(rowid, x) SELECT i, doc() FROM s;
COMMIT;
}
} else {
set lVocab [db eval { SELECT * FROM vocab1 }]
set nVocab [llength $lVocab]
}
proc rowid_query {n} {
set rowid 654
for {set ii 0} {$ii<$n} {incr ii} {
db eval { SELECT b FROM t1 WHERE a = $rowid }
set rowid [expr {($rowid + 7717) % 1000000}]
}
}
proc rowid_query_fts {n} {
set rowid 654
for {set ii 0} {$ii<$n} {incr ii} {
db eval { SELECT * FROM f1 WHERE rowid = $rowid }
set rowid [expr {($rowid + 7717) % 1000000}]
}
}
proc match_query_fts {n} {
set idx 654
for {set ii 0} {$ii<$n} {incr ii} {
set match [lrange $::lVocab $idx $idx+1]
db eval { SELECT * FROM f1($match) }
set idx [expr {($idx + 7717) % $::nVocab}]
}
}
proc prefix_query_fts {n} {
set idx 654
for {set ii 0} {$ii<$n} {incr ii} {
set match "[lindex $::lVocab $idx]*"
db eval { SELECT * FROM f1($match) }
set idx [expr {($idx + 7717) % $::nVocab}]
}
}
proc match_rowid_query_fts {n} {
set idx 654
for {set ii 0} {$ii<$n} {incr ii} {
set match "[lindex $::lVocab $idx]"
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
set idx [expr {($idx + 7717) % $::nVocab}]
}
}
proc prefix_rowid_query_fts {n} {
set idx 654
for {set ii 0} {$ii<$n} {incr ii} {
set match "[lindex $::lVocab $idx]*"
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
set idx [expr {($idx + 7717) % $::nVocab}]
}
}
proc mytime {cmd div} {
set tm [time $cmd]
expr {[lindex $tm 0] / $div}
}
#set us [mytime { match_rowid_query_fts 1000 } 1000]
#puts "1000 match/rowid queries on fts5 table: ${us} per query"
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
set us [mytime { match_query_fts 10 } 10]
puts "10 match queries on fts5 table: ${us} per query"
set us [mytime { prefix_query_fts 10 } 10]
puts "10 prefix queries on fts5 table: ${us} per query"
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
set us [mytime { rowid_query 10000 } 10000]
puts "10000 by-rowid queries on normal table: ${us} per query"
set us [mytime { rowid_query_fts 10000 } 10000]
puts "10000 by-rowid queries on fts5 table: ${us} per query"
+4 -8
View File
@@ -105,9 +105,6 @@ static const unsigned char icuUtf8Trans1[] = {
while( (*zIn & 0xc0)==0x80 ){ \
c = (c<<6) + (0x3f & *(zIn++)); \
} \
if( c<0x80 \
|| (c&0xFFFFF800)==0xD800 \
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
}
#define SQLITE_ICU_SKIP_UTF8(zIn) \
@@ -365,7 +362,7 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
const UChar *zInput; /* Pointer to input string */
UChar *zOutput = 0; /* Pointer to output buffer */
int nInput; /* Size of utf-16 input string in bytes */
sqlite3_int64 nOut; /* Size of output buffer in bytes */
int nOut; /* Size of output buffer in bytes */
int cnt;
int bToUpper; /* True for toupper(), false for tolower() */
UErrorCode status;
@@ -388,7 +385,7 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
}
for(cnt=0; cnt<2; cnt++){
UChar *zNew = sqlite3_realloc64(zOutput, nOut);
UChar *zNew = sqlite3_realloc(zOutput, nOut);
if( zNew==0 ){
sqlite3_free(zOutput);
sqlite3_result_error_nomem(p);
@@ -397,9 +394,9 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
zOutput = zNew;
status = U_ZERO_ERROR;
if( bToUpper ){
nOut = 2LL*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
}else{
nOut = 2LL*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
}
if( U_SUCCESS(status) ){
@@ -519,7 +516,6 @@ static void icuLoadCollation(
}
sqlite3_result_error(p, sqlite3_str_value(pStr), -1);
sqlite3_free(sqlite3_str_finish(pStr));
ucol_close(pUCollator);
return;
}
}
+1 -1
View File
@@ -319,7 +319,7 @@ static int intckGetToken(const char *z){
char c = z[0];
int iRet = 1;
if( c=='\'' || c=='"' || c=='`' ){
while( z[iRet] ){
while( 1 ){
if( z[iRet]==c ){
iRet++;
if( z[iRet]!=c ) break;
+3 -3
View File
@@ -847,7 +847,7 @@ static int amatchConnect(
(void)pAux;
*ppVtab = 0;
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
rc = SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -928,7 +928,7 @@ amatchConnectError:
static int amatchOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
amatch_vtab *p = (amatch_vtab*)pVTab;
amatch_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->pVtab = p;
@@ -1157,7 +1157,7 @@ static int amatchNext(sqlite3_vtab_cursor *cur){
#endif
nWord = (int)strlen(pWord->zWord+2);
if( nWord+20>nBuf ){
nBuf = nWord+100;
nBuf = (char)(nWord+100);
zBuf = sqlite3_realloc64(zBuf, nBuf);
if( zBuf==0 ) return SQLITE_NOMEM;
}
+3 -3
View File
@@ -232,7 +232,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_text(context,"",-1,SQLITE_STATIC);
break;
}
cBuf = sqlite3_malloc64(nc);
cBuf = sqlite3_malloc(nc);
if( !cBuf ) goto memFail;
nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf);
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
@@ -254,7 +254,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_zeroblob(context, 0);
break;
}
bBuf = sqlite3_malloc64(nb);
bBuf = sqlite3_malloc(nb);
if( !bBuf ) goto memFail;
nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf);
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
@@ -275,7 +275,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_base64_init
int sqlite3_base_init
#else
static int sqlite3_base64_init
#endif
+9 -9
View File
@@ -262,7 +262,7 @@ static int allBase85( char *p, int len ){
#ifndef BASE85_STANDALONE
#ifndef OMIT_BASE85_CHECKER
# ifndef OMIT_BASE85_CHECKER
/* This function does the work for the SQLite is_base85(t) UDF. */
static void is_base85(sqlite3_context *context, int na, sqlite3_value *av[]){
assert(na==1);
@@ -282,7 +282,7 @@ static void is_base85(sqlite3_context *context, int na, sqlite3_value *av[]){
return;
}
}
#endif
# endif
/* This function does the work for the SQLite base85(x) UDF. */
static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
@@ -309,7 +309,7 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_text(context,"",-1,SQLITE_STATIC);
break;
}
cBuf = sqlite3_malloc64(nc);
cBuf = sqlite3_malloc(nc);
if( !cBuf ) goto memFail;
nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf);
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
@@ -331,7 +331,7 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_zeroblob(context, 0);
break;
}
bBuf = sqlite3_malloc64(nb);
bBuf = sqlite3_malloc(nb);
if( !bBuf ) goto memFail;
nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf);
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
@@ -352,14 +352,14 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_base85_init
int sqlite3_base_init
#else
static int sqlite3_base85_init
#endif
(sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErr;
#ifndef OMIT_BASE85_CHECKER
# ifndef OMIT_BASE85_CHECKER
{
int rc = sqlite3_create_function
(db, "is_base85", 1,
@@ -367,7 +367,7 @@ static int sqlite3_base85_init
0, is_base85, 0, 0);
if( rc!=SQLITE_OK ) return rc;
}
#endif
# endif
return sqlite3_create_function
(db, "base85", 1,
SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8,
@@ -432,9 +432,9 @@ int main(int na, char *av[]){
int nc = strlen(cBuf);
size_t nbo = fromBase85( cBuf, nc, bBuf ) - bBuf;
if( 1 != fwrite(bBuf, nbo, 1, fb) ) rc = 1;
#ifndef OMIT_BASE85_CHECKER
# ifndef OMIT_BASE85_CHECKER
b85Clean &= allBase85( cBuf, nc );
#endif
# endif
}
break;
default:
+152
View File
@@ -0,0 +1,152 @@
/*
** 2019-03-30
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** An SQL function that uses the incremental BLOB I/O mechanism of SQLite
** to read or write part of a blob. This is intended for debugging use
** in the CLI.
**
** readblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,N)
**
** Returns N bytes of the blob starting at OFFSET.
**
** writeblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,NEWDATA)
**
** NEWDATA must be a blob. The content of NEWDATA overwrites the
** existing BLOB data at SCHEMA.TABLE.COLUMN for row ROWID beginning
** at OFFSET bytes into the blob.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
static void readblobFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_blob *pBlob = 0;
const char *zSchema;
const char *zTable;
const char *zColumn;
sqlite3_int64 iRowid;
int iOfst;
unsigned char *aData;
int nData;
sqlite3 *db;
int rc;
zSchema = (const char*)sqlite3_value_text(argv[0]);
zTable = (const char*)sqlite3_value_text(argv[1]);
if( zTable==0 ){
sqlite3_result_error(context, "bad table name", -1);
return;
}
zColumn = (const char*)sqlite3_value_text(argv[2]);
if( zTable==0 ){
sqlite3_result_error(context, "bad column name", -1);
return;
}
iRowid = sqlite3_value_int64(argv[3]);
iOfst = sqlite3_value_int(argv[4]);
nData = sqlite3_value_int(argv[5]);
if( nData<=0 ) return;
aData = sqlite3_malloc64( nData+1 );
if( aData==0 ){
sqlite3_result_error_nomem(context);
return;
}
db = sqlite3_context_db_handle(context);
rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 0, &pBlob);
if( rc ){
sqlite3_free(aData);
sqlite3_result_error(context, "cannot open BLOB pointer", -1);
return;
}
rc = sqlite3_blob_read(pBlob, aData, nData, iOfst);
sqlite3_blob_close(pBlob);
if( rc ){
sqlite3_free(aData);
sqlite3_result_error(context, "BLOB read failed", -1);
}else{
sqlite3_result_blob(context, aData, nData, sqlite3_free);
}
}
static void writeblobFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_blob *pBlob = 0;
const char *zSchema;
const char *zTable;
const char *zColumn;
sqlite3_int64 iRowid;
int iOfst;
unsigned char *aData;
int nData;
sqlite3 *db;
int rc;
zSchema = (const char*)sqlite3_value_text(argv[0]);
zTable = (const char*)sqlite3_value_text(argv[1]);
if( zTable==0 ){
sqlite3_result_error(context, "bad table name", -1);
return;
}
zColumn = (const char*)sqlite3_value_text(argv[2]);
if( zTable==0 ){
sqlite3_result_error(context, "bad column name", -1);
return;
}
iRowid = sqlite3_value_int64(argv[3]);
iOfst = sqlite3_value_int(argv[4]);
if( sqlite3_value_type(argv[5])!=SQLITE_BLOB ){
sqlite3_result_error(context, "6th argument must be a BLOB", -1);
return;
}
nData = sqlite3_value_bytes(argv[5]);
aData = (unsigned char *)sqlite3_value_blob(argv[5]);
db = sqlite3_context_db_handle(context);
rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 1, &pBlob);
if( rc ){
sqlite3_result_error(context, "cannot open BLOB pointer", -1);
return;
}
rc = sqlite3_blob_write(pBlob, aData, nData, iOfst);
sqlite3_blob_close(pBlob);
if( rc ){
sqlite3_result_error(context, "BLOB write failed", -1);
}
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_blobio_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "readblob", 6, SQLITE_UTF8, 0,
readblobFunc, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "writeblob", 6, SQLITE_UTF8, 0,
writeblobFunc, 0, 0);
}
return rc;
}
+1 -17
View File
@@ -60,13 +60,6 @@
**
** SELECT name FROM sqlite_btreeinfo
** WHERE type='table' AND NOT hasRowid;
**
** UNUSED, UNTESTED, UNSUPPORTED
**
** This extension exists for information and demonstration purposes
** only. The developers are not aware of any real-world use of this
** extension. The extension has no formal test cases. The developers
** do not actively support it.
*/
#if !defined(SQLITEINT_H)
#include "sqlite3ext.h"
@@ -293,11 +286,6 @@ static int binfoCompute(sqlite3 *db, int pgno, BinfoCursor *pCsr){
pCsr->depth = 1;
while(1){
sqlite3_bind_int(pStmt, 1, pgno);
if( pCsr->depth>25 ){
sqlite3_set_errmsg(db, SQLITE_CORRUPT, "btree nested too deep");
rc = SQLITE_ERROR;
break;
}
rc = sqlite3_step(pStmt);
if( rc!=SQLITE_ROW ){
rc = SQLITE_ERROR;
@@ -318,10 +306,6 @@ static int binfoCompute(sqlite3 *db, int pgno, BinfoCursor *pCsr){
nEntry *= (nCell+1);
if( aData[0]==10 || aData[0]==13 ) break;
nPage *= (nCell+1);
if( 14+2*(nCell/2)>=pgsz ){
rc = SQLITE_CORRUPT;
break;
}
if( nCell<=1 ){
pgno = get_uint32(aData+8);
}else{
@@ -355,7 +339,7 @@ static int binfoColumn(
sqlite3 *db = sqlite3_context_db_handle(ctx);
int rc = binfoCompute(db, pgno, pCsr);
if( rc ){
pCursor->pVtab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc));
pCursor->pVtab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
return SQLITE_ERROR;
}
}
+3 -3
View File
@@ -516,7 +516,7 @@ static int closureConnect(
(void)pAux;
*ppVtab = 0;
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
rc = SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -579,7 +579,7 @@ closureConnectError:
static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
closure_vtab *p = (closure_vtab*)pVTab;
closure_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->pVtab = p;
@@ -638,7 +638,7 @@ static int closureInsertNode(
sqlite3_int64 id, /* The node ID */
int iGeneration /* The generation number for this node */
){
closure_avl *pNew = sqlite3_malloc64( sizeof(*pNew) );
closure_avl *pNew = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
pNew->id = id;
+15 -27
View File
@@ -132,7 +132,7 @@ static int completionConnect(
" phase INT HIDDEN" /* Used for debugging only */
")");
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -154,7 +154,7 @@ static int completionDisconnect(sqlite3_vtab *pVtab){
*/
static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
completion_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->db = ((completion_vtab*)p)->db;
@@ -199,7 +199,6 @@ static int completionNext(sqlite3_vtab_cursor *cur){
completion_cursor *pCur = (completion_cursor*)cur;
int eNextPhase = 0; /* Next phase to try if current phase reaches end */
int iCol = -1; /* If >=0, step pCur->pStmt and use the i-th column */
int rc;
pCur->iRowid++;
while( pCur->ePhase!=COMPLETION_EOF ){
switch( pCur->ePhase ){
@@ -225,27 +224,22 @@ static int completionNext(sqlite3_vtab_cursor *cur){
case COMPLETION_TABLES: {
if( pCur->pStmt==0 ){
sqlite3_stmt *pS2;
sqlite3_str* pStr = sqlite3_str_new(pCur->db);
char *zSql = 0;
const char *zSep = "";
sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
while( sqlite3_step(pS2)==SQLITE_ROW ){
const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
sqlite3_str_appendf(pStr,
"%s"
zSql = sqlite3_mprintf(
"%z%s"
"SELECT name FROM \"%w\".sqlite_schema",
zSep, zDb
zSql, zSep, zDb
);
if( zSql==0 ) return SQLITE_NOMEM;
zSep = " UNION ";
}
rc = sqlite3_finalize(pS2);
zSql = sqlite3_str_finish(pStr);
if( zSql==0 ) return SQLITE_NOMEM;
if( rc==SQLITE_OK ){
sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
}
sqlite3_finalize(pS2);
sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
sqlite3_free(zSql);
if( rc ) return rc;
}
iCol = 0;
eNextPhase = COMPLETION_COLUMNS;
@@ -254,29 +248,24 @@ static int completionNext(sqlite3_vtab_cursor *cur){
case COMPLETION_COLUMNS: {
if( pCur->pStmt==0 ){
sqlite3_stmt *pS2;
sqlite3_str *pStr = sqlite3_str_new(pCur->db);
char *zSql = 0;
const char *zSep = "";
sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
while( sqlite3_step(pS2)==SQLITE_ROW ){
const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
sqlite3_str_appendf(pStr,
"%s"
zSql = sqlite3_mprintf(
"%z%s"
"SELECT pti.name FROM \"%w\".sqlite_schema AS sm"
" JOIN pragma_table_xinfo(sm.name,%Q) AS pti"
" WHERE sm.type='table'",
zSep, zDb, zDb
zSql, zSep, zDb, zDb
);
if( zSql==0 ) return SQLITE_NOMEM;
zSep = " UNION ";
}
rc = sqlite3_finalize(pS2);
zSql = sqlite3_str_finish(pStr);
if( zSql==0 ) return SQLITE_NOMEM;
if( rc==SQLITE_OK ){
sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
}
sqlite3_finalize(pS2);
sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
sqlite3_free(zSql);
if( rc ) return rc;
}
iCol = 0;
eNextPhase = COMPLETION_EOF;
@@ -293,10 +282,9 @@ static int completionNext(sqlite3_vtab_cursor *cur){
pCur->szRow = sqlite3_column_bytes(pCur->pStmt, iCol);
}else{
/* When all rows are finished, advance to the next phase */
rc = sqlite3_finalize(pCur->pStmt);
sqlite3_finalize(pCur->pStmt);
pCur->pStmt = 0;
pCur->ePhase = eNextPhase;
if( rc ) return rc;
continue;
}
}
+2 -10
View File
@@ -59,11 +59,7 @@ static void compressFunc(
pIn = sqlite3_value_blob(argv[0]);
nIn = sqlite3_value_bytes(argv[0]);
nOut = 13 + nIn + (nIn+999)/1000;
pOut = sqlite3_malloc64( nOut+5 );
if( pOut==0 ){
sqlite3_result_error_nomem(context);
return;
}
pOut = sqlite3_malloc( nOut+5 );
for(i=4; i>=0; i--){
x[i] = (nIn >> (7*(4-i)))&0x7f;
}
@@ -102,11 +98,7 @@ static void uncompressFunc(
nOut = (nOut<<7) | (pIn[i]&0x7f);
if( (pIn[i]&0x80)!=0 ){ i++; break; }
}
pOut = sqlite3_malloc64( nOut+1 );
if( pOut==0 ){
sqlite3_result_error_nomem(context);
return;
}
pOut = sqlite3_malloc( nOut+1 );
rc = uncompress(pOut, &nOut, &pIn[i], nIn-i);
if( rc==Z_OK ){
sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
+16 -24
View File
@@ -24,8 +24,8 @@
** schema= parameter, like this:
**
** CREATE VIRTUAL TABLE temp.csv2 USING csv(
** filename = '../http.log',
** schema = 'CREATE TABLE x(date,ipaddr,url,referrer,userAgent)'
** filename = "../http.log",
** schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)"
** );
**
** Instead of specifying a file, the text of the CSV can be loaded using
@@ -62,10 +62,6 @@ SQLITE_EXTENSION_INIT1
# define CSV_NOINLINE
#endif
#ifndef SQLITEINT_H
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
#endif
/* Max size of the error message in a CsvReader */
#define CSV_MXERR 200
@@ -78,9 +74,9 @@ typedef struct CsvReader CsvReader;
struct CsvReader {
FILE *in; /* Read the CSV text from this input stream */
char *z; /* Accumulated text for a field */
i64 n; /* Number of bytes in z */
i64 nAlloc; /* Space allocated for z[] */
i64 nLine; /* Current line number */
int n; /* Number of bytes in z */
int nAlloc; /* Space allocated for z[] */
int nLine; /* Current line number */
int bNotFirst; /* True if prior text has been seen */
int cTerm; /* Character that terminated the most recent field */
size_t iIn; /* Next unread character in the input buffer */
@@ -129,7 +125,7 @@ static int csv_reader_open(
const char *zData /* ... or use this data */
){
if( zFilename ){
p->zIn = sqlite3_malloc64( CSV_INBUFSZ );
p->zIn = sqlite3_malloc( CSV_INBUFSZ );
if( p->zIn==0 ){
csv_errmsg(p, "out of memory");
return 1;
@@ -178,7 +174,7 @@ static int csv_getc(CsvReader *p){
** Return 0 on success and non-zero if there is an OOM error */
static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){
char *zNew;
i64 nNew = p->nAlloc*2 + 100;
int nNew = p->nAlloc*2 + 100;
zNew = sqlite3_realloc64(p->z, nNew);
if( zNew ){
p->z = zNew;
@@ -222,7 +218,7 @@ static char *csv_read_one_field(CsvReader *p){
}
if( c=='"' ){
int pc, ppc;
i64 startLine = p->nLine;
int startLine = p->nLine;
pc = ppc = 0;
while( 1 ){
c = csv_getc(p);
@@ -326,7 +322,7 @@ typedef struct CsvCursor {
sqlite3_vtab_cursor base; /* Base class. Must be first */
CsvReader rdr; /* The CsvReader object */
char **azVal; /* Value of the current row */
i64 *aLen; /* Length of each entry */
int *aLen; /* Length of each entry */
sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */
} CsvCursor;
@@ -498,7 +494,7 @@ static int csvtabConnect(
CsvTable *pNew = 0; /* The CsvTable object to construct */
int bHeader = -1; /* header= flags. -1 means not seen yet */
int rc = SQLITE_OK; /* Result code from this routine */
u64 i, j; /* Loop counters */
int i, j; /* Loop counters */
#ifdef SQLITE_TEST
int tstFlags = 0; /* Value for testflags=N parameter */
#endif
@@ -514,10 +510,11 @@ static int csvtabConnect(
# define CSV_DATA (azPValue[1])
# define CSV_SCHEMA (azPValue[2])
assert( sizeof(azPValue)==sizeof(azParam) );
memset(&sRdr, 0, sizeof(sRdr));
memset(azPValue, 0, sizeof(azPValue));
for(i=3; i<(u64)argc; i++){
for(i=3; i<argc; i++){
const char *z = argv[i];
const char *zValue;
for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){
@@ -547,10 +544,6 @@ static int csvtabConnect(
if( nCol<=0 ){
csv_errmsg(&sRdr, "column= value must be positive");
goto csvtab_connect_error;
}else if( nCol>sqlite3_limit(db,SQLITE_LIMIT_COLUMN,-1) ){
csv_errmsg(&sRdr, "column= value too big, max %d",
sqlite3_limit(db, SQLITE_LIMIT_COLUMN,-1));
goto csvtab_connect_error;
}
}else
{
@@ -568,7 +561,7 @@ static int csvtabConnect(
){
goto csvtab_connect_error;
}
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) goto csvtab_connect_oom;
memset(pNew, 0, sizeof(*pNew));
@@ -713,14 +706,13 @@ static int csvtabClose(sqlite3_vtab_cursor *cur){
static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
CsvTable *pTab = (CsvTable*)p;
CsvCursor *pCur;
sqlite3_int64 nByte = pTab->nCol;
assert( pTab->nCol<32768 );
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(i64))*nByte;
size_t nByte;
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol;
pCur = sqlite3_malloc64( nByte );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, nByte);
pCur->azVal = (char**)&pCur[1];
pCur->aLen = (i64*)&pCur->azVal[pTab->nCol];
pCur->aLen = (int*)&pCur->azVal[pTab->nCol];
*ppCursor = &pCur->base;
if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){
csv_xfer_error(pTab, &pCur->rdr);
+16 -75
View File
@@ -31,10 +31,6 @@ SQLITE_EXTENSION_INIT1
#define IsSpace(X) isspace((unsigned char)X)
#endif
#ifndef SQLITE_DECIMAL_MAX_DIGIT
# define SQLITE_DECIMAL_MAX_DIGIT 10000000
#endif
/* A decimal object */
typedef struct Decimal Decimal;
struct Decimal {
@@ -73,8 +69,7 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
int i;
int iExp = 0;
if( zIn==0 ) goto new_from_text_failed;
p = sqlite3_malloc64( sizeof(*p) );
p = sqlite3_malloc( sizeof(*p) );
if( p==0 ) goto new_from_text_failed;
p->sign = 0;
p->oom = 0;
@@ -133,10 +128,9 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
}
}
if( iExp>0 ){
signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit
p->a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit
+ (sqlite3_int64)iExp + 1 );
if( a==0 ) goto new_from_text_failed;
p->a = a;
if( p->a==0 ) goto new_from_text_failed;
memset(p->a+p->nDigit, 0, iExp);
p->nDigit += iExp;
}
@@ -154,10 +148,9 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
}
}
if( iExp>0 ){
signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit
p->a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit
+ (sqlite3_int64)iExp + 1 );
if( a==0 ) goto new_from_text_failed;
p->a = a;
if( p->a==0 ) goto new_from_text_failed;
memmove(p->a+iExp, p->a, p->nDigit);
memset(p->a, 0, iExp);
p->nDigit += iExp;
@@ -168,7 +161,6 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
for(i=0; i<p->nDigit && p->a[i]==0; i++){}
if( i>=p->nDigit ) p->sign = 0;
}
if( p->nDigit>SQLITE_DECIMAL_MAX_DIGIT ) goto new_from_text_failed;
return p;
new_from_text_failed:
@@ -261,7 +253,7 @@ static void decimal_result(sqlite3_context *pCtx, Decimal *p){
sqlite3_result_null(pCtx);
return;
}
z = sqlite3_malloc64( (sqlite3_int64)p->nDigit+8 );
z = sqlite3_malloc64( (sqlite3_int64)p->nDigit+4 );
if( z==0 ){
sqlite3_result_error_nomem(pCtx);
return;
@@ -299,47 +291,12 @@ static void decimal_result(sqlite3_context *pCtx, Decimal *p){
sqlite3_result_text(pCtx, z, i, sqlite3_free);
}
/* Forward declaration */
static void decimal_expand(Decimal *p, int nDigit, int nFrac);
/*
** Round a decimal value to N significant digits. N must be positive.
*/
static void decimal_round(Decimal *p, int N){
int i;
int nZero; /* Number of leading zeros */
if( N<1 ) return;
if( p==0 ) return;
if( p->nDigit<=N ) return;
for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){}
N += nZero;
if( p->nDigit<=N ) return;
if( p->a[N]>=5 ){
/* If all leading digits are 9, increase the number of digits
** by adding a new 0 to the front */
for(i=0; i<N && p->a[i]==9; i++){}
if( i==N ){
decimal_expand(p, p->nDigit+1, 0);
if( p->oom ) return;
}
/* Do the rounding */
p->a[N-1]++;
for(i=N-1; i>0 && p->a[i]>9; i--){
p->a[i] = 0;
p->a[i-1]++;
}
assert( p->a[0]<=9 );
}
memset(&p->a[N], 0, p->nDigit - N);
}
/*
** Make the given Decimal the result in an format similar to '%+#e'.
** In other words, show exponential notation with leading and trailing
** zeros omitted.
*/
static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){
static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p){
char *z; /* The output buffer */
int i; /* Loop counter */
int nZero; /* Number of leading zeros */
@@ -357,8 +314,7 @@ static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){
sqlite3_result_null(pCtx);
return;
}
if( N<1 ) N = 0;
for(nDigit=p->nDigit; nDigit>N && p->a[nDigit-1]==0; nDigit--){}
for(nDigit=p->nDigit; nDigit>0 && p->a[nDigit-1]==0; nDigit--){}
for(nZero=0; nZero<nDigit && p->a[nZero]==0; nZero++){}
nFrac = p->nFrac + (nDigit - p->nDigit);
nDigit -= nZero;
@@ -474,18 +430,15 @@ cmp_done:
static void decimal_expand(Decimal *p, int nDigit, int nFrac){
int nAddSig;
int nAddFrac;
signed char *a;
if( p==0 ) return;
nAddFrac = nFrac - p->nFrac;
nAddSig = (nDigit - p->nDigit) - nAddFrac;
if( nAddFrac==0 && nAddSig==0 ) return;
if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; }
a = sqlite3_realloc64(p->a, nDigit+1);
if( a==0 ){
p->a = sqlite3_realloc64(p->a, nDigit+1);
if( p->a==0 ){
p->oom = 1;
return;
}
p->a = a;
if( nAddSig ){
memmove(p->a+nAddSig, p->a, p->nDigit);
memset(p->a, 0, nAddSig);
@@ -580,18 +533,14 @@ static void decimalMul(Decimal *pA, Decimal *pB){
signed char *acc = 0;
int i, j, k;
int minFrac;
sqlite3_int64 sumDigit;
if( pA==0 || pA->oom || pA->isNull
|| pB==0 || pB->oom || pB->isNull
){
goto mul_end;
}
sumDigit = pA->nDigit;
sumDigit += pB->nDigit;
sumDigit += 2;
if( sumDigit>SQLITE_DECIMAL_MAX_DIGIT ){ pA->oom = 1; return; }
acc = sqlite3_malloc64( sumDigit );
acc = sqlite3_malloc64( (sqlite3_int64)pA->nDigit +
(sqlite3_int64)pB->nDigit + 2 );
if( acc==0 ){
pA->oom = 1;
goto mul_end;
@@ -728,16 +677,10 @@ static void decimalFunc(
sqlite3_value **argv
){
Decimal *p = decimal_new(context, argv[0], 0);
int N;
if( argc==2 ){
N = sqlite3_value_int(argv[1]);
if( N>0 ) decimal_round(p, N);
}else{
N = 0;
}
UNUSED_PARAMETER(argc);
if( p ){
if( sqlite3_user_data(context)!=0 ){
decimal_result_sci(context, p, N);
decimal_result_sci(context, p);
}else{
decimal_result(context, p);
}
@@ -823,7 +766,7 @@ static void decimalSumStep(
if( p==0 ) return;
if( !p->isInit ){
p->isInit = 1;
p->a = sqlite3_malloc64(2);
p->a = sqlite3_malloc(2);
if( p->a==0 ){
p->oom = 1;
}else{
@@ -907,7 +850,7 @@ static void decimalPow2Func(
UNUSED_PARAMETER(argc);
if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
Decimal *pA = decimalPow2(sqlite3_value_int(argv[0]));
decimal_result_sci(context, pA, 0);
decimal_result_sci(context, pA);
decimal_free(pA);
}
}
@@ -928,9 +871,7 @@ int sqlite3_decimal_init(
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aFunc[] = {
{ "decimal", 1, 0, decimalFunc },
{ "decimal", 2, 0, decimalFunc },
{ "decimal_exp", 1, 1, decimalFunc },
{ "decimal_exp", 2, 1, decimalFunc },
{ "decimal_cmp", 2, 0, decimalCmpFunc },
{ "decimal_add", 2, 0, decimalAddFunc },
{ "decimal_sub", 2, 0, decimalSubFunc },
-847
View File
@@ -1,847 +0,0 @@
/*
** 2026-04-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 extension implements an SQL function:
**
** diskused(X)
**
** Where X is the schema name (typically 'main'). The output is text
** that describes how much filesystem space the various tables and indexes
** of the database consume.
**
** This function is a replacement for the (now deprecated)
** "sqlite3_analyzer" utility program. This function is built
** into the CLI and is used to implement the ".diskused" command there.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
/*
** State information for the analysis
*/
typedef struct DiskUsed DiskUsed;
struct DiskUsed {
sqlite3 *db; /* Database connection */
sqlite3_context *context; /* SQL function context */
sqlite3_str *pOut; /* Write output here */
char *zSU; /* Name of the temp.space_used table */
const char *zSchema; /* Schema to be analyzed */
};
/*
** Free all resources that the DiskUsed object references and
** reset the DiskUsed object.
**
** Call this routine multiple times on the same DiskUsed object
** is a harmless no-op, as long as the memory for the object itself
** has not been freed.
*/
static void diskusedReset(DiskUsed *p){
if( p->zSU ){
char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU);
if( zSql ){
sqlite3_exec(p->db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
}
sqlite3_str_free(p->pOut);
sqlite3_free(p->zSU);
memset(p, 0, sizeof(*p));
}
/*
** Report an error using formatted text. If zFormat==NULL then report
** an OOM error.
*/
static void diskusedError(DiskUsed *p, const char *zFormat, ...){
char *zErr;
if( zFormat ){
va_list ap;
va_start(ap, zFormat);
zErr = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
}else{
zErr = 0;
}
if( zErr==0 ){
sqlite3_result_error_nomem(p->context);
}else{
sqlite3_result_error(p->context, zErr, -1);
sqlite3_free(zErr);
}
diskusedReset(p);
}
/*
** Prepare and return an SQL statement.
*/
static sqlite3_stmt *diskusedVPrep(DiskUsed *p, const char *zFmt, va_list ap){
char *zSql;
int rc;
sqlite3_stmt *pStmt = 0;
zSql = sqlite3_vmprintf(zFmt, ap);
if( zSql==0 ){ diskusedError(p,0); return 0; }
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
if( rc ){
diskusedError(p, "SQL parse error: %s\nOriginal SQL: %s",
sqlite3_errmsg(p->db), zSql);
sqlite3_finalize(pStmt);
diskusedReset(p);
pStmt = 0;
}
sqlite3_free(zSql);
return pStmt;
}
static sqlite3_stmt *diskusedPrepare(DiskUsed *p, const char *zFormat, ...){
va_list ap;
sqlite3_stmt *pStmt = 0;
va_start(ap, zFormat);
pStmt = diskusedVPrep(p,zFormat,ap);
va_end(ap);
return pStmt;
}
/*
** If rc is something other than SQLITE_DONE or SQLITE_OK, then report
** an error and return true.
**
** If rc is SQLITE_DONE or SQLITE_OK, then return false.
**
** The prepared statement is closed in either case.
*/
static int diskusedStmtFinish(DiskUsed *p, int rc, sqlite3_stmt *pStmt){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}
if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){
diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s",
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
diskusedReset(p);
}
sqlite3_finalize(pStmt);
return rc;
}
/*
** Run SQL. Return the number of errors.
*/
static int diskusedSql(DiskUsed *p, const char *zFormat, ...){
va_list ap;
int rc;
sqlite3_stmt *pStmt = 0;
va_start(ap, zFormat);
pStmt = diskusedVPrep(p,zFormat,ap);
va_end(ap);
if( pStmt==0 ) return 1;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){}
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}else{
diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s",
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
diskusedReset(p);
}
sqlite3_finalize(pStmt);
return rc;
}
/*
** Run an SQL query that returns an integer. Write that integer
** into *piRes. Return the number of errors.
*/
static int diskusedSqlInt(
DiskUsed *p,
sqlite3_int64 *piRes,
const char *zFormat, ...
){
va_list ap;
int rc;
sqlite3_stmt *pStmt = 0;
va_start(ap, zFormat);
pStmt = diskusedVPrep(p,zFormat,ap);
va_end(ap);
if( pStmt==0 ) return 1;
rc = sqlite3_step(pStmt);
if( rc==SQLITE_ROW ){
*piRes = sqlite3_column_int64(pStmt, 0);
rc = SQLITE_OK;
}else if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}else{
if( p->db ){
/* p->db is NULL if there was some prior error */
diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s",
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
}
diskusedReset(p);
}
sqlite3_finalize(pStmt);
return rc;
}
/*
** Add to the output a title line that contains the text determined
** by the format string. If the output is initially empty, begin
** the title line with "/" so that it forms the beginning of a C-style
** comment. Otherwise begin with a new-line. Always finish with a
** newline.
*/
static void diskusedTitle(DiskUsed *p, const char *zFormat, ...){
char *zFirst;
char *zTitle;
size_t nTitle;
va_list ap;
va_start(ap, zFormat);
zTitle = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
if( zTitle==0 ){
diskusedError(p, 0);
return;
}
zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*";
nTitle = strlen(zTitle);
if( nTitle>=75 ){
sqlite3_str_appendf(p->pOut, "%s** %z\n\n", zFirst, zTitle);
}else{
int nExtra = 74 - (int)nTitle;
sqlite3_str_appendf(p->pOut, "%s** %z %.*c\n\n", zFirst, zTitle,
nExtra, '*');
}
}
/*
** Add an output line that begins with the zDesc text extended out to
** 50 columns with "." characters, and followed by whatever text is
** described by zFormat.
*/
static void diskusedLine(
DiskUsed *p, /* DiskUsed context */
const char *zDesc, /* Description */
const char *zFormat, /* Argument to the description */
...
){
char *zTxt;
size_t nDesc;
va_list ap;
va_start(ap, zFormat);
zTxt = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
if( zTxt==0 ){
diskusedError(p, 0);
return;
}
nDesc = zDesc ? strlen(zDesc) : 0;
if( nDesc>=50 ){
sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt);
}else{
int nExtra = 50 - (int)nDesc;
sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt);
}
}
/*
** Write a percentage into the output. The number written should show
** two or three significant digits, with the decimal point being the fourth
** character.
*/
static void diskusedPercent(DiskUsed *p, double r){
char zNum[100];
char *zDP;
int nLeadingDigit;
int sz;
sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r);
sz = (int)strlen(zNum);
zDP = strchr(zNum, '.');
if( zDP==0 ){
memcpy(zNum+sz,".0",3);
nLeadingDigit = sz;
sz += 2;
}else{
nLeadingDigit = (int)(zDP - zNum);
}
if( nLeadingDigit<3 ){
sqlite3_str_appendchar(p->pOut, 3-nLeadingDigit, ' ');
}
sqlite3_str_append(p->pOut, zNum, sz);
sqlite3_str_append(p->pOut, "%\n", 2);
}
/*
** Create a subreport on a subset of tables and/or indexes.
**
** The title if the subreport is given by zTitle. zWhere is
** a boolean expression that can go in the WHERE clause to select
** the relevant rows of the s.zSU table.
*/
static int diskusedSubreport(
DiskUsed *p, /* DiskUsed context */
char *zTitle, /* Title for this subreport */
char *zWhere, /* WHERE clause for this subreport */
sqlite3_int64 pgsz, /* Database page size */
sqlite3_int64 nPage /* Number of pages in entire database */
){
sqlite3_stmt *pStmt; /* Statement to query p->zSU */
sqlite3_int64 nentry; /* Number of btree entires */
sqlite3_int64 payload; /* Payload in bytes */
sqlite3_int64 ovfl_payload; /* overflow payload in bytes */
sqlite3_int64 mx_payload; /* largest individual payload */
sqlite3_int64 ovfl_cnt; /* Number entries using overflow */
sqlite3_int64 leaf_pages; /* Leaf pages */
sqlite3_int64 int_pages; /* internal pages */
sqlite3_int64 ovfl_pages; /* overflow pages */
sqlite3_int64 leaf_unused; /* unused bytes on leaf pages */
sqlite3_int64 int_unused; /* unused bytes on internal pages */
sqlite3_int64 ovfl_unused; /* unused bytes on overflow pages */
sqlite3_int64 int_cell; /* B-tree entries on internal pages */
sqlite3_int64 depth; /* btree depth */
sqlite3_int64 cnt; /* Number of s.zSU entries that match */
sqlite3_int64 storage; /* Total bytes */
sqlite3_int64 total_pages; /* Total page count */
sqlite3_int64 total_unused; /* Total unused bytes */
sqlite3_int64 total_meta; /* Total metadata */
int rc;
if( zTitle==0 || zWhere==0 ){
diskusedError(p, 0);
return SQLITE_NOMEM;
}
pStmt = diskusedPrepare(p,
"SELECT\n"
" sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */
" sum(payload),\n" /* 1 */
" sum(ovfl_payload),\n" /* 2 */
" max(mx_payload),\n" /* 3 */
" sum(ovfl_cnt),\n" /* 4 */
" sum(leaf_pages),\n" /* 5 */
" sum(int_pages),\n" /* 6 */
" sum(ovfl_pages),\n" /* 7 */
" sum(leaf_unused),\n" /* 8 */
" sum(int_unused),\n" /* 9 */
" sum(ovfl_unused),\n" /* 10 */
" max(depth),\n" /* 11 */
" count(*),\n" /* 12 */
" sum(int_entries)\n" /* 13 */
" FROM temp.%s WHERE %s",
p->zSU, zWhere);
if( pStmt==0 ) return 1;
rc = sqlite3_step(pStmt);
if( rc==SQLITE_ROW ){
diskusedTitle(p, "%s", zTitle);
nentry = sqlite3_column_int64(pStmt, 0);
payload = sqlite3_column_int64(pStmt, 1);
ovfl_payload = sqlite3_column_int64(pStmt, 2);
mx_payload = sqlite3_column_int64(pStmt, 3);
ovfl_cnt = sqlite3_column_int64(pStmt, 4);
leaf_pages = sqlite3_column_int64(pStmt, 5);
int_pages = sqlite3_column_int64(pStmt, 6);
ovfl_pages = sqlite3_column_int64(pStmt, 7);
leaf_unused = sqlite3_column_int64(pStmt, 8);
int_unused = sqlite3_column_int64(pStmt, 9);
ovfl_unused = sqlite3_column_int64(pStmt, 10);
depth = sqlite3_column_int64(pStmt, 11);
cnt = sqlite3_column_int64(pStmt, 12);
int_cell = sqlite3_column_int64(pStmt, 13);
rc = SQLITE_DONE;
total_pages = leaf_pages + int_pages + ovfl_pages;
diskusedLine(p, "Percentage of total database", "%.3g%%\n",
(total_pages*100.0)/(double)nPage);
diskusedLine(p, "Number of entries", "%lld\n", nentry);
storage = total_pages*pgsz;
diskusedLine(p, "Bytes of storage consumed", "%lld\n", storage);
diskusedLine(p, "Bytes of payload", "%-11lld ", payload);
diskusedPercent(p, payload*100.0/(double)storage);
if( ovfl_cnt>0 ){
diskusedLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload);
diskusedPercent(p, ovfl_payload*100.0/(double)payload);
}
total_unused = leaf_unused + int_unused + ovfl_unused;
total_meta = storage - payload - total_unused;
diskusedLine(p, "Bytes of metadata","%-11lld ", total_meta);
diskusedPercent(p, total_meta*100.0/(double)storage);
if( cnt==1 ){
diskusedLine(p, "B-tree depth", "%lld\n", depth);
if( int_cell>1 ){
diskusedLine(p, "Average fanout", "%.1f\n",
(double)(int_cell+int_pages)/(double)int_pages);
}
}
if( nentry>0 ){
diskusedLine(p, "Average payload per entry", "%.1f\n",
(double)payload/(double)nentry);
diskusedLine(p, "Average unused bytes per entry", "%.1f\n",
(double)total_unused/(double)nentry);
diskusedLine(p, "Average metadata per entry", "%.1f\n",
(double)total_meta/(double)nentry);
}
diskusedLine(p, "Maximum single-entry payload", "%lld\n", mx_payload);
if( nentry>0 ){
diskusedLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt);
diskusedPercent(p, ovfl_cnt*100.0/(double)nentry);
}
if( int_pages>0 ){
diskusedLine(p, "Index pages used", "%lld\n", int_pages);
}
diskusedLine(p, "Primary pages used", "%lld\n", leaf_pages);
if( ovfl_cnt ){
diskusedLine(p, "Overflow pages used", "%lld\n", ovfl_pages);
}
diskusedLine(p, "Total pages used", "%lld\n", total_pages);
if( int_pages>0 ){
diskusedLine(p, "Unused bytes on index pages", "%lld\n", int_unused);
}
diskusedLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused);
if( ovfl_cnt ){
diskusedLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused);
}
diskusedLine(p, "Unused bytes on all pages", "%-11lld ", total_unused);
diskusedPercent(p, total_unused*100.0/(double)storage);
}
return diskusedStmtFinish(p, rc, pStmt);
}
/*
** SQL Function: diskused(SCHEMA)
**
** Analyze the database schema named in the argument. Return text
** containing the space utilization stats.
*/
static void diskusedFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int rc;
sqlite3_stmt *pStmt;
int n;
sqlite3_int64 ii;
sqlite3_int64 pgsz;
sqlite3_int64 nPage;
sqlite3_int64 nPageInUse;
sqlite3_int64 nFreeList;
sqlite3_int64 nIndex;
sqlite3_int64 nWORowid;
DiskUsed s;
sqlite3_uint64 r[2];
(void)argc;
memset(&s, 0, sizeof(s));
s.db = sqlite3_context_db_handle(context);
s.context = context;
s.pOut = sqlite3_str_new(0);
if( sqlite3_str_errcode(s.pOut) ){
diskusedError(&s, 0);
return;
}
s.zSchema = (const char*)sqlite3_value_text(argv[0]);
if( s.zSchema==0 ){
s.zSchema = "main";
}else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){
diskusedReset(&s);
sqlite3_result_text(context, "cannot analyze \"temp\"",-1,SQLITE_STATIC);
return;
}
ii = 0;
rc = diskusedSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list"
" WHERE name=%Q COLLATE nocase",s.zSchema);
if( rc || ii==0 ){
diskusedReset(&s);
sqlite3_result_text(context,"no such database",-1,SQLITE_STATIC);
return;
}
sqlite3_randomness(sizeof(r), &r);
s.zSU = sqlite3_mprintf("diskused%016llx%016llx", r[0], r[1]);
if( s.zSU==0 ){ diskusedError(&s, 0); return; }
/* The s.zSU table contains the data used for the analysis.
** The table name contains 128-bits of randomness to avoid
** collisions with preexisting tables in temp.
*/
rc = diskusedSql(&s,
"CREATE TABLE temp.%s(\n"
" name text, -- A table or index\n"
" tblname text, -- Table that owns name\n"
" is_index boolean, -- TRUE if it is an index\n"
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n"
" nentry int, -- Number of entries in the BTree\n"
" leaf_entries int, -- Number of leaf entries\n"
" depth int, -- Depth of the b-tree\n"
" payload int, -- Total data stored in this table/index\n"
" ovfl_payload int, -- Total data stored on overflow pages\n"
" ovfl_cnt int, -- Number of entries that use overflow\n"
" mx_payload int, -- Maximum payload size\n"
" int_pages int, -- Interior pages used\n"
" leaf_pages int, -- Leaf pages used\n"
" ovfl_pages int, -- Overflow pages used\n"
" int_unused int, -- Unused bytes on interior pages\n"
" leaf_unused int, -- Unused bytes on primary pages\n"
" ovfl_unused int, -- Unused bytes on overflow pages\n"
" int_entries int -- Btree cells on internal pages\n"
");",
s.zSU
);
if( rc ) return;
/* Populate the s.zSU table
*/
rc = diskusedSql(&s,
"WITH\n"
" allidx(idxname) AS (\n"
" SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n"
" ),\n"
" allobj(allname,tblname,isidx,isworowid) AS (\n"
" SELECT 'sqlite_schema',\n"
" 'sqlite_schema',\n"
" 0,\n"
" 0\n"
" UNION ALL\n"
" SELECT name,\n"
" tbl_name,\n"
" type='index',\n"
" EXISTS(SELECT 1\n"
" FROM pragma_index_list(sqlite_schema.name,%Q)\n"
" WHERE pragma_index_list.origin='pk'\n"
" AND pragma_index_list.name NOT IN allidx)\n"
" FROM \"%w\".sqlite_schema\n"
" )\n"
"INSERT INTO temp.%s\n"
" SELECT\n"
" allname,\n"
" tblname,\n"
" isidx,\n"
" isworowid,\n"
" sum(ncell),\n"
" sum((pagetype='leaf')*ncell),\n"
" max((length(if(path GLOB '*+*','',path))+3)/4),\n"
" sum(payload),\n"
" sum((pagetype='overflow')*payload),\n"
" sum(path GLOB '*+000000'),\n"
" max(mx_payload),\n"
" sum(pagetype='internal'),\n"
" sum(pagetype='leaf'),\n"
" sum(pagetype='overflow'),\n"
" sum((pagetype='internal')*unused),\n"
" sum((pagetype='leaf')*unused),\n"
" sum((pagetype='overflow')*unused),\n"
" sum(if(pagetype='internal',ncell))\n"
" FROM allobj CROSS JOIN dbstat(%Q) \n"
" WHERE dbstat.name=allobj.allname\n"
" GROUP BY allname;\n",
s.zSchema, /* %w.sqlite_schema -- in allidx */
s.zSchema, /* pragma_index_list(...,%Q) */
s.zSchema, /* %w.sqlite_schema */
s.zSU, /* INTO temp.%s */
s.zSchema /* JOIN dbstat(%Q) */
);
if( rc ) return;
nPage = 0;
rc = diskusedSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema);
if( rc ) return;
if( nPage<=0 ){
/* Very brief reply for an empty database */
diskusedReset(&s);
sqlite3_result_text(context, "empty database", -1, SQLITE_STATIC);
return;
}
/* Begin generating the report */
diskusedTitle(&s, "Database storage utilization report");
pgsz = 0;
rc = diskusedSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema);
if( rc ) return;
diskusedLine(&s, "Page size in bytes","%lld\n",pgsz);
diskusedLine(&s, "Pages in the database", "%lld\n", nPage);
nPageInUse = 0;
rc = diskusedSqlInt(&s, &nPageInUse,
"SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU);
if( rc ) return;
diskusedLine(&s, "Pages that store data", "%-11lld ", nPageInUse);
diskusedPercent(&s, (nPageInUse*100.0)/(double)nPage);
nFreeList = 0;
rc = diskusedSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema);
if( rc ) return;
diskusedLine(&s, "Pages on the freelist", "%-11lld ", nFreeList);
diskusedPercent(&s, (nFreeList*100.0)/(double)nPage);
ii = 0;
rc = diskusedSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema);
if( rc ) return;
if( ii==0 || nPage<=1 ){
ii = 0;
}else{
double rPtrsPerPage = pgsz/5;
double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0);
ii = (sqlite3_int64)ceil(rAvPage);
}
diskusedLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii);
diskusedPercent(&s, (ii*100.0)/(double)nPage);
ii = 0;
rc = diskusedSqlInt(&s, &ii,
"SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'",
s.zSchema);
if( rc ) return;
diskusedLine(&s, "Number of tables", "%lld\n", ii);
nWORowid = 0;
rc = diskusedSqlInt(&s, &nWORowid,
"SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr",
s.zSchema);
if( rc ) return;
if( nWORowid>0 ){
diskusedLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid);
diskusedLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid);
}
nIndex = 0;
rc = diskusedSqlInt(&s, &nIndex,
"SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'",
s.zSchema);
if( rc ) return;
diskusedLine(&s, "Number of indexes", "%lld\n", nIndex);
ii = 0;
rc = diskusedSqlInt(&s, &ii,
"SELECT count(*) FROM \"%w\".sqlite_schema"
" WHERE name GLOB 'sqlite_autoindex_*' AND type='index'",
s.zSchema);
if( rc ) return;
diskusedLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii);
diskusedLine(&s, "Number of implied indexes", "%lld\n", ii);
diskusedLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage);
ii = 0;
rc = diskusedSqlInt(&s, &ii,
"SELECT sum(payload) FROM temp.%s"
" WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'",
s.zSU);
if( rc ) return;
diskusedLine(&s, "Bytes of payload", "%-11lld ", ii);
diskusedPercent(&s, ii*100.0/(double)(pgsz*nPage));
diskusedTitle(&s, "Page counts for all tables with their indexes");
pStmt = diskusedPrepare(&s,
"SELECT upper(tblname),\n"
" sum(int_pages+leaf_pages+ovfl_pages)\n"
" FROM temp.%s\n"
" WHERE tblname IS NOT NULL\n"
" GROUP BY 1\n"
" ORDER BY 2 DESC, 1;",
s.zSU);
if( pStmt==0 ) return;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
sqlite3_int64 nn = sqlite3_column_int64(pStmt,1);
diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn);
diskusedPercent(&s, (nn*100.0)/(double)nPage);
}
if( diskusedStmtFinish(&s, rc, pStmt) ) return;
diskusedTitle(&s, "Page counts for all tables and indexes separately");
pStmt = diskusedPrepare(&s,
"SELECT upper(name),\n"
" sum(int_pages+leaf_pages+ovfl_pages)\n"
" FROM temp.%s\n"
" WHERE name IS NOT NULL\n"
" GROUP BY 1\n"
" ORDER BY 2 DESC, 1;",
s.zSU);
if( pStmt==0 ) return;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
sqlite3_int64 nn = sqlite3_column_int64(pStmt,1);
diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn);
diskusedPercent(&s, (nn*100.0)/(double)nPage);
}
if( diskusedStmtFinish(&s, rc, pStmt) ) return;
rc = diskusedSubreport(&s, "All tables and indexes", "1", pgsz, nPage);
if( rc ) return;
rc = diskusedSubreport(&s, "All tables", "NOT is_index", pgsz, nPage);
if( rc ) return;
if( nWORowid>0 ){
rc = diskusedSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid",
pgsz, nPage);
if( rc ) return;
rc = diskusedSubreport(&s, "All rowid tables",
"NOT is_without_rowid AND NOT is_index",
pgsz, nPage);
if( rc ) return;
}
rc = diskusedSubreport(&s, "All indexes", "is_index", pgsz, nPage);
if( rc ) return;
pStmt = diskusedPrepare(&s,
"SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s"
" GROUP BY 1 ORDER BY 1",
s.zSU);
if( pStmt==0 ) return;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
const char *zUpper = (const char*)sqlite3_column_text(pStmt, 0);
const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
int nSubIndex = sqlite3_column_int(pStmt, 2);
if( nSubIndex==0 ){
char *zTitle = sqlite3_mprintf("Table %s", zUpper);
char *zWhere = sqlite3_mprintf("name=%Q", zName);
rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
}else{
sqlite3_stmt *pS2;
char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper);
char *zWhere = sqlite3_mprintf("tblname=%Q", zName);
rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper);
zWhere = sqlite3_mprintf("name=%Q", zName);
rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
if( nSubIndex>1 ){
zTitle = sqlite3_mprintf("All indexes of table %s", zUpper);
zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName);
rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
}
pS2 = diskusedPrepare(&s,
"SELECT name, upper(name) FROM temp.%s"
" WHERE is_index AND tblname=%Q",
s.zSU, zName);
if( pS2==0 ){
rc = SQLITE_NOMEM;
break;
}
while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){
const char *zU = (const char*)sqlite3_column_text(pS2, 1);
const char *zN = (const char*)sqlite3_column_text(pS2, 0);
zTitle = sqlite3_mprintf("Index %s", zU);
zWhere = sqlite3_mprintf("name=%Q", zN);
rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
}
rc = diskusedStmtFinish(&s, rc, pS2);
if( rc ) break;
}
}
if( diskusedStmtFinish(&s, rc, pStmt) ) return;
/* Append SQL statements that will recreate the raw data used for
** the analysis.
*/
diskusedTitle(&s, "Raw data used to generate this report");
sqlite3_str_appendf(s.pOut,
"The following SQL will create a table named \"space_used\" which\n"
"contains most of the information used to generate the report above.\n"
"*/\n"
);
sqlite3_str_appendf(s.pOut,
"BEGIN;\n"
"CREATE TABLE space_used(\n"
" name text, -- A table or index\n" /* 0 */
" tblname text, -- Table that owns name\n" /* 1 */
" is_index boolean, -- TRUE if it is an index\n" /* 2 */
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" /* 3 */
" nentry int, -- Number of entries in the BTree\n" /* 4 */
" leaf_entries int, -- Number of leaf entries\n" /* 5 */
" depth int, -- Depth of the b-tree\n" /* 6 */
" payload int, -- Total data in this table/index\n" /* 7 */
" ovfl_payload int, -- Total data on overflow pages\n" /* 8 */
" ovfl_cnt int, -- Entries that use overflow\n" /* 9 */
" mx_payload int, -- Maximum payload size\n" /* 10 */
" int_pages int, -- Interior pages used\n" /* 11 */
" leaf_pages int, -- Leaf pages used\n" /* 12 */
" ovfl_pages int, -- Overflow pages used\n" /* 13 */
" int_unused int, -- Unused bytes on interior pages\n" /* 14 */
" leaf_unused int, -- Unused bytes on primary pages\n" /* 15 */
" ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */
" int_entries int -- B-tree entries on internal pages\n"/* 17 */
");\n"
"INSERT INTO space_used VALUES\n"
);
pStmt = diskusedPrepare(&s,
"SELECT quote(name), quote(tblname),\n" /* 0..1 */
" is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */
" depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */
" int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */
" leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */
" FROM temp.%s;",
s.zSU);
if( pStmt==0 ) return;
n = 0;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
if( n++ ) sqlite3_str_appendf(s.pOut,",\n");
sqlite3_str_appendf(s.pOut,
" (%s,%s,%lld,%lld,%lld,%lld,%lld,%lld,%lld,"
"%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld)",
sqlite3_column_text(pStmt, 0),
sqlite3_column_text(pStmt, 1),
sqlite3_column_int64(pStmt, 2),
sqlite3_column_int64(pStmt, 3),
sqlite3_column_int64(pStmt, 4),
sqlite3_column_int64(pStmt, 5),
sqlite3_column_int64(pStmt, 6),
sqlite3_column_int64(pStmt, 7),
sqlite3_column_int64(pStmt, 8),
sqlite3_column_int64(pStmt, 9),
sqlite3_column_int64(pStmt, 10),
sqlite3_column_int64(pStmt, 11),
sqlite3_column_int64(pStmt, 12),
sqlite3_column_int64(pStmt, 13),
sqlite3_column_int64(pStmt, 14),
sqlite3_column_int64(pStmt, 15),
sqlite3_column_int64(pStmt, 16),
sqlite3_column_int64(pStmt, 17));
}
if( rc!=SQLITE_DONE ){
diskusedError(&s, "SQL run-time error: %s\nSQL: %s",
sqlite3_errmsg(s.db), sqlite3_sql(pStmt));
sqlite3_finalize(pStmt);
return;
}
sqlite3_str_appendf(s.pOut,";\nCOMMIT;");
sqlite3_finalize(pStmt);
if( sqlite3_str_length(s.pOut) ){
sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1,
sqlite3_free);
s.pOut = 0;
}
diskusedReset(&s);
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_diskused_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "diskused", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS,
0, diskusedFunc, 0, 0);
return rc;
}
+2 -2
View File
@@ -92,7 +92,7 @@ static int explainConnect(
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(addr,opcode,p1,p2,p3,p4,p5,comment,sql HIDDEN)");
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -114,7 +114,7 @@ static int explainDisconnect(sqlite3_vtab *pVtab){
*/
static int explainOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
explain_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->db = ((explain_vtab*)p)->db;
+68 -235
View File
@@ -73,6 +73,11 @@
** $path is a relative path, then $path is interpreted relative to $dir.
** And the paths returned in the "name" column of the table are also
** relative to directory $dir.
**
** Notes on building this extension for Windows:
** Unless linked statically with the SQLite library, a preprocessor
** symbol, FILEIO_WIN32_DLL, must be #define'd to create a stand-alone
** DLL form of this extension for WIN32. See its use below for details.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
@@ -89,8 +94,6 @@ SQLITE_EXTENSION_INIT1
# include <utime.h>
# include <sys/time.h>
# define STRUCT_STAT struct stat
# include <limits.h>
# include <stdlib.h>
#else
# include "windirent.h"
# include <direct.h>
@@ -123,70 +126,17 @@ SQLITE_EXTENSION_INIT1
#define FSDIR_COLUMN_PATH 5 /* Path to top of search */
#define FSDIR_COLUMN_DIR 6 /* Path is relative to this directory */
#ifdef _WIN32
/*
** Convert a UTF-8 string to Microsoft Unicode.
**
** Space to hold the returned string is obtained from sqlite3_malloc().
*/
static wchar_t *winUtf8To16(const char *zText){
int nChar;
wchar_t *zWideText;
nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
if( nChar==0 ){
return 0;
}
zWideText = sqlite3_malloc64(nChar*sizeof(WCHAR) );
if( zWideText==0 ){
return 0;
}
nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText,
nChar);
if( nChar==0 ){
sqlite3_free(zWideText);
zWideText = 0;
}
return zWideText;
}
#endif /* _WIN32 */
#ifdef _WIN32
/*
** Convert a Microsoft Unicode string to UTF-8.
**
** Space to hold the returned string is obtained from sqlite3_malloc().
*/
static char *winUtf16To8(wchar_t *zWideText){
int nByte;
char *zText;
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
if( nByte == 0 ){
return 0;
}
zText = sqlite3_malloc64( nByte );
if( zText==0 ){
return 0;
}
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte,
0, 0);
if( nByte == 0 ){
sqlite3_free(zText);
zText = 0;
}
return zText;
}
#endif /* _WIN32 */
/*
** UTF8 chmod() function for Windows
*/
#if defined(_WIN32) || defined(WIN32)
static int fileio_chmod(const char *zPath, int pmode){
sqlite3_int64 sz = strlen(zPath);
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
int rc;
wchar_t *b1 = winUtf8To16(zPath);
if( b1==0 ) return -1;
sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
b1[sz] = 0;
rc = _wchmod(b1, pmode);
sqlite3_free(b1);
return rc;
@@ -198,9 +148,12 @@ static int fileio_chmod(const char *zPath, int pmode){
*/
#if defined(_WIN32) || defined(WIN32)
static int fileio_mkdir(const char *zPath){
sqlite3_int64 sz = strlen(zPath);
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
int rc;
wchar_t *b1 = winUtf8To16(zPath);
if( b1==0 ) return -1;
sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
b1[sz] = 0;
rc = _wmkdir(b1);
sqlite3_free(b1);
return rc;
@@ -313,7 +266,50 @@ static sqlite3_uint64 fileTimeToUnixTime(
return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000;
}
#endif /* _WIN32 */
#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
# /* To allow a standalone DLL, use this next replacement function: */
# undef sqlite3_win32_utf8_to_unicode
# define sqlite3_win32_utf8_to_unicode utf8_to_utf16
#
LPWSTR utf8_to_utf16(const char *z){
int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0);
LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR));
if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) )
return rv;
sqlite3_free(rv);
return 0;
}
#endif
/*
** This function attempts to normalize the time values found in the stat()
** buffer to UTC. This is necessary on Win32, where the runtime library
** appears to return these values as local times.
*/
static void statTimesToUtc(
const char *zPath,
STRUCT_STAT *pStatBuf
){
HANDLE hFindFile;
WIN32_FIND_DATAW fd;
LPWSTR zUnicodeName;
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath);
if( zUnicodeName ){
memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
hFindFile = FindFirstFileW(zUnicodeName, &fd);
if( hFindFile!=NULL ){
pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime);
pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime);
FindClose(hFindFile);
}
sqlite3_free(zUnicodeName);
}
}
#endif
/*
** This function is used in place of stat(). On Windows, special handling
@@ -325,23 +321,14 @@ static int fileStat(
STRUCT_STAT *pStatBuf
){
#if defined(_WIN32)
sqlite3_int64 sz = strlen(zPath);
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
int rc;
wchar_t *b1 = winUtf8To16(zPath);
if( b1==0 ) return 1;
sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
b1[sz] = 0;
rc = _wstat(b1, pStatBuf);
if( rc==0 ){
HANDLE hFindFile;
WIN32_FIND_DATAW fd;
memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
hFindFile = FindFirstFileW(b1, &fd);
if( hFindFile!=NULL ){
pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime);
pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime);
FindClose(hFindFile);
}
}
sqlite3_free(b1);
if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
return rc;
#else
return stat(zPath, pStatBuf);
@@ -472,6 +459,7 @@ static int writeFile(
if( mtime>=0 ){
#if defined(_WIN32)
#if !SQLITE_OS_WINRT
/* Windows */
FILETIME lastAccess;
FILETIME lastWrite;
@@ -479,13 +467,14 @@ static int writeFile(
LONGLONG intervals;
HANDLE hFile;
LPWSTR zUnicodeName;
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
GetSystemTime(&currentTime);
SystemTimeToFileTime(&currentTime, &lastAccess);
intervals = (mtime*10000000) + 116444736000000000;
lastWrite.dwLowDateTime = (DWORD)intervals;
lastWrite.dwHighDateTime = intervals >> 32;
zUnicodeName = winUtf8To16(zFile);
zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
if( zUnicodeName==0 ){
return 1;
}
@@ -501,6 +490,7 @@ static int writeFile(
}else{
return 1;
}
#endif
#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
/* Recent unix */
struct timespec times[2];
@@ -666,7 +656,7 @@ static int fsdirConnect(
(void)pzErr;
rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
if( rc==SQLITE_OK ){
pNew = (fsdir_tab*)sqlite3_malloc64( sizeof(*pNew) );
pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
@@ -689,7 +679,7 @@ static int fsdirDisconnect(sqlite3_vtab *pVtab){
static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
fsdir_cursor *pCur;
(void)p;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->iLvl = -1;
@@ -1104,158 +1094,6 @@ static int fsdirRegister(sqlite3 *db){
# define fsdirRegister(x) SQLITE_OK
#endif
/*
** This version of realpath() works on any system. The string
** returned is held in memory allocated using sqlite3_malloc64().
** The caller is responsible for calling sqlite3_free().
*/
static char *portable_realpath(const char *zPath){
#if !defined(_WIN32) /* BEGIN unix */
char *zOut = 0; /* Result */
char *z; /* Temporary buffer */
#if defined(PATH_MAX)
char zBuf[PATH_MAX+1]; /* Space for the temporary buffer */
#endif
if( zPath==0 ) return 0;
#if defined(PATH_MAX)
z = realpath(zPath, zBuf);
if( z ){
zOut = sqlite3_mprintf("%s", zBuf);
}
#endif /* defined(PATH_MAX) */
if( zOut==0 ){
/* Try POSIX.1-2008 malloc behavior */
z = realpath(zPath, NULL);
if( z ){
zOut = sqlite3_mprintf("%s", z);
free(z);
}
}
return zOut;
#else /* End UNIX, Begin WINDOWS */
wchar_t *zPath16; /* UTF16 translation of zPath */
char *zOut = 0; /* Result */
wchar_t *z = 0; /* Temporary buffer */
if( zPath==0 ) return 0;
zPath16 = winUtf8To16(zPath);
if( zPath16==0 ) return 0;
z = _wfullpath(NULL, zPath16, 0);
sqlite3_free(zPath16);
if( z ){
zOut = winUtf16To8(z);
free(z);
}
return zOut;
#endif /* End WINDOWS, Begin common code */
}
/*
** SQL function: realpath(X)
**
** Try to convert file or pathname X into its real, absolute pathname.
** Return NULL if unable.
**
** The file or directory X is not required to exist. The answer is formed
** by calling system realpath() on the prefix of X that does exist and
** appending the tail of X that does not (yet) exist.
**
** FIXME: This routine sometimes returns NULL rather than raising
** an SQLITE_NOMEM error if an OOM is encountered.
*/
static void realpathFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zPath; /* Original input path */
char *zCopy; /* An editable copy of zPath */
char *zOut; /* The result */
char cSep = 0; /* Separator turned into \000 */
size_t len; /* Prefix length before cSep */
#ifdef _WIN32
const int isWin = 1;
#else
const int isWin = 0;
#endif
(void)argc;
zPath = (const char*)sqlite3_value_text(argv[0]);
if( zPath==0 ) return;
if( zPath[0]==0 ) zPath = ".";
zCopy = sqlite3_mprintf("%s",zPath);
if( zCopy==0 ) return;
len = strlen(zCopy);
while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){
len--;
}
zCopy[len] = 0;
while( 1 /*exit-by-break*/ ){
zOut = portable_realpath(zCopy);
zCopy[len] = cSep;
if( zOut ){
if( cSep ){
zOut = sqlite3_mprintf("%z%s",zOut,&zCopy[len]);
}
break;
}else{
size_t i = len-1;
while( i>0 ){
if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ) break;
i--;
}
if( i<=0 ){
if( zCopy[0]=='/' ){
zOut = zCopy;
zCopy = 0;
}else if( (zOut = portable_realpath("."))!=0 ){
zOut = sqlite3_mprintf("%z/%s", zOut, zCopy);
}
break;
}
cSep = zCopy[i];
zCopy[i] = 0;
len = i;
}
}
sqlite3_free(zCopy);
if( zOut ){
/* Simplify any "/./" or "/../" that might have snuck into the
** pathname due to appending of zCopy. We only have to consider
** unix "/" separators, because the _wfilepath() system call on
** Windows will have already done this simplification for us. */
size_t i, j, n;
n = strlen(zOut);
for(i=j=0; i<n; i++){
if( zOut[i]=='/' ){
if( zOut[i+1]=='/' ) continue;
if( zOut[i+1]=='.' && i+2<n && zOut[i+2]=='/' ){
i += 1;
continue;
}
if( zOut[i+1]=='.' && i+3<n && zOut[i+2]=='.' && zOut[i+3]=='/' ){
while( j>0 && zOut[j-1]!='/' ){ j--; }
if( j>0 ){ j--; }
i += 2;
continue;
}
}
zOut[j++] = zOut[i];
}
zOut[j] = 0;
/* Return the result */
sqlite3_result_text(context, zOut, -1, sqlite3_free);
}
}
#ifdef _WIN32
__declspec(dllexport)
#endif
@@ -1282,10 +1120,5 @@ int sqlite3_fileio_init(
if( rc==SQLITE_OK ){
rc = fsdirRegister(db);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "realpath", 1,
SQLITE_UTF8, 0,
realpathFunc, 0, 0);
}
return rc;
}
+22 -49
View File
@@ -29,17 +29,6 @@
** RBU does not use this extension directly. Rather, this extension is
** provided as a convenience to developers who want to analyze RBU files
** that contain deltas.
**
** Typical build commands assuming
**
** DIR=ext/misc
* NAME=fossildelta
**
** First run "make sqlite3ext.h" then:
**
** linux: gcc -shared -I. -fPIC -o $NAME.so $DIR/$NAME.c
** OS-X: gcc -dynamiclib -fPIC -I. -o $NAME.dylib $DIR/$NAME.c
** Win11: cl -I. $DIR/$NAME.c -link -dll -out:$NAME.dll
*/
#include <string.h>
#include <assert.h>
@@ -49,12 +38,9 @@ SQLITE_EXTENSION_INIT1
#ifndef SQLITE_AMALGAMATION
/*
** The "u32" type must be an unsigned 32-bit integer. "u64" is
** an unsigned 64-bit integer.
** The "u32" type must be an unsigned 32-bit integer. Adjust this
*/
typedef unsigned int u32;
typedef sqlite3_uint64 u64;
typedef sqlite3_int64 i64;
/*
** Must be a 16-bit value
@@ -179,26 +165,16 @@ static unsigned int deltaGetInt(const char **pz, int *pLen){
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
-1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
unsigned int v = 0;
int c;
unsigned char *z = (unsigned char*)*pz;
unsigned char *zEnd = z + (*pLen);
while( z<zEnd && (c = zValue[*z])>=0 ){
v = (v<<6) + c;
z++;
unsigned char *zStart = z;
while( (c = zValue[0x7f&*(z++)])>=0 ){
v = (v<<6) + c;
}
*pLen -= (int)(z - (unsigned char*)*pz);
z--;
*pLen -= z - zStart;
*pz = (char*)z;
return v;
}
@@ -288,8 +264,7 @@ static unsigned int checksum(const char *zIn, size_t N){
** The delta string will be NUL-terminated, but it might also contain
** embedded NUL characters if either the zSrc or zOut files are
** binary. This function returns the length of the delta string
** in bytes, excluding the final NUL terminator character. It returns
** 0 if an OOM occurs.
** in bytes, excluding the final NUL terminator character.
**
** Output Format:
**
@@ -381,7 +356,6 @@ static int delta_create(
*/
nHash = lenSrc/NHASH;
collide = sqlite3_malloc64( (sqlite3_int64)nHash*2*sizeof(int) );
if( collide==0 ) return 0;
memset(collide, -1, nHash*2*sizeof(int));
landmark = &collide[nHash];
for(i=0; i<lenSrc-NHASH; i+=NHASH){
@@ -532,7 +506,7 @@ static int delta_create(
static int delta_output_size(const char *zDelta, int lenDelta){
int size;
size = deltaGetInt(&zDelta, &lenDelta);
if( lenDelta<=0 || *zDelta!='\n' ){
if( *zDelta!='\n' ){
/* ERROR: size integer not terminated by "\n" */
return -1;
}
@@ -567,14 +541,14 @@ static int delta_apply(
int lenDelta, /* Length of the delta */
char *zOut /* Write the output into this preallocated buffer */
){
sqlite3_uint64 limit;
sqlite3_uint64 total = 0;
unsigned int limit;
unsigned int total = 0;
#ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST
char *zOrigOut = zOut;
#endif
limit = deltaGetInt(&zDelta, &lenDelta);
if( lenDelta<=0 || *zDelta!='\n' ){
if( *zDelta!='\n' ){
/* ERROR: size integer not terminated by "\n" */
return -1;
}
@@ -582,7 +556,6 @@ static int delta_apply(
while( *zDelta && lenDelta>0 ){
unsigned int cnt, ofst;
cnt = deltaGetInt(&zDelta, &lenDelta);
if( lenDelta<=0 ) return -1;
switch( zDelta[0] ){
case '@': {
zDelta++; lenDelta--;
@@ -597,7 +570,7 @@ static int delta_apply(
/* ERROR: copy exceeds output file size */
return -1;
}
if( (u64)ofst+(u64)cnt > (u64)lenSrc ){
if( ofst+cnt > lenSrc ){
/* ERROR: copy extends past end of input */
return -1;
}
@@ -794,11 +767,11 @@ struct deltaparsevtab_vtab {
struct deltaparsevtab_cursor {
sqlite3_vtab_cursor base; /* Base class - must be first */
char *aDelta; /* The delta being parsed */
i64 iCursor; /* Current cursor location */
i64 iNext; /* Next cursor value */
i64 nDelta; /* Number of bytes in the delta */
int nDelta; /* Number of bytes in the delta */
int iCursor; /* Current cursor location */
int eOp; /* Name of current operator */
unsigned int a1, a2; /* Arguments to current operator */
int iNext; /* Next cursor value */
};
/* Operator names:
@@ -868,7 +841,7 @@ static int deltaparsevtabDisconnect(sqlite3_vtab *pVtab){
*/
static int deltaparsevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
deltaparsevtab_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
@@ -902,7 +875,7 @@ static int deltaparsevtabNext(sqlite3_vtab_cursor *cur){
}
z = pCur->aDelta + pCur->iCursor;
pCur->a1 = deltaGetInt(&z, &i);
switch( i>0 ? z[0] : 0 ){
switch( z[0] ){
case '@': {
z++;
if( pCur->iNext>=pCur->nDelta ){
@@ -912,14 +885,14 @@ static int deltaparsevtabNext(sqlite3_vtab_cursor *cur){
}
pCur->a2 = deltaGetInt(&z, &i);
pCur->eOp = DELTAPARSE_OP_COPY;
pCur->iNext = (i64)(&z[1] - pCur->aDelta);
pCur->iNext = (int)(&z[1] - pCur->aDelta);
break;
}
case ':': {
z++;
pCur->a2 = (unsigned int)(z - pCur->aDelta);
pCur->eOp = DELTAPARSE_OP_INSERT;
pCur->iNext = (i64)(&z[pCur->a1] - pCur->aDelta);
pCur->iNext = (int)(&z[pCur->a1] - pCur->aDelta);
break;
}
case ';': {
@@ -963,7 +936,7 @@ static int deltaparsevtabColumn(
if( pCur->eOp==DELTAPARSE_OP_COPY ){
sqlite3_result_int(ctx, pCur->a2);
}else if( pCur->eOp==DELTAPARSE_OP_INSERT ){
if( (i64)pCur->a2 + (i64)pCur->a1 > pCur->nDelta ){
if( pCur->a2 + pCur->a1 > pCur->nDelta ){
sqlite3_result_zeroblob(ctx, pCur->a1);
}else{
sqlite3_result_blob(ctx, pCur->aDelta+pCur->a2, pCur->a1,
@@ -1032,14 +1005,14 @@ static int deltaparsevtabFilter(
a = pCur->aDelta;
pCur->eOp = DELTAPARSE_OP_SIZE;
pCur->a1 = deltaGetInt(&a, &i);
if( i<=0 || a[0]!='\n' ){
if( a[0]!='\n' ){
pCur->eOp = DELTAPARSE_OP_ERROR;
pCur->a1 = pCur->a2 = 0;
pCur->iNext = pCur->nDelta;
return SQLITE_OK;
}
a++;
pCur->iNext = (i64)(a - pCur->aDelta);
pCur->iNext = (unsigned int)(a - pCur->aDelta);
return SQLITE_OK;
}
+3 -3
View File
@@ -556,7 +556,7 @@ static int fuzzerConnect(
static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
fuzzer_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->pVtab = p;
@@ -617,12 +617,12 @@ static int fuzzerRender(
int *pnBuf /* Size of the buffer */
){
const fuzzer_rule *pRule = pStem->pRule;
sqlite3_int64 n; /* Size of output term without nul-term */
int n; /* Size of output term without nul-term */
char *z; /* Buffer to assemble output term in */
n = pStem->nBasis + pRule->nTo - pRule->nFrom;
if( (*pnBuf)<n+1 ){
(*pzBuf) = sqlite3_realloc64((*pzBuf), n+100);
(*pzBuf) = sqlite3_realloc((*pzBuf), n+100);
if( (*pzBuf)==0 ) return SQLITE_NOMEM;
(*pnBuf) = n+100;
}
+1 -35
View File
@@ -179,9 +179,9 @@ static void ieee754func(
}
if( m<0 ){
if( m<(-9223372036854775807LL) ) return;
isNeg = 1;
m = -m;
if( m<0 ) return;
}else if( m==0 && e>-1000 && e<1000 ){
sqlite3_result_double(context, 0.0);
return;
@@ -259,38 +259,6 @@ static void ieee754func_to_blob(
}
}
/*
** Functions to convert between 64-bit integers and floats.
**
** The bit patterns are copied. The numeric values are different.
*/
static void ieee754func_from_int(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
UNUSED_PARAMETER(argc);
if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
double r;
sqlite3_int64 v = sqlite3_value_int64(argv[0]);
memcpy(&r, &v, sizeof(r));
sqlite3_result_double(context, r);
}
}
static void ieee754func_to_int(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
UNUSED_PARAMETER(argc);
if( sqlite3_value_type(argv[0])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[0]);
sqlite3_uint64 v;
memcpy(&v, &r, sizeof(v));
sqlite3_result_int64(context, v);
}
}
/*
** SQL Function: ieee754_inc(r,N)
**
@@ -343,8 +311,6 @@ int sqlite3_ieee_init(
{ "ieee754_exponent", 1, 2, ieee754func },
{ "ieee754_to_blob", 1, 0, ieee754func_to_blob },
{ "ieee754_from_blob", 1, 0, ieee754func_from_blob },
{ "ieee754_to_int", 1, 0, ieee754func_to_int },
{ "ieee754_from_int", 1, 0, ieee754func_from_int },
{ "ieee754_inc", 2, 0, ieee754inc },
};
unsigned int i;
+2 -2
View File
@@ -85,7 +85,7 @@ static int memstatConnect(
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)");
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -107,7 +107,7 @@ static int memstatDisconnect(sqlite3_vtab *pVtab){
*/
static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
memstat_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->db = ((memstat_vtab*)p)->db;
+38 -38
View File
@@ -340,45 +340,45 @@ static void percentSort(double *a, unsigned int n){
int iGt; /* Entries at or after a[iGt] are greater than rPivot */
int i; /* Loop counter */
double rPivot; /* The pivot value */
while( n>=2 ){
if( a[0]>a[n-1] ){
SWAP_DOUBLE(a[0],a[n-1])
}
if( n==2 ) return;
iGt = n-1;
i = n/2;
if( a[0]>a[i] ){
SWAP_DOUBLE(a[0],a[i])
}else if( a[i]>a[iGt] ){
SWAP_DOUBLE(a[i],a[iGt])
}
if( n==3 ) return;
rPivot = a[i];
iLt = i = 1;
do{
if( a[i]<rPivot ){
if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt])
iLt++;
i++;
}else if( a[i]>rPivot ){
do{
iGt--;
}while( iGt>i && a[iGt]>rPivot );
SWAP_DOUBLE(a[i],a[iGt])
}else{
i++;
}
}while( i<iGt );
if( iLt>n/2 ){
if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
n = iLt;
}else{
if( iLt>=2 ) percentSort(a, iLt);
a += iGt;
n -= iGt;
}
assert( n>=2 );
if( a[0]>a[n-1] ){
SWAP_DOUBLE(a[0],a[n-1])
}
if( n==2 ) return;
iGt = n-1;
i = n/2;
if( a[0]>a[i] ){
SWAP_DOUBLE(a[0],a[i])
}else if( a[i]>a[iGt] ){
SWAP_DOUBLE(a[i],a[iGt])
}
if( n==3 ) return;
rPivot = a[i];
iLt = i = 1;
do{
if( a[i]<rPivot ){
if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt])
iLt++;
i++;
}else if( a[i]>rPivot ){
do{
iGt--;
}while( iGt>i && a[iGt]>rPivot );
SWAP_DOUBLE(a[i],a[iGt])
}else{
i++;
}
}while( i<iGt );
if( iLt>=2 ) percentSort(a, iLt);
if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
/* Uncomment for testing */
#if 0
for(i=0; i<n-1; i++){
assert( a[i]<=a[i+1] );
}
#endif
}
+3 -7
View File
@@ -75,7 +75,7 @@ static int prefixesConnect(
"CREATE TABLE prefixes(prefix TEXT, original_string TEXT HIDDEN)"
);
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -98,7 +98,7 @@ static int prefixesDisconnect(sqlite3_vtab *pVtab){
*/
static int prefixesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
prefixes_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
@@ -289,14 +289,10 @@ static void prefixLengthFunc(
int nL = sqlite3_value_bytes(apVal[0]);
int nR = sqlite3_value_bytes(apVal[1]);
int i;
if( zL==0 || zR==0 ){
sqlite3_result_int(ctx, 0);
return;
}
nByte = (nL > nR ? nL : nR);
for(i=0; i<nByte; i++){
if( zL[i]==0 || zL[i]!=zR[i] ) break;
if( zL[i]!=zR[i] ) break;
if( (zL[i] & 0xC0)!=0x80 ) nRet++;
}
+3 -3
View File
@@ -152,7 +152,7 @@ static int qpvtabConnect(
#define QPVTAB_FLAGS 11
#define QPVTAB_NONE 12
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -174,7 +174,7 @@ static int qpvtabDisconnect(sqlite3_vtab *pVtab){
*/
static int qpvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
qpvtab_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
@@ -363,7 +363,7 @@ static int qpvtabBestIndex(
}
sqlite3_str_appendf(pStr,"aConstraint,%d,%s,%d,%d,",
i,
iCol>=0 ? azColname[iCol] : "rowid",
azColname[iCol],
op,
pIdxInfo->aConstraint[i].usable);
pVal = 0;
+17 -30
View File
@@ -32,7 +32,7 @@
** ^X X occurring at the beginning of the string
** X$ X occurring at the end of the string
** . Match any single character
** \c Character c where c is one of \{}()[]|*+?-.
** \c Character c where c is one of \{}()[]|*+?.
** \c C-language escapes for c in afnrtv. ex: \t or \n
** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
** \xXX Where XX is exactly 2 hex digits, unicode value XX
@@ -417,7 +417,7 @@ static int re_hex(int c, int *pV){
** return its interpretation.
*/
static unsigned re_esc_char(ReCompiled *p){
static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]-";
static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
static const char zTrans[] = "\a\f\n\r\t\v";
int i, v = 0;
char c;
@@ -676,7 +676,7 @@ static const char *re_compile(
int i, j;
*ppRe = 0;
pRe = sqlite3_malloc64( sizeof(*pRe) );
pRe = sqlite3_malloc( sizeof(*pRe) );
if( pRe==0 ){
return "out of memory";
}
@@ -740,18 +740,11 @@ static const char *re_compile(
}
/*
** The value of LIMIT_MAX_PATTERN_LENGTH.
** Compute a reasonable limit on the length of the REGEXP NFA.
*/
static int re_maxlen(sqlite3_context *context){
sqlite3 *db = sqlite3_context_db_handle(context);
return sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH,-1);
}
/*
** Maximum NFA size given a maximum pattern length.
*/
static int re_maxnfa(int mxlen){
return 75+mxlen/2;
return 75 + sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH,-1)/2;
}
/*
@@ -777,17 +770,10 @@ static void re_sql_func(
(void)argc; /* Unused */
pRe = sqlite3_get_auxdata(context, 0);
if( pRe==0 ){
int mxLen = re_maxlen(context);
int nPattern;
zPattern = (const char*)sqlite3_value_text(argv[0]);
if( zPattern==0 ) return;
nPattern = sqlite3_value_bytes(argv[0]);
if( nPattern>mxLen ){
zErr = "REGEXP pattern too big";
}else{
zErr = re_compile(&pRe, zPattern, re_maxnfa(mxLen),
sqlite3_user_data(context)!=0);
}
zErr = re_compile(&pRe, zPattern, re_maxlen(context),
sqlite3_user_data(context)!=0);
if( zErr ){
re_free(pRe);
sqlite3_result_error(context, zErr, -1);
@@ -828,6 +814,7 @@ static void re_bytecode_func(
int i;
int n;
char *z;
(void)argc;
static const char *ReOpName[] = {
"EOF",
"MATCH",
@@ -850,10 +837,9 @@ static void re_bytecode_func(
"ATSTART",
};
(void)argc;
zPattern = (const char*)sqlite3_value_text(argv[0]);
if( zPattern==0 ) return;
zErr = re_compile(&pRe, zPattern, re_maxnfa(re_maxlen(context)),
zErr = re_compile(&pRe, zPattern, re_maxlen(context),
sqlite3_user_data(context)!=0);
if( zErr ){
re_free(pRe);
@@ -865,6 +851,7 @@ static void re_bytecode_func(
return;
}
pStr = sqlite3_str_new(0);
if( pStr==0 ) goto re_bytecode_func_err;
if( pRe->nInit>0 ){
sqlite3_str_appendf(pStr, "INIT ");
for(i=0; i<pRe->nInit; i++){
@@ -876,15 +863,15 @@ static void re_bytecode_func(
sqlite3_str_appendf(pStr, "%-8s %4d\n",
ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]);
}
if( sqlite3_str_errcode(pStr)==SQLITE_NOMEM ){
sqlite3_str_finish(pStr);
re_free(pRe);
sqlite3_result_error_nomem(context);
return;
}
n = sqlite3_str_length(pStr);
z = sqlite3_str_finish(pStr);
sqlite3_result_text(context, z, n-1, sqlite3_free);
if( n==0 ){
sqlite3_free(z);
}else{
sqlite3_result_text(context, z, n-1, sqlite3_free);
}
re_bytecode_func_err:
re_free(pRe);
}
+610
View File
@@ -0,0 +1,610 @@
/*
** 2016-05-05
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file implements a utility function (and a utility program) that
** makes a copy of an SQLite database while simultaneously zeroing out all
** deleted content.
**
** Normally (when PRAGMA secure_delete=OFF, which is the default) when SQLite
** deletes content, it does not overwrite the deleted content but rather marks
** the region of the file that held that content as being reusable. This can
** cause deleted content to recoverable from the database file. This stale
** content is removed by the VACUUM command, but VACUUM can be expensive for
** large databases. When in PRAGMA secure_delete=ON mode, the deleted content
** is zeroed, but secure_delete=ON has overhead as well.
**
** This utility attempts to make a copy of a complete SQLite database where
** all of the deleted content is zeroed out in the copy, and it attempts to
** do so while being faster than running VACUUM.
**
** Usage:
**
** int sqlite3_scrub_backup(
** const char *zSourceFile, // Source database filename
** const char *zDestFile, // Destination database filename
** char **pzErrMsg // Write error message here
** );
**
** Simply call the API above specifying the filename of the source database
** and the name of the backup copy. The source database must already exist
** and can be in active use. (A read lock is held during the backup.) The
** destination file should not previously exist. If the pzErrMsg parameter
** is non-NULL and if an error occurs, then an error message might be written
** into memory obtained from sqlite3_malloc() and *pzErrMsg made to point to
** that error message. But if the error is an OOM, the error might not be
** reported. The routine always returns non-zero if there is an error.
**
** If compiled with -DSCRUB_STANDALONE then a main() procedure is added and
** this file becomes a standalone program that can be run as follows:
**
** ./sqlite3scrub SOURCE DEST
*/
#include "sqlite3.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
typedef struct ScrubState ScrubState;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
/* State information for a scrub-and-backup operation */
struct ScrubState {
const char *zSrcFile; /* Name of the source file */
const char *zDestFile; /* Name of the destination file */
int rcErr; /* Error code */
char *zErr; /* Error message text */
sqlite3 *dbSrc; /* Source database connection */
sqlite3_file *pSrc; /* Source file handle */
sqlite3 *dbDest; /* Destination database connection */
sqlite3_file *pDest; /* Destination file handle */
u32 szPage; /* Page size */
u32 szUsable; /* Usable bytes on each page */
u32 nPage; /* Number of pages */
u32 iLastPage; /* Page number of last page written so far*/
u8 *page1; /* Content of page 1 */
};
/* Store an error message */
static void scrubBackupErr(ScrubState *p, const char *zFormat, ...){
va_list ap;
sqlite3_free(p->zErr);
va_start(ap, zFormat);
p->zErr = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
if( p->rcErr==0 ) p->rcErr = SQLITE_ERROR;
}
/* Allocate memory to hold a single page of content */
static u8 *scrubBackupAllocPage(ScrubState *p){
u8 *pPage;
if( p->rcErr ) return 0;
pPage = sqlite3_malloc( p->szPage );
if( pPage==0 ) p->rcErr = SQLITE_NOMEM;
return pPage;
}
/* Read a page from the source database into memory. Use the memory
** provided by pBuf if not NULL or allocate a new page if pBuf==NULL.
*/
static u8 *scrubBackupRead(ScrubState *p, int pgno, u8 *pBuf){
int rc;
sqlite3_int64 iOff;
u8 *pOut = pBuf;
if( p->rcErr ) return 0;
if( pOut==0 ){
pOut = scrubBackupAllocPage(p);
if( pOut==0 ) return 0;
}
iOff = (pgno-1)*(sqlite3_int64)p->szPage;
rc = p->pSrc->pMethods->xRead(p->pSrc, pOut, p->szPage, iOff);
if( rc!=SQLITE_OK ){
if( pBuf==0 ) sqlite3_free(pOut);
pOut = 0;
scrubBackupErr(p, "read failed for page %d", pgno);
p->rcErr = SQLITE_IOERR;
}
return pOut;
}
/* Write a page to the destination database */
static void scrubBackupWrite(ScrubState *p, int pgno, const u8 *pData){
int rc;
sqlite3_int64 iOff;
if( p->rcErr ) return;
iOff = (pgno-1)*(sqlite3_int64)p->szPage;
rc = p->pDest->pMethods->xWrite(p->pDest, pData, p->szPage, iOff);
if( rc!=SQLITE_OK ){
scrubBackupErr(p, "write failed for page %d", pgno);
p->rcErr = SQLITE_IOERR;
}
if( (u32)pgno>p->iLastPage ) p->iLastPage = pgno;
}
/* Prepare a statement against the "db" database. */
static sqlite3_stmt *scrubBackupPrepare(
ScrubState *p, /* Backup context */
sqlite3 *db, /* Database to prepare against */
const char *zSql /* SQL statement */
){
sqlite3_stmt *pStmt;
if( p->rcErr ) return 0;
p->rcErr = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( p->rcErr ){
scrubBackupErr(p, "SQL error \"%s\" on \"%s\"",
sqlite3_errmsg(db), zSql);
sqlite3_finalize(pStmt);
return 0;
}
return pStmt;
}
/* Open the source database file */
static void scrubBackupOpenSrc(ScrubState *p){
sqlite3_stmt *pStmt;
int rc;
/* Open the source database file */
p->rcErr = sqlite3_open_v2(p->zSrcFile, &p->dbSrc,
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_URI | SQLITE_OPEN_PRIVATECACHE, 0);
if( p->rcErr ){
scrubBackupErr(p, "cannot open source database: %s",
sqlite3_errmsg(p->dbSrc));
return;
}
p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_schema; BEGIN;",
0, 0, 0);
if( p->rcErr ){
scrubBackupErr(p,
"cannot start a read transaction on the source database: %s",
sqlite3_errmsg(p->dbSrc));
return;
}
rc = sqlite3_wal_checkpoint_v2(p->dbSrc, "main", SQLITE_CHECKPOINT_FULL,
0, 0);
if( rc ){
scrubBackupErr(p, "cannot checkpoint the source database");
return;
}
pStmt = scrubBackupPrepare(p, p->dbSrc, "PRAGMA page_size");
if( pStmt==0 ) return;
rc = sqlite3_step(pStmt);
if( rc==SQLITE_ROW ){
p->szPage = sqlite3_column_int(pStmt, 0);
}else{
scrubBackupErr(p, "unable to determine the page size");
}
sqlite3_finalize(pStmt);
if( p->rcErr ) return;
pStmt = scrubBackupPrepare(p, p->dbSrc, "PRAGMA page_count");
if( pStmt==0 ) return;
rc = sqlite3_step(pStmt);
if( rc==SQLITE_ROW ){
p->nPage = sqlite3_column_int(pStmt, 0);
}else{
scrubBackupErr(p, "unable to determine the size of the source database");
}
sqlite3_finalize(pStmt);
sqlite3_file_control(p->dbSrc, "main", SQLITE_FCNTL_FILE_POINTER, &p->pSrc);
if( p->pSrc==0 || p->pSrc->pMethods==0 ){
scrubBackupErr(p, "cannot get the source file handle");
p->rcErr = SQLITE_ERROR;
}
}
/* Create and open the destination file */
static void scrubBackupOpenDest(ScrubState *p){
sqlite3_stmt *pStmt;
int rc;
char *zSql;
if( p->rcErr ) return;
p->rcErr = sqlite3_open_v2(p->zDestFile, &p->dbDest,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
SQLITE_OPEN_URI | SQLITE_OPEN_PRIVATECACHE, 0);
if( p->rcErr ){
scrubBackupErr(p, "cannot open destination database: %s",
sqlite3_errmsg(p->dbDest));
return;
}
zSql = sqlite3_mprintf("PRAGMA page_size(%u);", p->szPage);
if( zSql==0 ){
p->rcErr = SQLITE_NOMEM;
return;
}
p->rcErr = sqlite3_exec(p->dbDest, zSql, 0, 0, 0);
sqlite3_free(zSql);
if( p->rcErr ){
scrubBackupErr(p,
"cannot set the page size on the destination database: %s",
sqlite3_errmsg(p->dbDest));
return;
}
sqlite3_exec(p->dbDest, "PRAGMA journal_mode=OFF;", 0, 0, 0);
p->rcErr = sqlite3_exec(p->dbDest, "BEGIN EXCLUSIVE;", 0, 0, 0);
if( p->rcErr ){
scrubBackupErr(p,
"cannot start a write transaction on the destination database: %s",
sqlite3_errmsg(p->dbDest));
return;
}
pStmt = scrubBackupPrepare(p, p->dbDest, "PRAGMA page_count;");
if( pStmt==0 ) return;
rc = sqlite3_step(pStmt);
if( rc!=SQLITE_ROW ){
scrubBackupErr(p, "cannot measure the size of the destination");
}else if( sqlite3_column_int(pStmt, 0)>1 ){
scrubBackupErr(p, "destination database is not empty - holds %d pages",
sqlite3_column_int(pStmt, 0));
}
sqlite3_finalize(pStmt);
sqlite3_file_control(p->dbDest, "main", SQLITE_FCNTL_FILE_POINTER, &p->pDest);
if( p->pDest==0 || p->pDest->pMethods==0 ){
scrubBackupErr(p, "cannot get the destination file handle");
p->rcErr = SQLITE_ERROR;
}
}
/* Read a 32-bit big-endian integer */
static u32 scrubBackupInt32(const u8 *a){
u32 v = a[3];
v += ((u32)a[2])<<8;
v += ((u32)a[1])<<16;
v += ((u32)a[0])<<24;
return v;
}
/* Read a 16-bit big-endian integer */
static u32 scrubBackupInt16(const u8 *a){
return (a[0]<<8) + a[1];
}
/*
** Read a varint. Put the value in *pVal and return the number of bytes.
*/
static int scrubBackupVarint(const u8 *z, sqlite3_int64 *pVal){
sqlite3_int64 v = 0;
int i;
for(i=0; i<8; i++){
v = (v<<7) + (z[i]&0x7f);
if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
}
v = (v<<8) + (z[i]&0xff);
*pVal = v;
return 9;
}
/*
** Return the number of bytes in a varint.
*/
static int scrubBackupVarintSize(const u8 *z){
int i;
for(i=0; i<8; i++){
if( (z[i]&0x80)==0 ){ return i+1; }
}
return 9;
}
/*
** Copy the freelist trunk page given, and all its descendents,
** zeroing out as much as possible in the process.
*/
static void scrubBackupFreelist(ScrubState *p, int pgno, u32 nFree){
u8 *a, *aBuf;
u32 n, mx;
if( p->rcErr ) return;
aBuf = scrubBackupAllocPage(p);
if( aBuf==0 ) return;
while( pgno && nFree){
a = scrubBackupRead(p, pgno, aBuf);
if( a==0 ) break;
n = scrubBackupInt32(&a[4]);
mx = p->szUsable/4 - 2;
if( n<mx ){
memset(&a[n*4+8], 0, 4*(mx-n));
}
scrubBackupWrite(p, pgno, a);
pgno = scrubBackupInt32(a);
#if 0
/* There is really no point in copying the freelist leaf pages.
** Simply leave them uninitialized in the destination database. The
** OS filesystem should zero those pages for us automatically.
*/
for(i=0; i<n && nFree; i++){
u32 iLeaf = scrubBackupInt32(&a[i*4+8]);
if( aZero==0 ){
aZero = scrubBackupAllocPage(p);
if( aZero==0 ){ pgno = 0; break; }
memset(aZero, 0, p->szPage);
}
scrubBackupWrite(p, iLeaf, aZero);
nFree--;
}
#endif
}
sqlite3_free(aBuf);
}
/*
** Copy an overflow chain from source to destination. Zero out any
** unused tail at the end of the overflow chain.
*/
static void scrubBackupOverflow(ScrubState *p, int pgno, u32 nByte){
u8 *a, *aBuf;
aBuf = scrubBackupAllocPage(p);
if( aBuf==0 ) return;
while( nByte>0 && pgno!=0 ){
a = scrubBackupRead(p, pgno, aBuf);
if( a==0 ) break;
if( nByte >= (p->szUsable)-4 ){
nByte -= (p->szUsable) - 4;
}else{
u32 x = (p->szUsable - 4) - nByte;
u32 i = p->szUsable - x;
memset(&a[i], 0, x);
nByte = 0;
}
scrubBackupWrite(p, pgno, a);
pgno = scrubBackupInt32(a);
}
sqlite3_free(aBuf);
}
/*
** Copy B-Tree page pgno, and all of its children, from source to destination.
** Zero out deleted content during the copy.
*/
static void scrubBackupBtree(ScrubState *p, int pgno, int iDepth){
u8 *a;
u32 i, n, pc;
u32 nCell;
u32 nPrefix;
u32 szHdr;
u32 iChild;
u8 *aTop;
u8 *aCell;
u32 x, y;
int ln = 0;
if( p->rcErr ) return;
if( iDepth>50 ){
scrubBackupErr(p, "corrupt: b-tree too deep at page %d", pgno);
return;
}
if( pgno==1 ){
a = p->page1;
}else{
a = scrubBackupRead(p, pgno, 0);
if( a==0 ) return;
}
nPrefix = pgno==1 ? 100 : 0;
aTop = &a[nPrefix];
szHdr = 8 + 4*(aTop[0]==0x02 || aTop[0]==0x05);
aCell = aTop + szHdr;
nCell = scrubBackupInt16(&aTop[3]);
/* Zero out the gap between the cell index and the start of the
** cell content area */
x = scrubBackupInt16(&aTop[5]); /* First byte of cell content area */
if( x>p->szUsable ){ ln=__LINE__; goto btree_corrupt; }
y = szHdr + nPrefix + nCell*2;
if( y>x ){ ln=__LINE__; goto btree_corrupt; }
if( y<x ) memset(a+y, 0, x-y); /* Zero the gap */
/* Zero out all the free blocks */
pc = scrubBackupInt16(&aTop[1]);
if( pc>0 && pc<x ){ ln=__LINE__; goto btree_corrupt; }
while( pc ){
if( pc>(p->szUsable)-4 ){ ln=__LINE__; goto btree_corrupt; }
n = scrubBackupInt16(&a[pc+2]);
if( pc+n>(p->szUsable) ){ ln=__LINE__; goto btree_corrupt; }
if( n>4 ) memset(&a[pc+4], 0, n-4);
x = scrubBackupInt16(&a[pc]);
if( x<pc+4 && x>0 ){ ln=__LINE__; goto btree_corrupt; }
pc = x;
}
/* Write this one page */
scrubBackupWrite(p, pgno, a);
/* Walk the tree and process child pages */
for(i=0; i<nCell; i++){
u32 X, M, K, nLocal;
sqlite3_int64 P;
pc = scrubBackupInt16(&aCell[i*2]);
if( pc <= szHdr ){ ln=__LINE__; goto btree_corrupt; }
if( pc > p->szUsable-3 ){ ln=__LINE__; goto btree_corrupt; }
if( aTop[0]==0x05 || aTop[0]==0x02 ){
if( pc+4 > p->szUsable ){ ln=__LINE__; goto btree_corrupt; }
iChild = scrubBackupInt32(&a[pc]);
pc += 4;
scrubBackupBtree(p, iChild, iDepth+1);
if( aTop[0]==0x05 ) continue;
}
pc += scrubBackupVarint(&a[pc], &P);
if( pc >= p->szUsable ){ ln=__LINE__; goto btree_corrupt; }
if( aTop[0]==0x0d ){
X = p->szUsable - 35;
}else{
X = ((p->szUsable - 12)*64/255) - 23;
}
if( P<=X ){
/* All content is local. No overflow */
continue;
}
M = ((p->szUsable - 12)*32/255)-23;
K = M + ((P-M)%(p->szUsable-4));
if( aTop[0]==0x0d ){
pc += scrubBackupVarintSize(&a[pc]);
if( pc > (p->szUsable-4) ){ ln=__LINE__; goto btree_corrupt; }
}
nLocal = K<=X ? K : M;
if( pc+nLocal > p->szUsable-4 ){ ln=__LINE__; goto btree_corrupt; }
iChild = scrubBackupInt32(&a[pc+nLocal]);
scrubBackupOverflow(p, iChild, (u32)(P-nLocal));
}
/* Walk the right-most tree */
if( aTop[0]==0x05 || aTop[0]==0x02 ){
iChild = scrubBackupInt32(&aTop[8]);
scrubBackupBtree(p, iChild, iDepth+1);
}
/* All done */
if( pgno>1 ) sqlite3_free(a);
return;
btree_corrupt:
scrubBackupErr(p, "corruption on page %d of source database (errid=%d)",
pgno, ln);
if( pgno>1 ) sqlite3_free(a);
}
/*
** Copy all ptrmap pages from source to destination.
** This routine is only called if the source database is in autovacuum
** or incremental vacuum mode.
*/
static void scrubBackupPtrmap(ScrubState *p){
u32 pgno = 2;
u32 J = p->szUsable/5;
u32 iLock = (1073742335/p->szPage)+1;
u8 *a, *pBuf;
if( p->rcErr ) return;
pBuf = scrubBackupAllocPage(p);
if( pBuf==0 ) return;
while( pgno<=p->nPage ){
a = scrubBackupRead(p, pgno, pBuf);
if( a==0 ) break;
scrubBackupWrite(p, pgno, a);
pgno += J+1;
if( pgno==iLock ) pgno++;
}
sqlite3_free(pBuf);
}
int sqlite3_scrub_backup(
const char *zSrcFile, /* Source file */
const char *zDestFile, /* Destination file */
char **pzErr /* Write error here if non-NULL */
){
ScrubState s;
u32 n, i;
sqlite3_stmt *pStmt;
memset(&s, 0, sizeof(s));
s.zSrcFile = zSrcFile;
s.zDestFile = zDestFile;
/* Open both source and destination databases */
scrubBackupOpenSrc(&s);
scrubBackupOpenDest(&s);
/* Read in page 1 */
s.page1 = scrubBackupRead(&s, 1, 0);
if( s.page1==0 ) goto scrub_abort;
s.szUsable = s.szPage - s.page1[20];
/* Copy the freelist */
n = scrubBackupInt32(&s.page1[36]);
i = scrubBackupInt32(&s.page1[32]);
if( n ) scrubBackupFreelist(&s, i, n);
/* Copy ptrmap pages */
n = scrubBackupInt32(&s.page1[52]);
if( n ) scrubBackupPtrmap(&s);
/* Copy all of the btrees */
scrubBackupBtree(&s, 1, 0);
pStmt = scrubBackupPrepare(&s, s.dbSrc,
"SELECT rootpage FROM sqlite_schema WHERE coalesce(rootpage,0)>0");
if( pStmt==0 ) goto scrub_abort;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
i = (u32)sqlite3_column_int(pStmt, 0);
scrubBackupBtree(&s, i, 0);
}
sqlite3_finalize(pStmt);
/* If the last page of the input db file is a free-list leaf, then the
** backup file on disk is still smaller than the size indicated within
** the database header. In this case, write a page of zeroes to the
** last page of the backup database so that SQLite does not mistakenly
** think the db is corrupt. */
if( s.iLastPage<s.nPage ){
u8 *aZero = scrubBackupAllocPage(&s);
if( aZero ){
memset(aZero, 0, s.szPage);
scrubBackupWrite(&s, s.nPage, aZero);
sqlite3_free(aZero);
}
}
scrub_abort:
/* Close the destination database without closing the transaction. If we
** commit, page zero will be overwritten. */
sqlite3_close(s.dbDest);
/* But do close out the read-transaction on the source database */
sqlite3_exec(s.dbSrc, "COMMIT;", 0, 0, 0);
sqlite3_close(s.dbSrc);
sqlite3_free(s.page1);
if( pzErr ){
*pzErr = s.zErr;
}else{
sqlite3_free(s.zErr);
}
return s.rcErr;
}
#ifdef SCRUB_STANDALONE
/* Error and warning log */
static void errorLogCallback(void *pNotUsed, int iErr, const char *zMsg){
const char *zType;
switch( iErr&0xff ){
case SQLITE_WARNING: zType = "WARNING"; break;
case SQLITE_NOTICE: zType = "NOTICE"; break;
default: zType = "ERROR"; break;
}
fprintf(stderr, "%s: %s\n", zType, zMsg);
}
/* The main() routine when this utility is run as a stand-alone program */
int main(int argc, char **argv){
char *zErr = 0;
int rc;
if( argc!=3 ){
fprintf(stderr,"Usage: %s SOURCE DESTINATION\n", argv[0]);
exit(1);
}
sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, 0);
rc = sqlite3_scrub_backup(argv[1], argv[2], &zErr);
if( rc==SQLITE_NOMEM ){
fprintf(stderr, "%s: out of memory\n", argv[0]);
exit(1);
}
if( zErr ){
fprintf(stderr, "%s: %s\n", argv[0], zErr);
sqlite3_free(zErr);
exit(1);
}
return 0;
}
#endif
+13 -31
View File
@@ -239,7 +239,7 @@ static int seriesConnect(
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
if( rc==SQLITE_OK ){
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
@@ -261,7 +261,7 @@ static int seriesDisconnect(sqlite3_vtab *pVtab){
static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){
series_cursor *pCur;
(void)pUnused;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
@@ -400,16 +400,6 @@ static double seriesFloor(double r){
}
#endif
/* Convert a floating point value to its closest integer. Do so in
** a way that avoids 'outside the range of representable values' warnings
** from UBSAN.
*/
sqlite3_int64 seriesRealToI64(double r){
if( r<-9223372036854774784.0 ) return SMALLEST_INT64;
if( r>+9223372036854774784.0 ) return LARGEST_INT64;
return (sqlite3_int64)r;
}
/*
** This method is called to "rewind" the series_cursor object back
** to the first row of output. This method is always called at least
@@ -532,7 +522,7 @@ static int seriesFilter(
&& r>=(double)SMALLEST_INT64
&& r<=(double)LARGEST_INT64
){
iMin = iMax = seriesRealToI64(r);
iMin = iMax = (sqlite3_int64)r;
}else{
goto series_no_rows;
}
@@ -540,19 +530,15 @@ static int seriesFilter(
iMin = iMax = sqlite3_value_int64(argv[iArg++]);
}
}else{
if( idxNum & 0x0300 ){ /* value>X (0x200) or value>=X (0x100) */
if( idxNum & 0x0300 ){ /* value>X or value>=X */
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[iArg++]);
if( r<=(double)SMALLEST_INT64 ){
if( r<(double)SMALLEST_INT64 ){
iMin = SMALLEST_INT64;
}else if( r>(double)LARGEST_INT64 ){
goto series_no_rows;
}else if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){
iMin = (sqlite3_int64)seriesCeil(r+1.0);
}else{
iMin = seriesRealToI64(seriesCeil(r));
if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){
if( iMin==LARGEST_INT64 ) goto series_no_rows;
iMin++;
}
iMin = (sqlite3_int64)seriesCeil(r);
}
}else{
iMin = sqlite3_value_int64(argv[iArg++]);
@@ -565,19 +551,15 @@ static int seriesFilter(
}
}
}
if( idxNum & 0x3000 ){ /* value<X (0x2000) or value<=X (0x1000) */
if( idxNum & 0x3000 ){ /* value<X or value<=X */
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[iArg++]);
if( r>=(double)LARGEST_INT64 ){
if( r>(double)LARGEST_INT64 ){
iMax = LARGEST_INT64;
}else if( r<=(double)SMALLEST_INT64 ){
goto series_no_rows;
}else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){
iMax = (sqlite3_int64)(r-1.0);
}else{
iMax = seriesRealToI64(seriesFloor(r));
if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){
if( iMax==SMALLEST_INT64 ) goto series_no_rows;
iMax--;
}
iMax = (sqlite3_int64)seriesFloor(r);
}
}else{
iMax = sqlite3_value_int64(argv[iArg++]);
+8 -24
View File
@@ -31,10 +31,6 @@ SQLITE_EXTENSION_INIT1
/******************************************************************************
** The Hash Engine
*/
#if defined(__GNUC__) && __GNUC__>=11
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstringop-overread"
#endif
/* Context for the SHA1 hash */
typedef struct SHA1Context SHA1Context;
struct SHA1Context {
@@ -175,7 +171,7 @@ static void hash_step(
}else{
i = 0;
}
if( len-i>0 ) (void)memcpy(&p->buffer[j], &data[i], len - i);
(void)memcpy(&p->buffer[j], &data[i], len - i);
}
/* Compute a string using sqlite3_vsnprintf() and hash it */
@@ -230,23 +226,17 @@ static void hash_finish(
zOut[i*2]= 0;
}
}
#if defined(__GNUC__) && __GNUC__>=11
# pragma GCC diagnostic pop
#endif
/* End of the hashing logic
*****************************************************************************/
/*
** Two SQL functions: sha1(X) and sha1b(X).
** Implementation of the sha1(X) function.
**
** sha1(X) returns a lower-case hexadecimal rendering of the SHA1 hash
** of the argument X. If X is a BLOB, it is hashed as is. For all other
** Return a lower-case hexadecimal rendering of the SHA1 hash of the
** argument X. If X is a BLOB, it is hashed as is. For all other
** types of input, X is converted into a UTF-8 string and the string
** is hashed without the trailing 0x00 terminator. The hash of a NULL
** is hash without the trailing 0x00 terminator. The hash of a NULL
** value is NULL.
**
** sha1b(X) is the same except that it returns a 20-byte BLOB containing
** the binary hash instead of a hexadecimal string.
*/
static void sha1Func(
sqlite3_context *context,
@@ -256,27 +246,22 @@ static void sha1Func(
SHA1Context cx;
int eType = sqlite3_value_type(argv[0]);
int nByte = sqlite3_value_bytes(argv[0]);
const unsigned char *pData;
char zOut[44];
assert( argc==1 );
if( eType==SQLITE_NULL ) return;
hash_init(&cx);
if( eType==SQLITE_BLOB ){
pData = (const unsigned char*)sqlite3_value_blob(argv[0]);
hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
}else{
pData = (const unsigned char*)sqlite3_value_text(argv[0]);
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
}
if( pData==0 ) return;
hash_step(&cx, pData, nByte);
if( sqlite3_user_data(context)!=0 ){
/* sha1b() - binary result */
hash_finish(&cx, zOut, 1);
sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT);
}else{
/* sha1() - hexadecimal text result */
hash_finish(&cx, zOut, 0);
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT);
}
}
@@ -330,7 +315,6 @@ static void sha1QueryFunc(
}
nCol = sqlite3_column_count(pStmt);
z = sqlite3_sql(pStmt);
if( z==0 ) z = "";
n = (int)strlen(z);
hash_step_vformat(&cx,"S%d:",n);
hash_step(&cx,(unsigned char*)z,n);
+11 -21
View File
@@ -32,7 +32,6 @@ SQLITE_EXTENSION_INIT1
# define NEVER(X) 0
typedef unsigned char u8;
typedef unsigned short u16;
typedef sqlite3_int64 i64;
#endif
#include <ctype.h>
@@ -193,7 +192,7 @@ static const unsigned char className[] = ".ABCDHLRMY9 ?";
** Return NULL if memory allocation fails.
*/
static unsigned char *phoneticHash(const unsigned char *zIn, int nIn){
unsigned char *zOut = sqlite3_malloc64( (i64)nIn + 1 );
unsigned char *zOut = sqlite3_malloc64( nIn + 1 );
int i;
int nOut = 0;
char cPrev = 0x77;
@@ -353,7 +352,6 @@ static int substituteCost(char cPrev, char cFrom, char cTo){
** -1 One of the inputs is NULL
** -2 Non-ASCII characters on input
** -3 Unable to allocate memory
** -4 Inputs too large
**
** If pnMatch is not NULL, then *pnMatch is set to the number of bytes
** of zB that matched the pattern in zA. If zA does not end with a '*',
@@ -392,11 +390,9 @@ static int editdist1(const char *zA, const char *zB, int *pnMatch){
for(nA=0; zA[nA]; nA++){
if( zA[nA]&0x80 ) return -2;
}
if( nA>=100000 ) return -4;
for(nB=0; zB[nB]; nB++){
if( zB[nB]&0x80 ) return -2;
}
if( nB>=100000 ) return -4;
/* Special processing if either string is empty */
if( nA==0 ){
@@ -423,7 +419,7 @@ static int editdist1(const char *zA, const char *zB, int *pnMatch){
if( nB<(sizeof(mStack)*4)/(sizeof(mStack[0])*5) ){
m = mStack;
}else{
m = toFree = sqlite3_malloc64( ((i64)nB+1)*5LL*sizeof(m[0])/4 );
m = toFree = sqlite3_malloc64( (nB+1)*5*sizeof(m[0])/4 );
if( m==0 ) return -3;
}
cx = (char*)&m[nB+1];
@@ -531,8 +527,6 @@ static void editdistSqlFunc(
if( res<0 ){
if( res==(-3) ){
sqlite3_result_error_nomem(context);
}else if( res==(-4) ){
sqlite3_result_error_toobig(context);
}else if( res==(-2) ){
sqlite3_result_error(context, "non-ASCII input to editdist()", -1);
}else{
@@ -773,7 +767,7 @@ static int editDist3ConfigLoad(
if( iCost>=10000 ) continue; /* Costs above 10K are considered infinite */
if( pLang==0 || iLang!=iLangPrev ){
EditDist3Lang *pNew;
pNew = sqlite3_realloc64(p->a, ((i64)p->nLang+1)*sizeof(p->a[0]));
pNew = sqlite3_realloc64(p->a, (p->nLang+1)*sizeof(p->a[0]));
if( pNew==0 ){ rc = SQLITE_NOMEM; break; }
p->a = pNew;
pLang = &p->a[p->nLang];
@@ -907,7 +901,7 @@ static EditDist3FromString *editDist3FromStringNew(
if( z==0 ) return 0;
if( n<0 ) n = (int)strlen(z);
pStr = sqlite3_malloc64( sizeof(*pStr) + sizeof(pStr->a[0])*n + (i64)n + 1 );
pStr = sqlite3_malloc64( sizeof(*pStr) + sizeof(pStr->a[0])*n + n + 1 );
if( pStr==0 ) return 0;
pStr->a = (EditDist3From*)&pStr[1];
memset(pStr->a, 0, sizeof(pStr->a[0])*n);
@@ -933,13 +927,13 @@ static EditDist3FromString *editDist3FromStringNew(
if( matchFrom(p, z+i, n-i)==0 ) continue;
if( p->nTo==0 ){
apNew = sqlite3_realloc64(pFrom->apDel,
sizeof(*apNew)*((i64)pFrom->nDel+1));
sizeof(*apNew)*(pFrom->nDel+1));
if( apNew==0 ) break;
pFrom->apDel = apNew;
apNew[pFrom->nDel++] = p;
}else{
apNew = sqlite3_realloc64(pFrom->apSubst,
sizeof(*apNew)*((i64)pFrom->nSubst+1));
sizeof(*apNew)*(pFrom->nSubst+1));
if( apNew==0 ) break;
pFrom->apSubst = apNew;
apNew[pFrom->nSubst++] = p;
@@ -1014,8 +1008,6 @@ static int editDist3Core(
unsigned int stackSpace[SQLITE_SPELLFIX_STACKALLOC_SZ/sizeof(unsigned int)];
/* allocate the Wagner matrix and the aTo[] array for the TO string */
if( n2>10000 ) return -2;
if( f.n>10000 ) return -2;
n = (f.n+1)*(n2+1);
n = (n+1)&~1;
nByte = n*sizeof(m[0]) + sizeof(a2[0])*n2;
@@ -1206,8 +1198,6 @@ static void editDist3SqlFunc(
editDist3FromStringDelete(pFrom);
if( dist==(-1) ){
sqlite3_result_error_nomem(context);
}else if( dist==(-2) ){
sqlite3_result_error_toobig(context);
}else{
sqlite3_result_int(context, dist);
}
@@ -1722,9 +1712,9 @@ static const Transliteration *spellfixFindTranslit(int c, int *pxTop){
*/
static unsigned char *transliterate(const unsigned char *zIn, int nIn){
#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
unsigned char *zOut = sqlite3_malloc64( (i64)nIn*5 + 1 );
unsigned char *zOut = sqlite3_malloc64( nIn*5 + 1 );
#else
unsigned char *zOut = sqlite3_malloc64( (i64)nIn*4 + 1 );
unsigned char *zOut = sqlite3_malloc64( nIn*4 + 1 );
#endif
int c, sz, nOut;
if( zOut==0 ) return 0;
@@ -2067,7 +2057,7 @@ static int spellfix1Init(
int i;
nDbName = (int)strlen(zDbName);
pNew = sqlite3_malloc64( sizeof(*pNew) + (i64)nDbName + 1);
pNew = sqlite3_malloc64( sizeof(*pNew) + nDbName + 1);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -2471,7 +2461,7 @@ static void spellfix1RunQuery(MatchQuery *p, const char *zQuery, int nQuery){
iDist = editdist1(p->zPattern, zK1, 0);
}
if( iDist<0 ){
p->rc = iDist==(-4) ? SQLITE_TOOBIG : SQLITE_NOMEM;
p->rc = SQLITE_NOMEM;
break;
}
pCur->nSearch++;
@@ -2783,7 +2773,7 @@ static int spellfix1Column(
if( !zTranslit ) return SQLITE_NOMEM;
res = editdist1(pCur->zPattern, zTranslit, &iMatchlen);
sqlite3_free(zTranslit);
if( res<0 ) return res==(-4) ? SQLITE_TOOBIG : SQLITE_NOMEM;
if( res<0 ) return SQLITE_NOMEM;
iMatchlen = translen_to_charlen(zWord, nWord, iMatchlen);
}else{
iMatchlen = utf8Charlen(zWord, nWord);
+3 -3
View File
@@ -46,7 +46,7 @@ static void sqlarCompressFunc(
uLongf nOut = compressBound(nData);
Bytef *pOut;
pOut = (Bytef*)sqlite3_malloc64(nOut);
pOut = (Bytef*)sqlite3_malloc(nOut);
if( pOut==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -84,14 +84,14 @@ static void sqlarUncompressFunc(
sqlite3_int64 sz;
assert( argc==2 );
sz = sqlite3_value_int64(argv[1]);
sz = sqlite3_value_int(argv[1]);
if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
sqlite3_result_value(context, argv[0]);
}else{
uLongf szf = sz;
const Bytef *pData= sqlite3_value_blob(argv[0]);
Bytef *pOut = sqlite3_malloc64(sz);
Bytef *pOut = sqlite3_malloc(sz);
if( pOut==0 ){
sqlite3_result_error_nomem(context);
}else if( Z_OK!=uncompress(pOut, &szf, pData, nData) ){
+7 -25
View File
@@ -101,8 +101,8 @@ FILE *sqlite3_fopen(const char *zFilename, const char *zMode){
sz1 = (int)strlen(zFilename);
sz2 = (int)strlen(zMode);
b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) );
b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) );
b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
if( b1 && b2 ){
sz1 = MultiByteToWideChar(CP_UTF8, 0, zFilename, sz1, b1, sz1);
b1[sz1] = 0;
@@ -127,8 +127,8 @@ FILE *sqlite3_popen(const char *zCommand, const char *zMode){
sz1 = (int)strlen(zCommand);
sz2 = (int)strlen(zMode);
b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) );
b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) );
b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
if( b1 && b2 ){
sz1 = MultiByteToWideChar(CP_UTF8, 0, zCommand, sz1, b1, sz1);
b1[sz1] = 0;
@@ -151,7 +151,7 @@ char *sqlite3_fgets(char *buf, int sz, FILE *in){
** that into UTF-8. Otherwise, non-ASCII characters all get translated
** into '?'.
*/
wchar_t *b1 = sqlite3_malloc64( sz*sizeof(wchar_t) );
wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
if( b1==0 ) return 0;
#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
DWORD nRead = 0;
@@ -226,7 +226,7 @@ int sqlite3_fputs(const char *z, FILE *out){
** to the console on Windows.
*/
int sz = (int)strlen(z);
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(wchar_t) );
wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
if( b1==0 ) return 0;
sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
b1[sz] = 0;
@@ -258,7 +258,7 @@ int sqlite3_fputs(const char *z, FILE *out){
/*
** Work-alikes for fprintf() and vfprintf() from the standard C library.
** Work-alike for fprintf() from the standard C library.
*/
int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
int rc;
@@ -285,24 +285,6 @@ int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
}
return rc;
}
int sqlite3_vfprintf(FILE *out, const char *zFormat, va_list ap){
int rc;
if( UseWtextForOutput(out) ){
/* When writing to the command-prompt in Windows, it is necessary
** to use _O_WTEXT input mode and write UTF-16 characters.
*/
char *z;
z = sqlite3_vmprintf(zFormat, ap);
sqlite3_fputs(z, out);
rc = (int)strlen(z);
sqlite3_free(z);
}else{
/* Writing to a file or other destination, just write bytes without
** any translation. */
rc = vfprintf(out, zFormat, ap);
}
return rc;
}
/*
** Set the mode for an output stream. mode argument is typically _O_BINARY or
-3
View File
@@ -31,7 +31,6 @@
#ifdef _WIN32
/**** Definitions For Windows ****/
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
FILE *sqlite3_fopen(const char *zFilename, const char *zMode);
@@ -39,7 +38,6 @@ FILE *sqlite3_popen(const char *zCommand, const char *type);
char *sqlite3_fgets(char *s, int size, FILE *stream);
int sqlite3_fputs(const char *s, FILE *stream);
int sqlite3_fprintf(FILE *stream, const char *format, ...);
int sqlite3_vfprintf(FILE *stream, const char *format, va_list);
void sqlite3_fsetmode(FILE *stream, int mode);
@@ -51,7 +49,6 @@ void sqlite3_fsetmode(FILE *stream, int mode);
#define sqlite3_fgets fgets
#define sqlite3_fputs fputs
#define sqlite3_fprintf fprintf
#define sqlite3_vfprintf vfprintf
#define sqlite3_fsetmode(F,X) /*no-op*/
#endif
+1 -1
View File
@@ -52,7 +52,7 @@ static void stmtrandFunc(
p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
if( p==0 ){
unsigned int seed;
p = sqlite3_malloc64( sizeof(*p) );
p = sqlite3_malloc( sizeof(*p) );
if( p==0 ){
sqlite3_result_error_nomem(context);
return;
+2 -2
View File
@@ -101,7 +101,7 @@ static int templatevtabConnect(
#define TEMPLATEVTAB_A 0
#define TEMPLATEVTAB_B 1
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -123,7 +123,7 @@ static int templatevtabDisconnect(sqlite3_vtab *pVtab){
*/
static int templatevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
templatevtab_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
-1042
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -120,7 +120,6 @@ static int sqlite3UuidStrToBlob(
unsigned char *aBlob /* Write results here */
){
int i;
if( zStr==0 ) return 1;
if( zStr[0]=='{' ) zStr++;
for(i=0; i<16; i++){
if( zStr[0]=='-' ) zStr++;
+2 -2
View File
@@ -613,7 +613,7 @@ static int vstattabConnect(
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
if( rc==SQLITE_OK ){
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
}
@@ -633,7 +633,7 @@ static int vstattabDisconnect(sqlite3_vtab *pVtab){
*/
static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
VfsStatCursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
+1 -1
View File
@@ -892,7 +892,7 @@ static int vfstraceOpen(
vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
pInfo->zVfsName, p->zFName, flags);
if( p->pReal->pMethods ){
sqlite3_io_methods *pNew = sqlite3_malloc64( sizeof(*pNew) );
sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
const sqlite3_io_methods *pSub = p->pReal->pMethods;
memset(pNew, 0, sizeof(*pNew));
pNew->iVersion = pSub->iVersion;
+8 -50
View File
@@ -14,8 +14,6 @@
** on stdout when its key interfaces are called. This is intended for
** interactive analysis and debugging of virtual table interfaces.
**
** HOW TO COMPILE:
**
** To build this extension as a separately loaded shared library or
** DLL, use compiler command-lines similar to the following:
**
@@ -23,7 +21,7 @@
** (mac) clang -fPIC -dynamiclib vtablog.c -o vtablog.dylib
** (windows) cl vtablog.c -link -dll -out:vtablog.dll
**
** USAGE EXAMPLE:
** Usage example:
**
** .load ./vtablog
** CREATE VIRTUAL TABLE temp.log USING vtablog(
@@ -31,23 +29,6 @@
** rows=25
** );
** SELECT * FROM log;
**
** ARGUMENTS TO CREATE VIRTUAL TABLE:
**
** In "CREATE VIRTUAL TABLE temp.log AS vtablog(ARGS....)" statement, the
** ARGS argument is a list of key-value pairs that can be any of the
** following.
**
** schema=TEXT Text is a CREATE TABLE statement that defines
** the schema of the new virtual table.
**
** rows=N The table as N rows.
**
** consume_order_by=N If the left-most ORDER BY terms is ASC and
** against column N (where the leftmost column
** is #1) then set the orderByConsumed=1 flag in
** xBestIndex. Or if the left-most ORDER BY is
** DESC and against column -N, do likewise.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
@@ -68,8 +49,6 @@ struct vtablog_vtab {
char *zName; /* Table name. argv[2] of xConnect/xCreate */
int nRow; /* Number of rows in the table */
int nCursor; /* Number of cursors created */
int iConsumeOB; /* Consume the ORDER BY clause if on column N-th
** and consumeOB=N or consumeOB=(-N) and DESC */
};
/* vtablog_cursor is a subclass of sqlite3_vtab_cursor which will
@@ -201,7 +180,6 @@ static int vtablogConnectCreate(
int rc;
char *zSchema = 0;
char *zNRow = 0;
char *zConsumeOB = 0;
printf("%s.%s.%s():\n", argv[1], argv[2],
isCreate ? "xCreate" : "xConnect");
@@ -225,10 +203,6 @@ static int vtablogConnectCreate(
rc = SQLITE_ERROR;
goto vtablog_end_connect;
}
if( vtablog_string_parameter(pzErr, "consume_order_by", z, &zConsumeOB) ){
rc = SQLITE_ERROR;
goto vtablog_end_connect;
}
}
if( zSchema==0 ){
zSchema = sqlite3_mprintf("%s","CREATE TABLE x(a,b);");
@@ -240,17 +214,13 @@ static int vtablogConnectCreate(
printf(" schema = '%s'\n", zSchema);
rc = sqlite3_declare_vtab(db, zSchema);
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
pNew->nRow = 10;
if( zNRow ) pNew->nRow = atoi(zNRow);
printf(" nrow = %d\n", pNew->nRow);
if( zConsumeOB ) pNew->iConsumeOB = atoi(zConsumeOB);
if( pNew->iConsumeOB ){
printf(" consume_order_by = %d\n", pNew->iConsumeOB);
}
pNew->zDb = sqlite3_mprintf("%s", argv[1]);
pNew->zName = sqlite3_mprintf("%s", argv[2]);
}
@@ -258,7 +228,6 @@ static int vtablogConnectCreate(
vtablog_end_connect:
sqlite3_free(zSchema);
sqlite3_free(zNRow);
sqlite3_free(zConsumeOB);
return rc;
}
static int vtablogCreate(
@@ -313,7 +282,7 @@ static int vtablogOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
vtablog_cursor *pCur;
printf("%s.%s.xOpen(cursor=%d)\n", pTab->zDb, pTab->zName,
++pTab->nCursor);
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->iCursor = pTab->nCursor;
@@ -545,27 +514,16 @@ static int vtablogBestIndex(
}
}
printf(" nOrderBy: %d\n", p->nOrderBy);
if( p->nOrderBy ){
for(i=0; i<p->nOrderBy; i++){
printf(" orderby[%d]: col=%d desc=%d\n",
i,
p->aOrderBy[i].iColumn,
p->aOrderBy[i].desc);
}
if( pTab->iConsumeOB ){
int N = p->aOrderBy[0].iColumn+1;
if( (p->aOrderBy[0].desc && N==-pTab->iConsumeOB)
|| (!p->aOrderBy[0].desc && N==pTab->iConsumeOB)
){
p->orderByConsumed = 1;
}
}
for(i=0; i<p->nOrderBy; i++){
printf(" orderby[%d]: col=%d desc=%d\n",
i,
p->aOrderBy[i].iColumn,
p->aOrderBy[i].desc);
}
p->estimatedCost = (double)500;
p->estimatedRows = 500;
printf(" idxNum=%d\n", p->idxNum);
printf(" idxStr=NULL\n");
printf(" sqlite3_vtab_distinct()=%d\n", sqlite3_vtab_distinct(p));
printf(" orderByConsumed=%d\n", p->orderByConsumed);
printf(" estimatedCost=%g\n", p->estimatedCost);
printf(" estimatedRows=%lld\n", p->estimatedRows);
+5 -5
View File
@@ -86,7 +86,7 @@ static int vtshimCreate(
}
return SQLITE_ERROR;
}
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -125,7 +125,7 @@ static int vtshimConnect(
}
return SQLITE_ERROR;
}
pNew = sqlite3_malloc64( sizeof(*pNew) );
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -192,7 +192,7 @@ static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){
int rc;
*ppCursor = 0;
if( pAux->bDisposed ) return SQLITE_ERROR;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild);
@@ -444,7 +444,7 @@ static int vtshimCopyModule(
){
sqlite3_module *p;
if( !pMod || !ppMod ) return SQLITE_ERROR;
p = sqlite3_malloc64( sizeof(*p) );
p = sqlite3_malloc( sizeof(*p) );
if( p==0 ) return SQLITE_NOMEM;
memcpy(p, pMod, sizeof(*p));
*ppMod = p;
@@ -464,7 +464,7 @@ void *sqlite3_create_disposable_module(
vtshim_aux *pAux;
sqlite3_module *pMod;
int rc;
pAux = sqlite3_malloc64( sizeof(*pAux) );
pAux = sqlite3_malloc( sizeof(*pAux) );
if( pAux==0 ){
if( xDestroy ) xDestroy(pClientData);
return 0;
+4 -11
View File
@@ -13,11 +13,6 @@
** This file implements a virtual table that returns the whole numbers
** between 1 and 4294967295, inclusive.
**
** TESTING AND DEBUG USE ONLY -> This is not production code. This is
** not a deliverable. Use the generate_series() virtual table for
** real-world applications instead of this extension. THIS EXTENSION
** MAY CONTAIN BUGS.
**
** Example:
**
** CREATE VIRTUAL TABLE nums USING wholenumber;
@@ -52,7 +47,7 @@ static int wholenumberConnect(
char **pzErr
){
sqlite3_vtab *pNew;
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
@@ -74,7 +69,7 @@ static int wholenumberDisconnect(sqlite3_vtab *pVtab){
*/
static int wholenumberOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
wholenumber_cursor *pCur;
pCur = sqlite3_malloc64( sizeof(*pCur) );
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
@@ -159,14 +154,12 @@ static int wholenumberFilter(
pCur->iValue = 1;
pCur->mxValue = 0xffffffff; /* 4294967295 */
if( idxNum & 3 ){
v = sqlite3_value_int64(argv[0]);
if( v<=pCur->mxValue && (idxNum&1)!=0 ) v++;
v = sqlite3_value_int64(argv[0]) + (idxNum&1);
if( v>pCur->iValue && v<=pCur->mxValue ) pCur->iValue = v;
i++;
}
if( idxNum & 12 ){
v = sqlite3_value_int64(argv[i]);
if( v>0 && ((idxNum>>2)&1)!=0 ) v--;
v = sqlite3_value_int64(argv[i]) - ((idxNum>>2)&1);
if( v>=pCur->iValue && v<pCur->mxValue ) pCur->mxValue = v;
}
return SQLITE_OK;
+35 -48
View File
@@ -393,7 +393,7 @@ static int zipfileConnect(
rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
if( rc==SQLITE_OK ){
pNew = (ZipfileTab*)sqlite3_malloc64((i64)nByte+nFile);
pNew = (ZipfileTab*)sqlite3_malloc64((sqlite3_int64)nByte+nFile);
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, nByte+nFile);
pNew->db = db;
@@ -456,7 +456,7 @@ static int zipfileDisconnect(sqlite3_vtab *pVtab){
static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
ZipfileTab *pTab = (ZipfileTab*)p;
ZipfileCsr *pCsr;
pCsr = sqlite3_malloc64(sizeof(*pCsr));
pCsr = sqlite3_malloc(sizeof(*pCsr));
*ppCsr = (sqlite3_vtab_cursor*)pCsr;
if( pCsr==0 ){
return SQLITE_NOMEM;
@@ -488,7 +488,6 @@ static void zipfileResetCursor(ZipfileCsr *pCsr){
pNext = p->pNext;
zipfileEntryFree(p);
}
pCsr->pFreeEntry = 0;
}
/*
@@ -540,15 +539,14 @@ static void zipfileCursorErr(ZipfileCsr *pCsr, const char *zFmt, ...){
static int zipfileReadData(
FILE *pFile, /* Read from this file */
u8 *aRead, /* Read into this buffer */
i64 nRead, /* Number of bytes to read */
int nRead, /* Number of bytes to read */
i64 iOff, /* Offset to read from */
char **pzErrmsg /* OUT: Error message (from sqlite3_malloc) */
){
size_t n;
fseek(pFile, (long)iOff, SEEK_SET);
n = fread(aRead, 1, (long)nRead, pFile);
if( n!=(size_t)nRead ){
sqlite3_free(*pzErrmsg);
n = fread(aRead, 1, nRead, pFile);
if( (int)n!=nRead ){
*pzErrmsg = sqlite3_mprintf("error in fread()");
return SQLITE_ERROR;
}
@@ -565,7 +563,7 @@ static int zipfileAppendData(
fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
if( (int)n!=nWrite ){
zipfileTableErr(pTab,"error in fwrite()");
pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
return SQLITE_ERROR;
}
pTab->szCurrent += nWrite;
@@ -706,12 +704,7 @@ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){
u8 *p = aExtra;
u8 *pEnd = &aExtra[nExtra];
/* Stop when there are less than 9 bytes left to scan in the buffer. This
** is because the timestamp field requires exactly 9 bytes - 4 bytes of
** header fields and 5 bytes of data. If there are less than 9 bytes
** remaining, either it is some other field or else the extra data
** is corrupt. Either way, do not process it. */
while( p+(2*sizeof(u16) + 1 + sizeof(u32))<=pEnd ){
while( p<pEnd ){
u16 id = zipfileRead16(p);
u16 nByte = zipfileRead16(p);
@@ -817,7 +810,6 @@ static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){
** generic corruption message and return SQLITE_CORRUPT;
*/
static int zipfileCorrupt(char **pzErr){
sqlite3_free(*pzErr);
*pzErr = sqlite3_mprintf("zip archive is corrupt");
return SQLITE_CORRUPT;
}
@@ -836,7 +828,7 @@ static int zipfileCorrupt(char **pzErr){
static int zipfileGetEntry(
ZipfileTab *pTab, /* Store any error message here */
const u8 *aBlob, /* Pointer to in-memory file image */
i64 nBlob, /* Size of aBlob[] in bytes */
int nBlob, /* Size of aBlob[] in bytes */
FILE *pFile, /* If aBlob==0, read from this file */
i64 iOff, /* Offset of CDS record */
ZipfileEntry **ppEntry /* OUT: Pointer to new object */
@@ -876,14 +868,14 @@ static int zipfileGetEntry(
memset(pNew, 0, sizeof(ZipfileEntry));
rc = zipfileReadCDS(aRead, &pNew->cds);
if( rc!=SQLITE_OK ){
zipfileTableErr(pTab, "failed to read CDS at offset %lld", iOff);
*pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff);
}else if( aBlob==0 ){
rc = zipfileReadData(
pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr
);
}else{
aRead = (u8*)&aBlob[iOff + ZIPFILE_CDS_FIXED_SZ];
if( (iOff + ZIPFILE_CDS_FIXED_SZ + nFile + nExtra)>nBlob ){
if( (iOff + ZIPFILE_LFH_FIXED_SZ + nFile + nExtra)>nBlob ){
rc = zipfileCorrupt(pzErr);
}
}
@@ -891,13 +883,7 @@ static int zipfileGetEntry(
if( rc==SQLITE_OK ){
u32 *pt = &pNew->mUnixTime;
/* aRead[0..nFile-1] might contain embedded \000 characters
** See Bug 2026-05-31T11:43:05Z */
pNew->cds.zFile = sqlite3_malloc64(nFile+1);
if( pNew->cds.zFile!=0 ){
memcpy(pNew->cds.zFile, aRead, nFile);
pNew->cds.zFile[nFile] = 0;
}
pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead);
pNew->aExtra = (u8*)&pNew[1];
memcpy(pNew->aExtra, &aRead[nFile], nExtra);
if( pNew->cds.zFile==0 ){
@@ -914,15 +900,14 @@ static int zipfileGetEntry(
rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr);
}else{
aRead = (u8*)&aBlob[pNew->cds.iOffset];
if( ((i64)pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ)>nBlob ){
if( (pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ)>nBlob ){
rc = zipfileCorrupt(pzErr);
}
}
memset(&lfh, 0, sizeof(lfh));
if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh);
if( rc==SQLITE_OK ){
pNew->iDataOff = (i64)pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
pNew->iDataOff += lfh.nFile + lfh.nExtra;
if( aBlob && pNew->cds.szCompressed ){
if( pNew->iDataOff + pNew->cds.szCompressed > nBlob ){
@@ -933,7 +918,7 @@ static int zipfileGetEntry(
}
}
}else{
zipfileTableErr(pTab, "failed to read LFH at offset %d",
*pzErr = sqlite3_mprintf("failed to read LFH at offset %d",
(int)pNew->cds.iOffset
);
}
@@ -957,7 +942,7 @@ static int zipfileNext(sqlite3_vtab_cursor *cur){
int rc = SQLITE_OK;
if( pCsr->pFile ){
i64 iEof = (i64)pCsr->eocd.iOffset + (i64)pCsr->eocd.nSize;
i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize;
zipfileEntryFree(pCsr->pCurrent);
pCsr->pCurrent = 0;
if( pCsr->iNextOff>=iEof ){
@@ -1002,7 +987,7 @@ static void zipfileInflate(
int nIn, /* Size of buffer aIn[] in bytes */
int nOut /* Expected output size */
){
u8 *aRes = sqlite3_malloc64(nOut);
u8 *aRes = sqlite3_malloc(nOut);
if( aRes==0 ){
sqlite3_result_error_nomem(pCtx);
}else{
@@ -1023,7 +1008,7 @@ static void zipfileInflate(
if( err!=Z_STREAM_END ){
zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err);
}else{
sqlite3_result_blob(pCtx, aRes, (int)str.total_out, zipfileFree);
sqlite3_result_blob(pCtx, aRes, nOut, zipfileFree);
aRes = 0;
}
}
@@ -1195,12 +1180,12 @@ static int zipfileEof(sqlite3_vtab_cursor *cur){
static int zipfileReadEOCD(
ZipfileTab *pTab, /* Return errors here */
const u8 *aBlob, /* Pointer to in-memory file image */
i64 nBlob, /* Size of aBlob[] in bytes */
int nBlob, /* Size of aBlob[] in bytes */
FILE *pFile, /* Read from this file if aBlob==0 */
ZipfileEOCD *pEOCD /* Object to populate */
){
u8 *aRead = pTab->aBuffer; /* Temporary buffer */
i64 nRead; /* Bytes to read from file */
int nRead; /* Bytes to read from file */
int rc = SQLITE_OK;
memset(pEOCD, 0, sizeof(ZipfileEOCD));
@@ -1221,7 +1206,7 @@ static int zipfileReadEOCD(
}
if( rc==SQLITE_OK ){
i64 i;
int i;
/* Scan backwards looking for the signature bytes */
for(i=nRead-20; i>=0; i--){
@@ -1232,7 +1217,9 @@ static int zipfileReadEOCD(
}
}
if( i<0 ){
zipfileTableErr(pTab, "cannot find end of central directory record");
pTab->base.zErrMsg = sqlite3_mprintf(
"cannot find end of central directory record"
);
return SQLITE_ERROR;
}
@@ -1277,7 +1264,7 @@ static void zipfileAddEntry(
}
}
static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, i64 nBlob){
static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, int nBlob){
ZipfileEOCD eocd;
int rc;
int i;
@@ -1325,7 +1312,7 @@ static int zipfileFilter(
}else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
static const u8 aEmptyBlob = 0;
const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
i64 nBlob = sqlite3_value_bytes(argv[0]);
int nBlob = sqlite3_value_bytes(argv[0]);
assert( pTab->pFirstEntry==0 );
if( aBlob==0 ){
aBlob = &aEmptyBlob;
@@ -1399,7 +1386,7 @@ static int zipfileBestIndex(
static ZipfileEntry *zipfileNewEntry(const char *zPath){
ZipfileEntry *pNew;
pNew = sqlite3_malloc64(sizeof(ZipfileEntry));
pNew = sqlite3_malloc(sizeof(ZipfileEntry));
if( pNew ){
memset(pNew, 0, sizeof(ZipfileEntry));
pNew->cds.zFile = sqlite3_mprintf("%s", zPath);
@@ -1523,7 +1510,7 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
assert( pTab->pWriteFd==0 );
if( pTab->zFile==0 || pTab->zFile[0]==0 ){
zipfileTableErr(pTab, "zipfile: missing filename");
pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename");
return SQLITE_ERROR;
}
@@ -1533,9 +1520,9 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
** in main-memory until the transaction is committed. */
pTab->pWriteFd = sqlite3_fopen(pTab->zFile, "ab+");
if( pTab->pWriteFd==0 ){
zipfileTableErr(pTab,
"zipfile: failed to open file %s for writing", pTab->zFile
);
pTab->base.zErrMsg = sqlite3_mprintf(
"zipfile: failed to open file %s for writing", pTab->zFile
);
rc = SQLITE_ERROR;
}else{
fseek(pTab->pWriteFd, 0, SEEK_END);
@@ -2000,11 +1987,11 @@ struct ZipfileCtx {
ZipfileBuffer cds;
};
static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){
if( (pBuf->nAlloc-pBuf->n)<nByte ){
static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){
if( pBuf->n+nByte>pBuf->nAlloc ){
u8 *aNew;
i64 nNew = pBuf->n ? (i64)pBuf->n*2 : 512;
i64 nReq = pBuf->n + nByte;
sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512;
int nReq = pBuf->n + nByte;
while( nNew<nReq ) nNew = nNew*2;
aNew = sqlite3_realloc64(pBuf->a, nNew);
@@ -2049,7 +2036,7 @@ static void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
char *zName = 0; /* Path (name) of new entry */
int nName = 0; /* Size of zName in bytes */
char *zFree = 0; /* Free this before returning */
i64 nByte;
int nByte;
memset(&e, 0, sizeof(e));
p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
-775
View File
@@ -1,775 +0,0 @@
# SQLite Query Result Formatting Subsystem
The "Query Result Formatter" or "QRF" subsystem is a C-language
subroutine that formats the output from an SQLite query for display using
a fix-width font, for example on a terminal window over an SSH connection.
The output format is configurable. The application can request various
table formats, with flexible column widths and alignments, row-oriented
formats, such as CSV and similar, as well as various special purpose formats
like JSON.
For the first 25 years of SQLite's existance, the
[command-line interface](https://sqlite.org/cli.html) (CLI)
formatted query results using a hodge-podge of routines
that had grown slowly by accretion. The QRF was created
in fall of 2025 to refactor and reorganize this code into
a more usable form. The idea behind QRF is to implement all the
query result formatting capabilities of the CLI in a subroutine
that can be incorporated and reused by other applications.
## 1.0 Overview Of Operation
Suppose variable `sqlite3_stmt *pStmt` is a pointer to an SQLite
prepared statement that has been reset and bound and is ready to run.
Then to format the output from this prepared statement, use code
similar to the following:
> ~~~
sqlite3_qrf_spec spec; /* Format specification */
char *zErrMsg; /* Text error message (optional) */
char *zResult = 0; /* Formatted output written here */
int rc; /* Result code */
memset(&spec, 0, sizeof(spec)); /* Initialize the spec */
spec.iVersion = 1; /* Version number must be 1 */
spec.pzOutput = &zResult; /* Write results in variable zResult */
/* Optionally fill in other settings in spec here, as needed */
zErrMsg = 0; /* Not required; just being pedantic */
rc = sqlite3_format_query_result(pStmt, &spec, &zErrMsg); /* Format results */
if( rc ){
printf("Error (%d): %s\n", rc, zErrMsg); /* Report an error */
sqlite3_free(zErrMsg); /* Free the error message text */
}else{
printf("%s", zResult); /* Report the results */
}
sqlite3_free(zResult); /* Free memory used to hold results */
~~~
The `sqlite3_qrf_spec` object describes the desired output format
and where to send the generated output. Most of the work in using
the QRF involves filling out the sqlite3_qrf_spec.
### 1.1 Using QRF with SQL text
If you start with SQL text instead of an sqlite3_stmt pointer, and
especially if the SQL text might comprise two or more statements, then
the SQL text needs to be converted into sqlite3_stmt objects separately.
If the original SQL text is in a variable `const char *zSql` and the
database connection is in variable `sqlite3 *db`, then code
similar to the following should work:
> ~~~
sqlite3_qrf_spec spec; /* Format specification */
char *zErrMsg; /* Text error message (optional) */
char *zResult = 0; /* Formatted output written here */
sqlite3_stmt *pStmt; /* Next prepared statement */
int rc; /* Result code */
memset(&spec, 0, sizeof(spec)); /* Initialize the spec */
spec.iVersion = 1; /* Version number must be 1 */
spec.pzOutput = &zResult; /* Write results in variable zResult */
/* Optionally fill in other settings in spec here, as needed */
zErrMsg = 0; /* Not required; just being pedantic */
while( zSql && zSql[0] ){
pStmt = 0; /* Not required; just being pedantic */
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
if( rc!=SQLITE_OK ){
printf("Error: %s\n", sqlite3_errmsg(db));
}else{
rc = sqlite3_format_query_result(pStmt, &spec, &zErrMsg); /* Get results */
if( rc ){
printf("Error (%d): %s\n", rc, zErrMsg); /* Report an error */
sqlite3_free(zErrMsg); /* Free the error message text */
}else{
printf("%s", zResult); /* Report the results */
sqlite3_free(zResult); /* Free memory used to hold results */
zResult = 0;
}
}
sqlite3_finalize(pStmt);
}
~~~
<a id="spec"></a>
## 2.0 The `sqlite3_qrf_spec` object
The `sqlite3_qrf_spec` looks like this:
> ~~~
typedef struct sqlite3_qrf_spec sqlite3_qrf_spec;
struct sqlite3_qrf_spec {
unsigned char iVersion; /* Version number of this structure */
unsigned char eStyle; /* Formatting style. "box", "csv", etc... */
unsigned char eEsc; /* How to escape control characters in text */
unsigned char eText; /* Quoting style for text */
unsigned char eTitle; /* Quating style for the text of column names */
unsigned char eBlob; /* Quoting style for BLOBs */
unsigned char bTitles; /* True to show column names */
unsigned char bWordWrap; /* Try to wrap on word boundaries */
unsigned char bTextJsonb; /* Render JSONB blobs as JSON text */
unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */
unsigned char eTitleAlign; /* Alignment for column headers */
unsigned char bSplitColumn; /* Wrap single-column output into many columns */
unsigned char bBorder; /* Show outer border in Box and Table styles */
short int nWrap; /* Wrap columns wider than this */
short int nScreenWidth; /* Maximum overall table width */
short int nLineLimit; /* Maximum number of lines for any row */
short int nTitleLimit; /* Maximum number of characters in a title */
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
int nCharLimit; /* Maximum number of characters in a cell */
int nWidth; /* Number of entries in aWidth[] */
int nAlign; /* Number of entries in aAlignment[] */
short int *aWidth; /* Column widths */
unsigned char *aAlign; /* Column alignments */
char *zColumnSep; /* Alternative column separator */
char *zRowSep; /* Alternative row separator */
char *zTableName; /* Output table name */
char *zNull; /* Rendering of NULL */
char *(*xRender)(void*,sqlite3_value*); /* Render a value */
int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */
void *pRenderArg; /* First argument to the xRender callback */
void *pWriteArg; /* First argument to the xWrite callback */
char **pzOutput; /* Storage location for output string */
/* Additional fields may be added in the future */
};
~~~
Do not be alarmed by the complexity of this structure. Everything can
be zeroed except for:
* `.iVersion`
* One of `.pzOutput` or `.xWrite`.
You do not need to understand and configure every field of this object
in order to use QRF effectively. Start by zeroing out the whole structure,
then initializing iVersion and one of pzOutput or xWrite. Then maybe
tweak one or two other settings to get the output you want.
Further detail on the meanings of each of the fields in the
`sqlite3_qrf_spec` object is in the subsequent sections.
### 2.1 Structure Version Number
The sqlite3_qrf_spec.iVersion field must be 1. Future enhancements to
the QRF might add new fields to the bottom of the sqlite3_qrf_spec
object. Those new fields will only be accessible if the iVersion is greater
than 1. Thus the iVersion field is used to support upgradability.
### 2.2 Output Deposition (xWrite and pzOutput)
The formatted output can either be sent to a callback function
or accumulated into an output buffer in memory obtained
from sqlite3_malloc(). If the sqlite3_qrf_spec.xWrite column is not NULL,
then that function is invoked (using sqlite3_qrf_spec.xWriteArg as its
first argument) to transmit the formatted output. Or, if
sqlite3_qrf_spec.pzOutput points to a pointer to a character, then that
pointer is made to point to memory obtained from sqlite3_malloc() that
contains the complete text of the formatted output. If spec.pzOutput\[0\]
is initially non-NULL, then it is assumed to already point to memory obtained
from sqlite3_malloc(). In that case, the buffer is resized using
sqlite3_realloc() and the new text is appended.
One of either sqlite3_qrf_spec.xWrite and sqlite3_qrf_spec.pzOutput must be
non-NULL and the other must be NULL.
The return value from xWrite is an SQLITE result code. The usual return
should be SQLITE_OK. But if for some reason the write fails, a different
value might be returned.
### 2.3 Output Format
The sqlite3_qrf_spec.eStyle field is an integer code that defines the
specific output format that will be generated. See [section 4.0](#style)
below for details on the meaning of the various style options.
Other fields in sqlite3_qrf_spec might be used or might be
ignored, depending on the value of eStyle.
### 2.4 Show Column Names (bTitles)
The sqlite3_qrf_spec.bTitles field can be either QRF_SW_Auto,
QRF_SW_On, or QRF_SW_Off. Those three constants also have shorter
alternative spellings: QRF_Auto, QRF_No, and
QRF_Yes.
> ~~~
#define QRF_SW_Auto 0 /* Let QRF choose the best value */
#define QRF_SW_Off 1 /* This setting is forced off */
#define QRF_SW_On 2 /* This setting is forced on */
#define QRF_Auto 0 /* Alternate spelling for QRF_SW_Auto and others */
#define QRF_No 1 /* Alternate spelling for QRF_SW_Off */
#define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */
~~~
If the value is QRF_Yes, then column names appear in the output.
If the value is QRF_No, column names are omitted. If the
value is QRF_Auto, then an appropriate default is chosen.
### 2.5 Control Character Escapes (eEsc)
The sqlite3_qrf_spec.eEsc determines how ASCII control characters are
formatted when displaying TEXT values in the result. These are the allowed
values:
> ~~~
#define QRF_ESC_Auto 0 /* Choose the ctrl-char escape automatically */
#define QRF_ESC_Off 1 /* Do not escape control characters */
#define QRF_ESC_Ascii 2 /* Unix-style escapes. Ex: U+0007 shows ^G */
#define QRF_ESC_Symbol 3 /* Unicode escapes. Ex: U+0007 shows U+2407 */
~~~
If the value of eEsc is QRF_ESC_Ascii, then the control character
with value X is displayed as ^Y where Y is X+0x40. Hence, a
backspace character (U+0008) is shown as "^H".
If eEsc is QRF_ESC_Symbol, then control characters in the range of U+0001
through U+001f are mapped into U+2401 through U+241f, respectively.
If the value of eEsc is QRF_ESC_Off, then no translation occurs
and control characters that appear in TEXT strings are transmitted
to the formatted output as-is. This can be dangerous in applications,
since an adversary who can control TEXT values might be able to
inject ANSI cursor movement sequences to hide nefarious values.
The QRF_ESC_Auto value for eEsc means that the query result formatter
gets to pick whichever control-character encoding it thinks is best for
the situation. This will usually be QRF_ESC_Ascii.
The TAB (U+0009), LF (U+000a) and CR-LF (U+000d,U+000a) character
sequence are always output literally and are not mapped to alternative
display values, regardless of this setting.
### 2.6 Display of TEXT values (eText, eTitle)
The sqlite3_qrf_spec.eText controls how text values are rendered in the
display. sqlite3_qrf_spec.eTitle controls how column names are rendered.
Both fields can have one of the following values:
> ~~~
#define QRF_TEXT_Auto 0 /* Choose text encoding automatically */
#define QRF_TEXT_Plain 1 /* Literal text */
#define QRF_TEXT_Sql 2 /* Quote as an SQL literal */
#define QRF_TEXT_Csv 3 /* CSV-style quoting */
#define QRF_TEXT_Html 4 /* HTML-style quoting */
#define QRF_TEXT_Tcl 5 /* C/Tcl quoting */
#define QRF_TEXT_Json 6 /* JSON quoting */
#define QRF_TEXT_Relaxed 7 /* Relaxed SQL quoting */
~~~
A value of QRF_TEXT_Auto means that the query result formatter will choose
what it thinks will be the best text encoding.
A value of QRF_TEXT_Plain means that text values appear in the output exactly
as they are found in the database file, with no translation.
A value of QRF_TEXT_Sql means that text values are escaped so that they
look like SQL literals. That means the value will be surrounded by
single-quotes (U+0027) and any single-quotes contained within the text
will be doubled.
QRF_TEXT_Relaxed is similar to QRF_TEXT_Sql, except that it automatically
reverts to QRF_TEXT_Plain if the value to be displayed does not contain
special characters and is not easily confused with a NULL or a numeric
value. QRF_TEXT_Relaxed strives to minimize the amount of quoting syntax
while keeping the result unambiguous and easy for humans to read. The
precise rules for when quoting is omitted in QRF_TEXT_Relaxed, and when
it is applied, might be adjusted in future releases.
A value of QRF_TEXT_Csv means that text values are escaped in accordance
with RFC&nbsp;4180, which defines Comma-Separated-Value or CSV files.
Text strings that contain no special values appears as-is. Text strings
that contain special values are contained in double-quotes (U+0022) and
any double-quotes within the value are doubled.
A value of QRF_TEXT_Html means that text values are escaped for use in
HTML. Special characters "&lt;", "&amp;", "&gt;", "&quot;", and "&#39;"
are displayed as "&amp;lt;", "&amp;amp;", "&amp;gt;", "&amp;quot;",
and "&amp;#39;", respectively.
A value of QRF_TEXT_Tcl means that text values are displayed inside of
double-quotes and special characters within the string are escaped using
backslash escape, as in ANSI-C or TCL or Perl or other popular programming
languages.
A value of QRF_TEXT_Json gives similar results as QRF_TEXT_Tcl except that the
rules are adjusted so that the displayed string is strictly conforming
the JSON specification.
### 2.7 How to display BLOB values (eBlob and bTextJsonb)
If the sqlite3_qrf_spec.bTextJsonb flag is QRF_SW_On and if the value to be
displayed is JSONB, then the JSONB is translated into text JSON and the
text is shown according to the sqlite3_qrf_spec.eText setting as
described in the previous section.
If the bTextJsonb flag is QRF_SW_Off (the usual case) or if the BLOB value to
be displayed is not JSONB, then the sqlite3_qrf_spec.eBlob field determines
how the BLOB value is formatted. The following options are available;
> ~~~
#define QRF_BLOB_Auto 0 /* Determine BLOB quoting using eText */
#define QRF_BLOB_Text 1 /* Display content exactly as it is */
#define QRF_BLOB_Sql 2 /* Quote as an SQL literal */
#define QRF_BLOB_Hex 3 /* Hexadecimal representation */
#define QRF_BLOB_Tcl 4 /* "\000" notation */
#define QRF_BLOB_Json 5 /* A JSON string */
#define QRF_BLOB_Size 6 /* Display the blob size only */
~~~
A value of QRF_BLOB_Auto means that display format is selected automatically
by sqlite3_format_query_result() based on eStyle and eText.
A value of QRF_BLOB_Text means that BLOB values are interpreted as UTF8
text and are displayed using formatting results set by eEsc and
eText.
A value of QRF_BLOB_Sql means that BLOB values are shown as SQL BLOB
literals: a prefix "`x'`" following by hexadecimal and ending with a
final "`'`".
A value of QRF_BLOB_Hex means that BLOB values are shown as
hexadecimal text with no delimiters.
A value of QRF_BLOB_Tcl means that BLOB values are shown as a
C/Tcl/Perl string literal where every byte is an octal backslash
escape. So a BLOB of `x'052881f3'` would be displayed as
`"\005\050\201\363"`.
A value of QRF_BLOB_Json is similar to QRF_BLOB_Tcl except that is
uses unicode backslash escapes, since JSON does not understand
the C/Tcl/Perl octal backslash escapes. So the string from the
previous paragraph would be shown as
`"\u0005\u0028\u0081\u00f3"`.
A value of QRF_BLOB_Size does not show any BLOB content at all.
Instead, it substitutes a text string that says how many bytes
the BLOB contains.
### 2.8 Maximum size of displayed content (nLineLimit, nCharLimit, nTitleLimit)
If the sqlite3_qrf_spec.nCharLimit setting is non-zero, then the formatter
will display only the first nCharLimit characters of each value.
Only characters that take up space are counted when enforcing this
limit. Zero-width characters and VT100 escape sequences do not count
toward this limit. The count is in characters, not bytes. When
imposing this limit, the formatter adds the three characters "..."
to the end of the value. Those added characters are not counted
as part of the limit. Very small limits still result in truncation,
but might render a few more characters than the limit.
If the sqlite3_qrf_spec.nLineLimit setting is non-zero, then the
formatter will only display the first nLineLimit lines of each value.
It does not matter if the value is split because it contains a newline
character, or if it split by wrapping. This setting merely limits
the number of displayed lines. The nLineLimit setting currently only
works for **Box**, **Column**, **Line**, **Markdown**, and **Table**
styles, though that limitation might change in future releases.
The idea behind both of these settings is to prevent large renderings
when doing a query that (unexpectedly) contains very large text or
blob values: perhaps megabyes of text.
If the sqlite3_qrf_spec.nTitleLimit is non-zero, then the formatter
attempts to limits the size of column titles to at most nTitleLimit
display characters in width and a single line of text. The nTitleLimit
is useful for queries that have result columns that are scalar
subqueries or complex expressions. If those columns lack an AS
clause, then the name of the column will be a copy of the expression
that defines the column, which in some queries can be hundreds of
characters and multiple lines in length, which can reduce the readability
of tabular displays. An nTitleLimit somewhere in the range of 10 to 20.
can improve readability. The nTitleLimit setting currently only
works for **Box**, **Column**, **Line**, **Markdown**, and **Table**
styles, though that limitation might change in future releases.
### 2.9 Multiple Tuples Per INSERT In QRF_STYLE_Insert (nMultiInsert)
If the sqlite3_qrf_spec.nMultiInsert value is positive, then the
QRF_STYLE_Insert output mode will generate multiple tuples in
each INSERT statement until the total number of bytes in the
statement exceeds nMultiInsert. A value of a few thousand is
recommended here, in order to generate SQL output that is parsed
and inserted at maximum speed by SQLite.
### 2.10 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
When using columnar formatting modes (QRF_STYLE_Box, QRF_STYLE_Column,
QRF_STYLE_Markdown, or QRF_STYLE_Table), the formatter attempts to limit
the width of any individual column to sqlite3_qrf_spec.nWrap characters
if nWrap is non-zero. A zero value for nWrap means "unlimited".
The nWrap limit might be exceeded if the limit is very small.
In order to keep individual columns within requested width limits,
it is sometimes necessary to wrap the content for a single row of
a single column across multiple lines. When this
becomes necessary and if the bWordWrap setting is QRF_Yes, then the
formatter attempts to split the content on whitespace or at a word boundary.
If bWordWrap is QRF_No, then the formatter is free to split content
anywhere, including in the middle of a word.
For narrow columns and wide words, it might sometimes be necessary to split
a column in the middle of a word, even when bWordWrap is QRF_Yes.
### 2.11 Helping The Output To Fit On The Terminal (nScreenWidth)
The sqlite3_qrf_spec.nScreenWidth field can be set the number of
characters that will fit on one line on the viewer output device.
This is typically a number like 80 or 132. The formatter will attempt
to reduce the length of output lines, depending on the style, so
that all output fits on that screen.
A value of zero for nScreenWidth means "unknown" or "no width limit".
When the value is zero, the formatter makes no attempt to keep the
lines of output short.
The nScreenWidth is a hint to the formatter, not a requirement.
The formatter trieds to keep lines below the nScreenWidth limit,
but it does not guarantee that it will.
The nScreenWidth field currently only makes a difference in
columnar styles (**Box**, **Column**, **Markdown**, and **Table**)
and in the **Line** style.
### 2.12 Individual Column Width (nWidth and aWidth)
The sqlite3_qrf_spec.aWidth field is a pointer to an array of
signed 16-bit integers that control the width of individual columns
in columnar output modes (QRF_STYLE_Box, QRF_STYLE_Column,
QRF_STYLE_Markdown, or QRF_STYLE_Table). The sqlite3_qrf_spec.nWidth
field is the number of integers in the aWidth array.
If aWidth is a NULL pointer or if nWidth is zero, then the array is
assumed to be all zeros. If nWidth is less then the number of
columns in the output, then zero is used for the width
for all columns past then end of the aWidth array.
The aWidth array is deliberately an array of 16-bit signed integers.
Only 16 bits are used because no good comes for having very large
column widths. The range if further restricted as follows:
> ~~~
#define QRF_MAX_WIDTH 10000 /* Maximum column width */
#define QRF_MIN_WIDTH 0 /* Minimum column width */
~~~
A width greater than then QRF_MAX_WIDTH is interpreted as QRF_MAX_WIDTH.
Any aWidth\[\] value of zero means the formatter should use a flexible
width column (limited only by sqlite_qrf_spec.mxWidth) that is just
big enough to hold the largest row.
For historical compatibility, aWidth\[\] can contain negative values,
down to -QRF_MAX_WIDTH. The column width used is the absolute value
of the number in aWidth\[\]. The only difference is that negative
values cause the default horizontal alignment to be QRF_ALIGN_Right.
The sign of the aWidth\[\] values only affects alignment if the
alignment is not otherwise specified by aAlign\[\] or eDfltAlign.
Again, negative values for aWidth\[\] entries are supported for
backwards compatibility only, and are not recommended for new
applications.
### 2.13 Alignment (nAlignment, aAlignment, eDfltAlign, eTitleAlign)
Some cells in a display table might contain a lot of text and thus
be wide, or they might contain newline characters or be wrapped by
width constraints so that they span many rows of text. Other cells
might be narrower and shorter. In columnar formats, the display width
of a cell is the maximum of the widest value in the same column, and the
display height is the height of the tallest value in the same row.
So some cells might be much taller and wider than necessary to hold
their values.
Alignment determines where smaller values are placed within larger cells.
The sqlite3_qrf_spec.aAlign field points to an array of unsigned characters
that specifies alignment (both vertical and horizontal) of individual
columns within the table. The sqlite3_qrf_spec.nAlign fields holds
the number of entries in the aAlign\[\] array.
If sqlite3_qrf_spec.aAlign is a NULL pointer or if sqlite3_qrf_spec.nAlign
is zero, or for columns to the right of what are specified by
sqlite3_qrf_spec.nAlign, the sqlite3_qrf_spec.eDfltAlign value is used
for the alignment. Column names can be (and often are) aligned
differently, as specified by sqlite3_qrf_spec.eTitleAlign.
Each alignment value specifies both vertical and horizontal alignment.
Horizontal alignment can be left, center, right, or no preference.
Vertical alignment can be top, middle, bottom, or no preference.
Thus there are 16 possible alignment values, as follows:
> ~~~
/*
** Horizontal Vertial
** ---------- -------- */
#define QRF_ALIGN_Auto 0 /* auto auto */
#define QRF_ALIGN_Left 1 /* left auto */
#define QRF_ALIGN_Center 2 /* center auto */
#define QRF_ALIGN_Right 3 /* right auto */
#define QRF_ALIGN_Top 4 /* auto top */
#define QRF_ALIGN_NW 5 /* left top */
#define QRF_ALIGN_N 6 /* center top */
#define QRF_ALIGN_NE 7 /* right top */
#define QRF_ALIGN_Middle 8 /* auto middle */
#define QRF_ALIGN_W 9 /* left middle */
#define QRF_ALIGN_C 10 /* center middle */
#define QRF_ALIGN_E 11 /* right middle */
#define QRF_ALIGN_Bottom 12 /* auto bottom */
#define QRF_ALIGN_SW 13 /* left bottom */
#define QRF_ALIGN_S 14 /* center bottom */
#define QRF_ALIGN_SE 15 /* right bottom */
~~~
Notice how alignment values with an unspecified horizontal
or vertical component can be added to another alignment value
for which that component is specified, to get a fully
specified alignment. For eample:
> QRF_ALIGN_Center + QRF_ALIGN_Bottom == QRF_ALIGN_S.
The alignment for column names is always determined by the
eTitleAlign setting. If eTitleAlign is QRF_Auto, then column
names use center-bottom alignment, QRF_ALIGN_W, value 14.
The aAlign\[\] and eDfltAlign settings have no affect on
column names.
For data in the first nAlign columns, the aAlign\[\] array
entry for that column takes precedence. If either the horizontal
or vertical alignment has an "auto" value for that column or if
a column is beyond the first nAlign entries, then eDfltAlign
is used as a backup. If neither aAlign\[\] nor eDfltAlign
specify a horizontal alignment, then values are right-aligned
(QRF_ALIGN_Right) if they are numeric and left-aligned
(QRF_ALIGN_Left) otherwise. If neither aAlign\[\] nor eDfltAlign
specify a vertical alignment, then values are top-aligned
(QRF_ALIGN_Top).
*As of 2025-11-08, only horizontal alignment is implemented.
The vertical alignment settings are currently ignored and
the vertical alignment is always QRF_ALIGN_Top.*
### 2.14 Row and Column Separator Strings
The sqlite3_qrf_spec.zColumnSep and sqlite3_qrf_spec.zRowSep strings
are alternative column and row separator character sequences. If not
specified (if these pointers are left as NULL) then appropriate defaults
are used. Some output styles have hard-coded column and row separators
and these settings are ignored for those styles.
### 2.15 The Output Table Name
The sqlite3_qrf_spec.zTableName value is the name of the output table
when eStyle is QRF_STYLE_Insert.
### 2.16 The Rendering Of NULL (zNull)
If a value is NULL then show the NULL using the string
found in sqlite3_qrf_spec.zNull. If zNull is itself a NULL pointer
then NULL values are rendered as an empty string.
### 2.17 Optional Value Rendering Callback
If the sqlite3_qrf_spec.xRender field is not NULL, then each
sqlite3_value coming out of the query is first passed to the
xRender function, giving that function an opportunity to render
the results itself, using whatever custom format is desired.
If xRender chooses to render, it should write the rendering
into memory obtained from sqlite3_malloc() and return a pointer
to that memory. The xRender function can decline
to render (for example, based on the sqlite3_value_type() or other
characteristics of the value) in which case it can simply return a
NULL pointer and the usual default rendering will be used instead.
The sqlite3_format_query_result() function (which calls xRender)
will take responsibility for freeing the string returned by xRender
after it has finished using it.
The eText, eBlob, and eEsc settings above become no-ops if the xRender
routine returns non-NULL. In other words, the application-supplied
xRender routine is expected to do all of its own quoting and formatting.
The xRender routine is expected to do character length limiting itself.
So the nCharLimit setting becomes a no-op if xRender is used. However
the nLineLimit setting is still applied. The nTitleLimit setting is
not applicable to xRender because title values come from the
sqlite3_column_name() interface not from sqlite3_column_value(),
and so that names of columns are never processed by xRender.
## 3.0 The `sqlite3_format_query_result()` Interface
Invoke the `sqlite3_format_query_result(P,S,E)` interface to run
the prepared statement P and format its results according to the
specification found in S. The sqlite3_format_query_result() function
will return an SQLite result code, usually SQLITE_OK, but perhaps
SQLITE_NOMEM or SQLITE_ERROR or similar. If an error occurs and if
the E parameter is not NULL, then error message text might be written
into *E. Any error message text will be stored in memory obtained
from sqlite3_malloc() and it is the responsibility of the caller to
free that memory by a subsequent call to sqlite3_free().
<a id="style"></a>
## 4.0 Output Styles
The result formatter supports a variety of output styles. The
output style (sometimes called "output mode") is determined by
the eStyle field of the sqlite3_qrf_spec object. The set of
supported output modes might increase in future versions.
The following output modes are currently defined:
> ~~~
#define QRF_STYLE_Auto 0 /* Choose a style automatically */
#define QRF_STYLE_Box 1 /* Unicode box-drawing characters */
#define QRF_STYLE_Column 2 /* One record per line in neat columns */
#define QRF_STYLE_Count 3 /* Output only a count of the rows of output */
#define QRF_STYLE_Csv 4 /* Comma-separated-value */
#define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */
#define QRF_STYLE_Explain 6 /* EXPLAIN output */
#define QRF_STYLE_Html 7 /* Generate an XHTML table */
#define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */
#define QRF_STYLE_Json 9 /* Output is a list of JSON objects */
#define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */
#define QRF_STYLE_Line 11 /* One column per line. */
#define QRF_STYLE_List 12 /* One record per line with a separator */
#define QRF_STYLE_Markdown 13 /* Markdown formatting */
#define QRF_STYLE_Off 14 /* No query output shown */
#define QRF_STYLE_Quote 15 /* SQL-quoted, comma-separated */
#define QRF_STYLE_Stats 16 /* EQP-like output but with performance stats */
#define QRF_STYLE_StatsEst 17 /* EQP-like output with planner estimates */
#define QRF_STYLE_StatsVm 18 /* EXPLAIN-like output with performance stats */
#define QRF_STYLE_Table 19 /* MySQL-style table formatting */
~~~
In the following subsections, these styles will often be referred
to without the "QRF_STYLE_" prefix.
### 4.1 Default Style (Auto)
The **Auto** style means QRF gets to choose an appropriate output
style. It will usually choose **Box**, but might also pick one of
**Explain** or **Eqp** if the `sqlite3_stmt_explain()` function
returns 1 or 2, respectively.
### 4.2 Columnar Styles (Box, Column, Markdown, Table)
The **Box**, **Column**, **Markdown**, and **Table**
modes are columnar. This means the output is arranged into neat,
uniform-width columns. These styles can use more memory, especially when
the query result has many rows, because they need to load the entire output
into memory first in order to determine how wide to make each column.
The nWidth, aWidth, and mxWidth fields of the `sqlite3_qrf_spec` object
are used by these styles only, and are ignored by all other styles.
The zRowSep and zColumnSep settings are ignored by these styles. The
bTitles setting is honored by these styles; it defaults to QRF_SW_On.
The **Box** style uses Unicode box-drawing character to draw a grid
of columns and rows to show the result. The **Table** is the same,
except that it uses ASCII-art rather than Unicode box-drawing characters
to draw the grid. The **Column** arranges the results in neat columns
but does not draw in column or row separator, except that it does draw
lines horizontal lines using "`-`" characters to separate the column names
from the data below. This is very similar to default output styling in
psql. The **Markdown** renders its result in the Markdown table format.
The **Box** and **Table** styles normally have a border that surrounds
the entire result. However, if sqlite3_qrf_spec.bBorder is QRF_No, then
that border is omitted, saving a little space both horizontally and
vertically.
#### 4.2.1 Split Column Mode
If the bSplitColumn field is QRF_Yes, and eStyle is QRF_STYLE_Column,
and bTitles is QRF_No, and nScreenWidth is greater than zero, and if
the query only returns a single column, then a special rendering known
as "Split Column Mode" will be used. In split column mode, instead
of showing all results in one tall column, the content wraps vertically
so that it appears on the screen as multiple columns, as many as will
fit in the available screen width.
### 4.3 Line-oriented Styles
The line-oriented styles output each row of result as it is received from
the prepared statement.
The **List** style is the most familiar line-oriented output format.
The **List** style shows output columns for each row on the
same line, each separated by a single "`|`" character and with lines
terminated by a single newline (\\u000a or \\n). These column
and row separator choices can be overridden using the zColumnSep
and zRowSep fields of the `sqlite3_qrf_spec` structure. The text
formatting is QRF_TEXT_Plain, and BLOB encoding is QRF_BLOB_Text. So
characters appear in the output exactly as they appear in the database.
Except the eEsp mode defaults to `QRF_ESC_On`, so that control
characters are escaped, for safety.
The **Csv** and **Quote** styles are simply variations on **List**
with hard-coded values for some of the sqlite3_qrf_spec settings:
<table border=1 cellpadding=2 cellspacing=0>
<tr><th>&nbsp;<th>Quote<th>Csv
<tr><td>zColumnSep<td>","<td>","
<tr><td>zRowSep<td>"\\n"<td>"\\r\\n"
<tr><td>zNull<td>"NULL"<td>""
<tr><td>eText<td>QRF_TEXT_Sql<td>QRF_TEXT_Csv
<tr><td>eBlob<td>QRF_BLOB_Sql<td>QRF_BLOB_Text
</table>
The **Html** style generates HTML table content, just without
the `<TABLE>..</TABLE>` around the outside.
The **Insert** style generates a series of SQL "INSERT" statements
that will inserts the data that is output into a table whose name is defined
by the zTableName field of `sqlite3_qrf_spec`. If zTableName is NULL,
then a substitute name is used. If nMultiInsert is positive, then the
output will add multiple rows to each INSERT statement until the size
of the INSERT statement exceeds nMultiInsert bytes before starting
a new INSERT statement.
The **Json** and **JObject** styles generates JSON text for the query result.
The **Json** style produces a JSON array of structures with one
structure per row. **JObject** outputs independent JSON objects, one per
row, with each structure on a separate line all by itself, and not
part of a larger array. In both cases, the labels on the elements of the
JSON objects are taken from the column names of the SQL query. So if
you have an SQL query that has two or more output columns with the same
name, you will end up with JSON structures that have duplicate elements.
Finally, the **Line** style paints each column of a row on a
separate line with the column name on the left and a "`=`" separating the
column name from its value. A single blank line appears between rows.
### 4.4 EXPLAIN Styles (Eqp, Explain)
The **Eqp** and **Explain** styles format output for
EXPLAIN QUERY PLAN and EXPLAIN statements, respectively. If the input
statement is not already an EXPLAIN QUERY PLAN or EXPLAIN statement is
is temporarily converted for the duration of the rendering, but
is converted back before `sqlite3_format_query_result()` returns.
### 4.5 ScanStatus Styles (Stats, StatsEst, StatsVm)
The **Stats**, **StatsEst**, and **StatsVm** styles are similar to **Eqp**
and **Explain** except that they include profiling information
from prior executions of the input prepared statement.
These modes only work if SQLite has been compiled with
-DSQLITE_ENABLE_STMT_SCANSTATUS and if the SQLITE_DBCONFIG_STMT_SCANSTATUS
is enabled for the database connection. The **StatsVm** style
also requires the bytecode() virtual table which is enabled using
the -DSQLITE_ENABLE_BYTECODE_VTAB compile-time option.
### 4.6 Other Styles (Count, Off)
The **Count** style discards all query results and returns
a count of the number of rows of output at the end. The **Off**
style is completely silent; it generates no output. These corner-case
modes are sometimes useful for debugging.
### 5.0 Source Code Files
The SQLite Query Result Formatter is implemented in three source code files:
* `qrf.c` &rarr; The implementation, written in portable C99
* `qrf.h` &rarr; A header file defining interfaces
* `README.md` &rarr; This documentation
To use the SQLite result formatter, include the "`qrf.h`" header file
and link the application against the "`qrf.c`" source file.
-14
View File
@@ -1,14 +0,0 @@
# Developer Notes
## Measuring Test Coverage On Linux
On Mint Linux, as of 2025-12-02:
> ~~~
./configure --dev CFLAGS='-O0 -g -fprofile-arcs -ftest-coverage'
make clean testfixture
./testfixture test/qrf*.test
gcov -b -c testfixture-tclsqlite-ex.c
~~~
View results in tclsqlite-ex.c.gcov
-3029
View File
File diff suppressed because it is too large Load Diff
-200
View File
@@ -1,200 +0,0 @@
/*
** 2025-10-20
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Header file for the Query Result-Format or "qrf" utility library for
** SQLite. See the README.md documentation for additional information.
*/
#ifndef SQLITE_QRF_H
#define SQLITE_QRF_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include "sqlite3.h"
/*
** Specification used by clients to define the output format they want
*/
typedef struct sqlite3_qrf_spec sqlite3_qrf_spec;
struct sqlite3_qrf_spec {
unsigned char iVersion; /* Version number of this structure */
unsigned char eStyle; /* Formatting style. "box", "csv", etc... */
unsigned char eEsc; /* How to escape control characters in text */
unsigned char eText; /* Quoting style for text */
unsigned char eTitle; /* Quating style for the text of column names */
unsigned char eBlob; /* Quoting style for BLOBs */
unsigned char bTitles; /* True to show column names */
unsigned char bWordWrap; /* Try to wrap on word boundaries */
unsigned char bTextJsonb; /* Render JSONB blobs as JSON text */
unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */
unsigned char eTitleAlign; /* Alignment for column headers */
unsigned char bSplitColumn; /* Wrap single-column output into many columns */
unsigned char bBorder; /* Show outer border in Box and Table styles */
short int nWrap; /* Wrap columns wider than this */
short int nScreenWidth; /* Maximum overall table width */
short int nLineLimit; /* Maximum number of lines for any row */
short int nTitleLimit; /* Maximum number of characters in a title */
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
int nCharLimit; /* Maximum number of characters in a cell */
int nWidth; /* Number of entries in aWidth[] */
int nAlign; /* Number of entries in aAlignment[] */
short int *aWidth; /* Column widths */
unsigned char *aAlign; /* Column alignments */
char *zColumnSep; /* Alternative column separator */
char *zRowSep; /* Alternative row separator */
char *zTableName; /* Output table name */
char *zNull; /* Rendering of NULL */
char *(*xRender)(void*,sqlite3_value*); /* Render a value */
int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */
void *pRenderArg; /* First argument to the xRender callback */
void *pWriteArg; /* First argument to the xWrite callback */
char **pzOutput; /* Storage location for output string */
/* Additional fields may be added in the future */
};
/*
** Interfaces
*/
int sqlite3_format_query_result(
sqlite3_stmt *pStmt, /* SQL statement to run */
const sqlite3_qrf_spec *pSpec, /* Result format specification */
char **pzErr /* OUT: Write error message here */
);
/*
** Range of values for sqlite3_qrf_spec.aWidth[] entries.
*/
#define QRF_MAX_WIDTH 10000
#define QRF_MIN_WIDTH 0
/*
** Output styles:
*/
#define QRF_STYLE_Auto 0 /* Choose a style automatically */
#define QRF_STYLE_Box 1 /* Unicode box-drawing characters */
#define QRF_STYLE_Column 2 /* One record per line in neat columns */
#define QRF_STYLE_Count 3 /* Output only a count of the rows of output */
#define QRF_STYLE_Csv 4 /* Comma-separated-value */
#define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */
#define QRF_STYLE_Explain 6 /* EXPLAIN output */
#define QRF_STYLE_Html 7 /* Generate an XHTML table */
#define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */
#define QRF_STYLE_Json 9 /* Output is a list of JSON objects */
#define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */
#define QRF_STYLE_Line 11 /* One column per line. */
#define QRF_STYLE_List 12 /* One record per line with a separator */
#define QRF_STYLE_Markdown 13 /* Markdown formatting */
#define QRF_STYLE_Off 14 /* No query output shown */
#define QRF_STYLE_Quote 15 /* SQL-quoted, comma-separated */
#define QRF_STYLE_Stats 16 /* EQP-like output but with performance stats */
#define QRF_STYLE_StatsEst 17 /* EQP-like output with planner estimates */
#define QRF_STYLE_StatsVm 18 /* EXPLAIN-like output with performance stats */
#define QRF_STYLE_Table 19 /* MySQL-style table formatting */
/*
** Quoting styles for text.
** Allowed values for sqlite3_qrf_spec.eText
*/
#define QRF_TEXT_Auto 0 /* Choose text encoding automatically */
#define QRF_TEXT_Plain 1 /* Literal text */
#define QRF_TEXT_Sql 2 /* Quote as an SQL literal */
#define QRF_TEXT_Csv 3 /* CSV-style quoting */
#define QRF_TEXT_Html 4 /* HTML-style quoting */
#define QRF_TEXT_Tcl 5 /* C/Tcl quoting */
#define QRF_TEXT_Json 6 /* JSON quoting */
#define QRF_TEXT_Relaxed 7 /* Relaxed SQL quoting */
/*
** Quoting styles for BLOBs
** Allowed values for sqlite3_qrf_spec.eBlob
*/
#define QRF_BLOB_Auto 0 /* Determine BLOB quoting using eText */
#define QRF_BLOB_Text 1 /* Display content exactly as it is */
#define QRF_BLOB_Sql 2 /* Quote as an SQL literal */
#define QRF_BLOB_Hex 3 /* Hexadecimal representation */
#define QRF_BLOB_Tcl 4 /* "\000" notation */
#define QRF_BLOB_Json 5 /* A JSON string */
#define QRF_BLOB_Size 6 /* Display the blob size only */
/*
** Control-character escape modes.
** Allowed values for sqlite3_qrf_spec.eEsc
*/
#define QRF_ESC_Auto 0 /* Choose the ctrl-char escape automatically */
#define QRF_ESC_Off 1 /* Do not escape control characters */
#define QRF_ESC_Ascii 2 /* Unix-style escapes. Ex: U+0007 shows ^G */
#define QRF_ESC_Symbol 3 /* Unicode escapes. Ex: U+0007 shows U+2407 */
/*
** Allowed values for "boolean" fields, such as "bColumnNames", "bWordWrap",
** and "bTextJsonb". There is an extra "auto" variants so these are actually
** tri-state settings, not booleans.
*/
#define QRF_SW_Auto 0 /* Let QRF choose the best value */
#define QRF_SW_Off 1 /* This setting is forced off */
#define QRF_SW_On 2 /* This setting is forced on */
#define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */
#define QRF_No 1 /* Alternate spelling for QRF_SW_Off */
#define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */
/*
** Possible alignment values alignment settings
**
** Horizontal Vertial
** ---------- -------- */
#define QRF_ALIGN_Auto 0 /* auto auto */
#define QRF_ALIGN_Left 1 /* left auto */
#define QRF_ALIGN_Center 2 /* center auto */
#define QRF_ALIGN_Right 3 /* right auto */
#define QRF_ALIGN_Top 4 /* auto top */
#define QRF_ALIGN_NW 5 /* left top */
#define QRF_ALIGN_N 6 /* center top */
#define QRF_ALIGN_NE 7 /* right top */
#define QRF_ALIGN_Middle 8 /* auto middle */
#define QRF_ALIGN_W 9 /* left middle */
#define QRF_ALIGN_C 10 /* center middle */
#define QRF_ALIGN_E 11 /* right middle */
#define QRF_ALIGN_Bottom 12 /* auto bottom */
#define QRF_ALIGN_SW 13 /* left bottom */
#define QRF_ALIGN_S 14 /* center bottom */
#define QRF_ALIGN_SE 15 /* right bottom */
#define QRF_ALIGN_HMASK 3 /* Horizontal alignment mask */
#define QRF_ALIGN_VMASK 12 /* Vertical alignment mask */
/*
** Auxiliary routines contined within this module that might be useful
** in other contexts, and which are therefore exported.
*/
/*
** Return an estimate of the width, in columns, for the single Unicode
** character c. For normal characters, the answer is always 1. But the
** estimate might be 0 or 2 for zero-width and double-width characters.
**
** Different devices display unicode using different widths. So
** it is impossible to know that true display width with 100% accuracy.
** Inaccuracies in the width estimates might cause columns to be misaligned.
** Unfortunately, there is nothing we can do about that.
*/
int sqlite3_qrf_wcwidth(int c);
/*
** Return an estimate of the number of display columns used by the
** string in the argument. The width of individual characters is
** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences
** are assigned a width of zero.
*/
size_t sqlite3_qrf_wcswidth(const char*);
#ifdef __cplusplus
}
#endif
#endif /* !defined(SQLITE_QRF_H) */
-28
View File
@@ -192,32 +192,4 @@ do_test 4.7.2 {
list [catch {rbu close} msg] $msg
} {1 {SQLITE_ERROR - rbu_state mismatch error}}
#-------------------------------------------------------------------------
# https://sqlite.org/forum/info/6d0a31e22a435877
#
reset_db
forcedelete rbu.db
do_execsql_test 5.0 {
CREATE TABLE t1(a BLOB);
INSERT INTO t1 VALUES(x'41');
}
sqlite3 dbRbu rbu.db
dbRbu eval {
CREATE TABLE data_t1(a, rbu_control, rbu_rowid);
INSERT INTO data_t1 VALUES(X'310a313a5a337e7e7e7e7e40302c303b','f',1);
}
dbRbu close
do_test 5.1 {
sqlite3rbu rbu test.db rbu.db
rbu step
} {SQLITE_ERROR}
do_test 5.2 {
list [catch {rbu close} msg] $msg
} {1 {SQLITE_ERROR - corrupt fossil delta}}
finish_test
-61
View File
@@ -397,65 +397,4 @@ do_test 3.5 {
} {0 SQLITE_DONE}
catch { db close }
#-------------------------------------------------------------------------
# Test that a database that uses custom collation sequences can be RBU
# vacuumed.
#
reset_db
do_execsql_test 4.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'i');
INSERT INTO t1 VALUES(2, 'iiii');
INSERT INTO t1 VALUES(3, 'ii');
INSERT INTO t1 VALUES(4, 'iii');
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = sql || '; SELECT blow_up_the_world();';
SELECT sql FROM sqlite_schema;
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b); SELECT blow_up_the_world();}}
set ::eof 0
proc blowup {} {
set ::eof 1
}
db close
do_test 4.1 {
sqlite3rbu_vacuum rbu test.db state.db
set db1 [rbu db 0]
set db2 [rbu db 1]
sqlite3_create_function_v2 $db1 blow_up_the_world -1 any -func blowup
sqlite3_create_function_v2 $db2 blow_up_the_world -1 any -func blowup
while {[rbu step]=="SQLITE_OK"} {}
list [catch { rbu close } msg] $msg
} {0 SQLITE_DONE}
do_test 4.2 { set ::eof } 0
sqlite3 db test.db
do_execsql_test 4.3 {
SELECT sql FROM sqlite_schema
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b)}}
do_execsql_test 4.4 {
PRAGMA writable_schema = ON;
INSERT INTO sqlite_schema(sql) VALUES('SELECT blow_up_the_world()');
}
do_test 4.5 {
sqlite3rbu_vacuum rbu test.db state.db
while {[rbu step]=="SQLITE_OK"} {}
list [catch { rbu close } msg] $msg
} {1 {SQLITE_CORRUPT - malformed database schema (?)}}
finish_test

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