Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 843418ae70 | |||
| 0ec8c56567 |
+102
-187
@@ -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 \
|
||||
@@ -1866,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)
|
||||
@@ -2366,7 +2429,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.
|
||||
#
|
||||
@@ -2601,22 +2664,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.
|
||||
#
|
||||
@@ -2640,8 +2687,8 @@ smoketest: $(TESTPROGS)
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
|
||||
|
||||
shelltest:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl release shell
|
||||
shelltest: $(TESTPROGS)
|
||||
.\testfixture.exe $(TOP)\test\permutations.test 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)
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl -DINCLUDE_SQLITE3_C $(TOP)\tool\sqlite3_analyzer.c.in > $@
|
||||
@@ -2709,9 +2756,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)
|
||||
@@ -2780,135 +2824,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>>
|
||||
|
||||
@@ -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
|
||||
@@ -100,16 +99,16 @@ script found at the root of the source tree. Then run "make".
|
||||
|
||||
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
|
||||
@@ -117,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"
|
||||
@@ -135,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.
|
||||
@@ -158,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.
|
||||
@@ -184,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
|
||||
|
||||
@@ -197,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.
|
||||
@@ -379,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.
|
||||
@@ -409,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.
|
||||
|
||||
@@ -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
-11
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
========================================================================
|
||||
|
||||
+4
-6
@@ -7409,13 +7409,11 @@ void *JimDefaultAllocator(void *ptr, size_t size)
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
else if (ptr) {
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
else {
|
||||
void *p = realloc(ptr, size);
|
||||
if( p==0 ){
|
||||
fprintf(stderr,"Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
return p;
|
||||
return malloc(size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
+3
-10
@@ -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:   `mkdir $HOME/local`
|
||||
<li>Run:   `./configure --prefix=$HOME/local`<br>
|
||||
SQLite deliverable builds add:   `--static CFLAGS=-Os`
|
||||
<li>Run:   `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
|
||||
@@ -42,12 +41,6 @@ guidance on building for Windows.
|
||||
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.
|
||||
|
||||
The SQLite developers typically add the
|
||||
  `--with-linenoise=$HOME/linenoise`   option
|
||||
to provide command-line editing. "$HOME/linenoise" is a directory
|
||||
that contains [linenoise](https://github.com/antirez/linenoise) source
|
||||
code files, `linenoise.c` and `linenoise.h`.
|
||||
|
||||
6. Run the "`Makefile`" makefile with an appropriate target.
|
||||
Examples:
|
||||
<ul>
|
||||
|
||||
@@ -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.
|
||||
|
||||
+57
-102
@@ -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,40 +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`, and `fuzzcheck`.
|
||||
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 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 devtest`
|
||||
* `make releasetest`
|
||||
* `make sdevtest`
|
||||
* `make testrunner`
|
||||
|
||||
<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.
|
||||
@@ -83,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
|
||||
@@ -104,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.
|
||||
@@ -182,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
|
||||
@@ -209,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>
|
||||
@@ -228,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
|
||||
@@ -251,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
|
||||
@@ -263,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:
|
||||
@@ -272,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
|
||||
@@ -286,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
|
||||
@@ -295,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
|
||||
@@ -303,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>
|
||||
@@ -313,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>
|
||||
@@ -340,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
|
||||
@@ -366,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
|
||||
```
|
||||
@@ -376,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>
|
||||
@@ -390,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
|
||||
@@ -399,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
|
||||
@@ -409,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
|
||||
@@ -425,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 ...
|
||||
```
|
||||
@@ -435,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 ...
|
||||
```
|
||||
@@ -445,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
|
||||
```
|
||||
|
||||
+6
-3
@@ -1816,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);
|
||||
}
|
||||
@@ -3391,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{
|
||||
@@ -4014,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"
|
||||
|
||||
@@ -601,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);
|
||||
|
||||
+10
-32
@@ -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;
|
||||
}
|
||||
@@ -3596,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);
|
||||
}
|
||||
|
||||
@@ -5349,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);
|
||||
}
|
||||
|
||||
@@ -5479,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
@@ -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
|
||||
|
||||
+21
-27
@@ -2074,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 ){
|
||||
@@ -5240,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;
|
||||
@@ -5319,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5399,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);
|
||||
@@ -5454,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;
|
||||
@@ -5465,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);
|
||||
@@ -5496,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);
|
||||
@@ -5936,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) ){
|
||||
|
||||
@@ -2081,7 +2081,6 @@ static int fts5UpdateMethod(
|
||||
}
|
||||
|
||||
update_out:
|
||||
sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
|
||||
pTab->p.pConfig->pzErrmsg = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -306,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{
|
||||
@@ -343,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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -59,7 +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 );
|
||||
pOut = sqlite3_malloc( nOut+5 );
|
||||
for(i=4; i>=0; i--){
|
||||
x[i] = (nIn >> (7*(4-i)))&0x7f;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ static void uncompressFunc(
|
||||
nOut = (nOut<<7) | (pIn[i]&0x7f);
|
||||
if( (pIn[i]&0x80)!=0 ){ i++; break; }
|
||||
}
|
||||
pOut = sqlite3_malloc64( nOut+1 );
|
||||
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);
|
||||
|
||||
+7
-9
@@ -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,9 +62,6 @@ SQLITE_EXTENSION_INIT1
|
||||
# define CSV_NOINLINE
|
||||
#endif
|
||||
|
||||
#ifndef SQLITEINT_H
|
||||
typedef sqlite3_int64 i64;
|
||||
#endif
|
||||
|
||||
/* Max size of the error message in a CsvReader */
|
||||
#define CSV_MXERR 200
|
||||
@@ -77,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 */
|
||||
@@ -177,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;
|
||||
@@ -513,6 +510,7 @@ 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));
|
||||
|
||||
+2
-1
@@ -329,7 +329,6 @@ static int fileStat(
|
||||
b1[sz] = 0;
|
||||
rc = _wstat(b1, pStatBuf);
|
||||
if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
|
||||
sqlite3_free(b1);
|
||||
return rc;
|
||||
#else
|
||||
return stat(zPath, pStatBuf);
|
||||
@@ -460,6 +459,7 @@ static int writeFile(
|
||||
|
||||
if( mtime>=0 ){
|
||||
#if defined(_WIN32)
|
||||
#if !SQLITE_OS_WINRT
|
||||
/* Windows */
|
||||
FILETIME lastAccess;
|
||||
FILETIME lastWrite;
|
||||
@@ -490,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];
|
||||
|
||||
@@ -38,11 +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;
|
||||
|
||||
/*
|
||||
** Must be a 16-bit value
|
||||
@@ -543,8 +541,8 @@ 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
|
||||
@@ -572,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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+7
-21
@@ -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;
|
||||
@@ -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);
|
||||
@@ -853,7 +839,7 @@ static void re_bytecode_func(
|
||||
|
||||
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);
|
||||
|
||||
+5
-10
@@ -230,16 +230,13 @@ static void hash_finish(
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
** 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,
|
||||
@@ -260,13 +257,11 @@ static void sha1Func(
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+6
-48
@@ -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);");
|
||||
@@ -247,10 +221,6 @@ static int vtablogConnectCreate(
|
||||
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(
|
||||
@@ -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);
|
||||
|
||||
+27
-28
@@ -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;
|
||||
@@ -539,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;
|
||||
}
|
||||
@@ -564,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;
|
||||
@@ -811,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;
|
||||
}
|
||||
@@ -830,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 */
|
||||
@@ -870,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);
|
||||
}
|
||||
}
|
||||
@@ -902,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 ){
|
||||
@@ -921,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
|
||||
);
|
||||
}
|
||||
@@ -945,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 ){
|
||||
@@ -1011,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;
|
||||
}
|
||||
}
|
||||
@@ -1183,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));
|
||||
@@ -1209,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--){
|
||||
@@ -1220,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;
|
||||
}
|
||||
|
||||
@@ -1265,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;
|
||||
@@ -1313,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;
|
||||
@@ -1511,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;
|
||||
}
|
||||
|
||||
@@ -1521,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);
|
||||
@@ -1988,7 +1987,7 @@ struct ZipfileCtx {
|
||||
ZipfileBuffer cds;
|
||||
};
|
||||
|
||||
static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){
|
||||
static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){
|
||||
if( pBuf->n+nByte>pBuf->nAlloc ){
|
||||
u8 *aNew;
|
||||
sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512;
|
||||
@@ -2037,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));
|
||||
|
||||
+42
-130
@@ -19,10 +19,10 @@ 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:
|
||||
Suppose `pStmt` is a pointer to an SQLite prepared statement
|
||||
(a pointer to an `sqlite3_stmt` object) that has been reset and
|
||||
bound and is ready to run. Then to format the output from this
|
||||
prepared statement, use code similar to the following:
|
||||
|
||||
> ~~~
|
||||
sqlite3_qrf_spec spec; /* Format specification */
|
||||
@@ -41,59 +41,26 @@ if( rc ){
|
||||
sqlite3_free(zErrMsg); /* Free the error message text */
|
||||
}else{
|
||||
printf("%s", zResult); /* Report the results */
|
||||
sqlite3_free(zResult); /* Free memory used to hold 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
|
||||
and what to do with 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:
|
||||
The `sqlite3_qrf_spec` structure defines how the results of a query
|
||||
are to be formatted, and what to do with the formatted text. The
|
||||
most recent definition of `sqlite3_qrf_spec` is shown below.
|
||||
|
||||
Do not be alarmed by the complexity of this structure. You only have
|
||||
to understand the properties you want to modify. Zero is always a good
|
||||
default for all of the attributes (except iVersion and pzOutput/xWrite)
|
||||
and so simply zeroing out the bulk of this structure is a good start.
|
||||
You can then slowly make adjustments to individual fields to get the
|
||||
results you desire.
|
||||
|
||||
> ~~~
|
||||
typedef struct sqlite3_qrf_spec sqlite3_qrf_spec;
|
||||
@@ -107,14 +74,12 @@ struct sqlite3_qrf_spec {
|
||||
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 bTextNull; /* Apply eText encoding to zNull[] */
|
||||
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 */
|
||||
int nCharLimit; /* Maximum number of characters in a cell */
|
||||
int nWidth; /* Number of entries in aWidth[] */
|
||||
int nAlign; /* Number of entries in aAlignment[] */
|
||||
@@ -133,24 +98,21 @@ struct sqlite3_qrf_spec {
|
||||
};
|
||||
~~~
|
||||
|
||||
Do not be alarmed by the complexity of this structure. Everything can
|
||||
be zeroed except for:
|
||||
Again, the only fields that must initialized are:
|
||||
|
||||
* `.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.
|
||||
All other fields can be zeroed. Or they can contain other values to
|
||||
alter the formatting of the query results.
|
||||
|
||||
Further detail on the meanings of each of the fields in the
|
||||
`sqlite3_qrf_spec` object is in the subsequent sections.
|
||||
`sqlite3_qrf_spec` object are described below.
|
||||
|
||||
### 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
|
||||
the QRF might add new fields onto 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.
|
||||
|
||||
@@ -164,7 +126,7 @@ 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
|
||||
is initially non-NULL, then it is assumed to point to memory obtained
|
||||
from sqlite3_malloc(). In that case, the buffer is resized using
|
||||
sqlite3_realloc() and the new text is appended.
|
||||
|
||||
@@ -178,8 +140,8 @@ 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.
|
||||
specific output format that will be generated. See section 4.0 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.
|
||||
@@ -252,7 +214,6 @@ Both fields can have one of the following values:
|
||||
#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
|
||||
@@ -266,14 +227,6 @@ 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 4180, which defines Comma-Separated-Value or CSV files.
|
||||
Text strings that contain no special values appears as-is. Text strings
|
||||
@@ -312,7 +265,6 @@ how the BLOB value is formatted. The following options are available;
|
||||
#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
|
||||
@@ -340,11 +292,7 @@ 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)
|
||||
### 2.8 Maximum size of displayed content (nLineLimit, nCharLimit)
|
||||
|
||||
If the sqlite3_qrf_spec.nCharLimit setting is non-zero, then the formatter
|
||||
will display only the first nCharLimit characters of each value.
|
||||
@@ -360,27 +308,13 @@ 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 number of displayed lines. This setting only works for
|
||||
**Box**, **Column**, **Line**, **Markdown**, and **Table** styles.
|
||||
|
||||
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 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
|
||||
|
||||
When using columnar formatting modes (QRF_STYLE_Box, QRF_STYLE_Column,
|
||||
@@ -416,10 +350,6 @@ 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.11 Individual Column Width (nWidth and aWidth)
|
||||
|
||||
The sqlite3_qrf_spec.aWidth field is a pointer to an array of
|
||||
@@ -527,9 +457,8 @@ 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 horizontal alignment, then values are left-aligned
|
||||
(QRF_ALIGN_Left). If neither aAlign\[\] nor eDfltAlign
|
||||
specify a vertical alignment, then values are top-aligned
|
||||
(QRF_ALIGN_Top).
|
||||
|
||||
@@ -550,12 +479,17 @@ and these settings are ignored for those styles.
|
||||
The sqlite3_qrf_spec.zTableName value is the name of the output table
|
||||
when eStyle is QRF_STYLE_Insert.
|
||||
|
||||
### 2.15 The Rendering Of NULL (zNull)
|
||||
### 2.15 The Rendering Of NULL (zNull, eTextNull)
|
||||
|
||||
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.
|
||||
|
||||
If the sqlite3_qrf_spec.bTextNull field is QRF_Yes, then the
|
||||
text encoding specified by eText is applied to the value in
|
||||
zNull. If bTextNull is QRF_No or QRF_Auto, then the value
|
||||
in zNull is shown verbatim.
|
||||
|
||||
### 2.16 Optional Value Rendering Callback
|
||||
|
||||
If the sqlite3_qrf_spec.xRender field is not NULL, then each
|
||||
@@ -577,13 +511,6 @@ 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
|
||||
@@ -596,13 +523,12 @@ 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.
|
||||
output style used is determined by the eStyle setting of the
|
||||
sqlite3_qrf_spec object. The set of supported output modes
|
||||
might increase in future versions.
|
||||
The following output modes are currently defined:
|
||||
|
||||
> ~~~
|
||||
@@ -658,22 +584,8 @@ 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.
|
||||
psql. The **Markdown** renders its result in the
|
||||
Markdown table format.
|
||||
|
||||
### 4.3 Line-oriented Styles
|
||||
|
||||
@@ -756,7 +668,7 @@ The SQLite Query Result Formatter is implemented in three source code files:
|
||||
|
||||
* `qrf.c` → The implementation, written in portable C99
|
||||
* `qrf.h` → A header file defining interfaces
|
||||
* `README.md` → This documentation
|
||||
* `README.md` → This documentation, in Markdown
|
||||
|
||||
To use the SQLite result formatter, include the "`qrf.h`" header file
|
||||
and link the application against the "`qrf.c`" source 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
|
||||
+118
-437
File diff suppressed because it is too large
Load Diff
+2
-13
@@ -34,14 +34,13 @@ struct sqlite3_qrf_spec {
|
||||
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 bTextNull; /* Apply eText encoding to zNull[] */
|
||||
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 */
|
||||
int nCharLimit; /* Maximum number of characters in a cell */
|
||||
int nWidth; /* Number of entries in aWidth[] */
|
||||
int nAlign; /* Number of entries in aAlignment[] */
|
||||
@@ -110,7 +109,6 @@ int sqlite3_format_query_result(
|
||||
#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
|
||||
@@ -122,7 +120,6 @@ int sqlite3_format_query_result(
|
||||
#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.
|
||||
@@ -178,21 +175,13 @@ int sqlite3_format_query_result(
|
||||
** 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
|
||||
** Different display 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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -623,7 +623,7 @@ static int rbuDeltaApply(
|
||||
/* ERROR: copy exceeds output file size */
|
||||
return -1;
|
||||
}
|
||||
if( (u64)ofst+(u64)cnt > (u64)lenSrc ){
|
||||
if( (int)(ofst+cnt) > lenSrc ){
|
||||
/* ERROR: copy extends past end of input */
|
||||
return -1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -200,7 +200,7 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
|
||||
/* The sqlite3AtoF() routine is much much faster than atof(), if it
|
||||
** is available */
|
||||
double r;
|
||||
(void)sqlite3AtoF((const char*)p->z, &r);
|
||||
(void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8);
|
||||
*pVal = r;
|
||||
#else
|
||||
*pVal = (GeoCoord)atof((const char*)p->z);
|
||||
|
||||
+1
-1
@@ -3775,7 +3775,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
|
||||
if( node.zData==0 ) return;
|
||||
nData = sqlite3_value_bytes(apArg[1]);
|
||||
if( nData<4 ) return;
|
||||
if( nData<4+NCELL(&node)*tree.nBytesPerCell ) return;
|
||||
if( nData<NCELL(&node)*tree.nBytesPerCell ) return;
|
||||
|
||||
pOut = sqlite3_str_new(0);
|
||||
for(ii=0; ii<NCELL(&node); ii++){
|
||||
|
||||
@@ -47,14 +47,4 @@ ifcapable rtree_int_only {
|
||||
|
||||
do_rtree_integrity_test rtreeB-1.2 t1
|
||||
|
||||
# https://sqlite.org/forum/forumpost/2026-01-08T23:32:19Z
|
||||
#
|
||||
db null NULL
|
||||
do_execsql_test rtreeB-2.1 {
|
||||
SELECT rtreenode(1,x'00000001'||randomblob(15)) IS NULL;
|
||||
} {1}
|
||||
do_execsql_test rtreeB-2.2 {
|
||||
SELECT rtreenode(1,x'00000001'||randomblob(16)) IS NOT NULL;
|
||||
} {1}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -135,7 +135,6 @@ foreach {tn blob} {
|
||||
54 540101743400120003001200010000000000000002120002400C000000000002120002400C00000000000050040100000074310017FF0050040100000074310017FF7F00000000000000050100000000000000030100000003001700010000666F7572
|
||||
55 540101743400120003001200010000000000000002120002400C00000000000050040100000074310017000100010080000001000000020003010100000300170100000003001700010000666F7572
|
||||
56 5487ffffff7f
|
||||
57 54015052494e5446110017120004
|
||||
} {
|
||||
do_test 2.$tn {
|
||||
set changeset [binary decode hex $blob]
|
||||
|
||||
@@ -192,16 +192,6 @@ do_test 3.3 {
|
||||
}
|
||||
} {1 1 3 3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
set C [binary format c* 0x54 0x01 0x01 0x00 0x12 0x00 0x05]
|
||||
|
||||
do_test 4.0 {
|
||||
sqlite3changegroup grp
|
||||
list [catch { grp add $C } msg] $msg
|
||||
} {1 SQLITE_CORRUPT}
|
||||
grp delete
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -349,20 +349,6 @@ static int sessionVarintGet(const u8 *aBuf, int *piVal){
|
||||
return getVarint32(aBuf, *piVal);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a varint value from buffer aBuf[], size nBuf bytes, into *piVal.
|
||||
** Return the number of bytes read.
|
||||
*/
|
||||
static int sessionVarintGetSafe(const u8 *aBuf, int nBuf, int *piVal){
|
||||
u8 aCopy[5];
|
||||
const u8 *aRead = aBuf;
|
||||
if( nBuf<5 ){
|
||||
memcpy(aCopy, aBuf, nBuf);
|
||||
aRead = aCopy;
|
||||
}
|
||||
return getVarint32(aRead, *piVal);
|
||||
}
|
||||
|
||||
/* Load an unaligned and unsigned 32-bit integer */
|
||||
#define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
|
||||
|
||||
@@ -657,10 +643,14 @@ static unsigned int sessionChangeHash(
|
||||
int isPK = pTab->abPK[i];
|
||||
if( bPkOnly && isPK==0 ) continue;
|
||||
|
||||
/* It is not possible for eType to be SQLITE_NULL here. The session
|
||||
** module does not record changes for rows with NULL values stored in
|
||||
** primary key columns. */
|
||||
assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
|
||||
|| eType==SQLITE_TEXT || eType==SQLITE_BLOB
|
||||
|| eType==SQLITE_NULL || eType==0
|
||||
);
|
||||
assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
|
||||
|
||||
if( isPK ){
|
||||
a++;
|
||||
@@ -668,16 +658,12 @@ static unsigned int sessionChangeHash(
|
||||
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
|
||||
h = sessionHashAppendI64(h, sessionGetI64(a));
|
||||
a += 8;
|
||||
}else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
|
||||
}else{
|
||||
int n;
|
||||
a += sessionVarintGet(a, &n);
|
||||
h = sessionHashAppendBlob(h, n, a);
|
||||
a += n;
|
||||
}
|
||||
/* It should not be possible for eType to be SQLITE_NULL or 0x00 here,
|
||||
** as the session module does not record changes for rows with NULL
|
||||
** values stored in primary key columns. But a corrupt changesets
|
||||
** may contain such a value. */
|
||||
}else{
|
||||
a += sessionSerialLen(a);
|
||||
}
|
||||
@@ -3086,13 +3072,10 @@ static int sessionGenerateChangeset(
|
||||
}
|
||||
|
||||
if( pSession->rc ) return pSession->rc;
|
||||
rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
||||
return rc;
|
||||
}
|
||||
|
||||
for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
|
||||
if( pTab->nEntry ){
|
||||
@@ -3575,8 +3558,7 @@ static int sessionReadRecord(
|
||||
u8 *aVal = &pIn->aData[pIn->iNext];
|
||||
if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
|
||||
int nByte;
|
||||
int nRem = pIn->nData - pIn->iNext;
|
||||
pIn->iNext += sessionVarintGetSafe(aVal, nRem, &nByte);
|
||||
pIn->iNext += sessionVarintGet(aVal, &nByte);
|
||||
rc = sessionInputBuffer(pIn, nByte);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( nByte<0 || nByte>pIn->nData-pIn->iNext ){
|
||||
@@ -3629,8 +3611,7 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
|
||||
|
||||
rc = sessionInputBuffer(pIn, 9);
|
||||
if( rc==SQLITE_OK ){
|
||||
int nBuf = pIn->nData - pIn->iNext;
|
||||
nRead += sessionVarintGetSafe(&pIn->aData[pIn->iNext], nBuf, &nCol);
|
||||
nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
|
||||
/* The hard upper limit for the number of columns in an SQLite
|
||||
** database table is, according to sqliteLimit.h, 32676. So
|
||||
** consider any table-header that purports to have more than 65536
|
||||
@@ -3650,15 +3631,8 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
|
||||
while( (pIn->iNext + nRead)<pIn->nData && pIn->aData[pIn->iNext + nRead] ){
|
||||
nRead++;
|
||||
}
|
||||
|
||||
/* Break out of the loop if if the nul-terminator byte has been found.
|
||||
** Otherwise, read some more input data and keep seeking. If there is
|
||||
** no more input data, consider the changeset corrupt. */
|
||||
if( (pIn->iNext + nRead)<pIn->nData ) break;
|
||||
rc = sessionInputBuffer(pIn, nRead + 100);
|
||||
if( rc==SQLITE_OK && (pIn->iNext + nRead)>=pIn->nData ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
}
|
||||
*pnByte = nRead+1;
|
||||
return rc;
|
||||
@@ -3790,10 +3764,10 @@ static int sessionChangesetNextOne(
|
||||
memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
|
||||
}
|
||||
|
||||
/* Make sure the buffer contains at least 2 bytes of input data, or all
|
||||
** remaining data if there are less than 2 bytes available. This is
|
||||
** sufficient either for the 'T' or 'P' byte that begins a new table,
|
||||
** or for the "op" and "bIndirect" single bytes otherwise. */
|
||||
/* Make sure the buffer contains at least 10 bytes of input data, or all
|
||||
** remaining data if there are less than 10 bytes available. This is
|
||||
** sufficient either for the 'T' or 'P' byte and the varint that follows
|
||||
** it, or for the two single byte values otherwise. */
|
||||
p->rc = sessionInputBuffer(&p->in, 2);
|
||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||
|
||||
@@ -3823,13 +3797,11 @@ static int sessionChangesetNextOne(
|
||||
return (p->rc = SQLITE_CORRUPT_BKPT);
|
||||
}
|
||||
|
||||
if( (op!=SQLITE_UPDATE && op!=SQLITE_DELETE && op!=SQLITE_INSERT)
|
||||
|| (p->in.iNext>=p->in.nData)
|
||||
){
|
||||
return (p->rc = SQLITE_CORRUPT_BKPT);
|
||||
}
|
||||
p->op = op;
|
||||
p->bIndirect = p->in.aData[p->in.iNext++];
|
||||
if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
|
||||
return (p->rc = SQLITE_CORRUPT_BKPT);
|
||||
}
|
||||
|
||||
if( paRec ){
|
||||
int nVal; /* Number of values to buffer */
|
||||
|
||||
+25
-49
@@ -7,8 +7,6 @@
|
||||
#include <string.h>
|
||||
#include "tclsqlite.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
typedef unsigned char u8;
|
||||
#endif
|
||||
@@ -858,21 +856,6 @@ static int testStreamInput(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This works like Tcl_GetByteArrayFromObj(), except that it returns a buffer
|
||||
** allocated using malloc() that must be freed by the caller. This is done
|
||||
** because Tcl's buffers are often padded by a few bytes, which prevents
|
||||
** small overreads from being detected when tests are run under asan.
|
||||
*/
|
||||
static void *testGetByteArrayFromObj(Tcl_Obj *p, Tcl_Size *pnByte){
|
||||
Tcl_Size nByte = 0;
|
||||
void *aByte = Tcl_GetByteArrayFromObj(p, &nByte);
|
||||
void *aCopy = malloc(nByte ? (size_t)nByte : 1);
|
||||
memcpy(aCopy, aByte, (size_t)nByte);
|
||||
*pnByte = nByte;
|
||||
return aCopy;
|
||||
}
|
||||
|
||||
|
||||
static int SQLITE_TCLAPI testSqlite3changesetApply(
|
||||
int iVersion,
|
||||
@@ -937,7 +920,7 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
db = *(sqlite3 **)info.objClientData;
|
||||
pChangeset = (void *)testGetByteArrayFromObj(objv[2], &nChangeset);
|
||||
pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[2], &nChangeset);
|
||||
ctx.pConflictScript = objv[3];
|
||||
ctx.pFilterScript = objc==5 ? objv[4] : 0;
|
||||
ctx.interp = interp;
|
||||
@@ -989,7 +972,6 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
|
||||
}
|
||||
}
|
||||
|
||||
free(pChangeset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return test_session_error(interp, rc, 0);
|
||||
}else{
|
||||
@@ -1213,12 +1195,7 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach(
|
||||
pCS = objv[2];
|
||||
pScript = objv[3];
|
||||
|
||||
/* Take a copy of the changeset into an exact sized buffer allocated
|
||||
** using malloc(). The Tcl buffer will be padded by a few bytes, which
|
||||
** prevents small overreads from being detected by ASAN when the tests
|
||||
** are run. */
|
||||
pChangeset = (void*)testGetByteArrayFromObj(pCS, &nChangeset);
|
||||
|
||||
pChangeset = (void *)Tcl_GetByteArrayFromObj(pCS, &nChangeset);
|
||||
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
|
||||
if( isInvert ){
|
||||
int f = SQLITE_CHANGESETSTART_INVERT;
|
||||
@@ -1239,33 +1216,32 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach(
|
||||
rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
while( SQLITE_ROW==sqlite3changeset_next(pIter) ){
|
||||
Tcl_Obj *pVar = 0; /* Tcl value to set $VARNAME to */
|
||||
pVar = testIterData(pIter);
|
||||
Tcl_ObjSetVar2(interp, pVarname, 0, pVar, 0);
|
||||
rc = Tcl_EvalObjEx(interp, pScript, 0);
|
||||
if( rc!=TCL_OK && rc!=TCL_CONTINUE ){
|
||||
sqlite3changeset_finalize(pIter);
|
||||
free(pChangeset);
|
||||
return rc==TCL_BREAK ? TCL_OK : rc;
|
||||
}
|
||||
}
|
||||
|
||||
if( isCheckNext ){
|
||||
int rc2 = sqlite3changeset_next(pIter);
|
||||
rc = sqlite3changeset_finalize(pIter);
|
||||
assert( (rc2==SQLITE_DONE && rc==SQLITE_OK) || rc2==rc );
|
||||
}else{
|
||||
rc = sqlite3changeset_finalize(pIter);
|
||||
}
|
||||
}
|
||||
|
||||
free(pChangeset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return test_session_error(interp, rc, 0);
|
||||
}
|
||||
|
||||
while( SQLITE_ROW==sqlite3changeset_next(pIter) ){
|
||||
Tcl_Obj *pVar = 0; /* Tcl value to set $VARNAME to */
|
||||
pVar = testIterData(pIter);
|
||||
Tcl_ObjSetVar2(interp, pVarname, 0, pVar, 0);
|
||||
rc = Tcl_EvalObjEx(interp, pScript, 0);
|
||||
if( rc!=TCL_OK && rc!=TCL_CONTINUE ){
|
||||
sqlite3changeset_finalize(pIter);
|
||||
return rc==TCL_BREAK ? TCL_OK : rc;
|
||||
}
|
||||
}
|
||||
|
||||
if( isCheckNext ){
|
||||
int rc2 = sqlite3changeset_next(pIter);
|
||||
rc = sqlite3changeset_finalize(pIter);
|
||||
assert( (rc2==SQLITE_DONE && rc==SQLITE_OK) || rc2==rc );
|
||||
}else{
|
||||
rc = sqlite3changeset_finalize(pIter);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return test_session_error(interp, rc, 0);
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
+23
-123
@@ -86,7 +86,6 @@ emo.strip = 💈
|
||||
emo.test = 🧪
|
||||
emo.tool = 🔨
|
||||
emo.wasm-opt = 🧼
|
||||
emo.cleanup = 🧼
|
||||
# 👷🪄🧮🧫🧽🍿⛽🚧🎱🪚🏆🧼
|
||||
|
||||
#
|
||||
@@ -318,7 +317,7 @@ endif
|
||||
#
|
||||
sqlite3.canonical.c = $(dir.top)/sqlite3.c
|
||||
sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c))
|
||||
sqlite3.h = $(dir $(sqlite3.c))sqlite3.h
|
||||
sqlite3.h = $(dir $(sqlite3.c))/sqlite3.h
|
||||
|
||||
#
|
||||
# bin.version-info = binary to output various sqlite3 version info for
|
||||
@@ -869,12 +868,13 @@ $(sqlite3-license-version.js): $(bin.version-info) \
|
||||
$(dir.api)/sqlite3-license-version-header.js $(MAKEFILE)
|
||||
@$(call b.mkdir@); echo '$(logtag.@) $(emo.disk)'; { \
|
||||
cat $(dir.api)/sqlite3-license-version-header.js || exit $$?; \
|
||||
echo '/* @preserve'; \
|
||||
echo '/*'; \
|
||||
echo '** This code was built from sqlite3 version...'; \
|
||||
echo '**'; \
|
||||
awk '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
awk '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
echo '**'; echo '** Emscripten SDK: $(emcc.version)'; \
|
||||
echo '**'; echo '** Preprocessed by:'; echo '** @c-pp::ARGV@'; \
|
||||
echo '*/'; \
|
||||
} > $@
|
||||
|
||||
@@ -997,21 +997,14 @@ endif
|
||||
# /shell.c
|
||||
########################################################################
|
||||
|
||||
#
|
||||
# Fiddle-related decls we need before .wasmbuilds is included
|
||||
#
|
||||
|
||||
fiddle.c.in = $(dir.top)/shell.c $(sqlite3-wasm.c)
|
||||
|
||||
EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
|
||||
$(EXPORTED_FUNCTIONS.fiddle): $(EXPORTED_FUNCTIONS.api.in) \
|
||||
$(MAKEFILE_LIST) $(bin.c-pp)
|
||||
@$(call b.mkdir@)
|
||||
@$(call b.c-pp.shcmd,fiddle,$(EXPORTED_FUNCTIONS.api.in),\
|
||||
@$(call b.c-pp.shcmd,filter,$(EXPORTED_FUNCTIONS.api.in),\
|
||||
$@,$(EXPORTED_FUNCTIONS.c-pp.flags) -Dfiddle)
|
||||
@echo $(logtag.@) $(emo.disk)
|
||||
|
||||
|
||||
emcc.flags.fiddle = \
|
||||
$(emcc.cflags) $(emcc_opt_full) \
|
||||
--minify 0 \
|
||||
@@ -1036,23 +1029,21 @@ emcc.flags.fiddle = \
|
||||
-USQLITE_WASM_BARE_BONES \
|
||||
-DSQLITE_SHELL_FIDDLE
|
||||
|
||||
clean: clean-fiddle
|
||||
clean-fiddle:
|
||||
rm -f $(dir.fiddle)/fiddle-module.js \
|
||||
$(dir.fiddle)/*.wasm \
|
||||
$(dir.fiddle)/sqlite3-opfs-*.js \
|
||||
$(dir.fiddle)/*.gz \
|
||||
$(EXPORTED_FUNCTIONS.fiddle)
|
||||
rm -fr $(dir.fiddle-debug)
|
||||
|
||||
emcc.flags.fiddle.debug = $(emcc.flags.fiddle) \
|
||||
-DSQLITE_DEBUG \
|
||||
-DSQLITE_ENABLE_SELECTTRACE \
|
||||
-DSQLITE_ENABLE_WHERETRACE
|
||||
|
||||
clean: clean-fiddle
|
||||
clean-fiddle:
|
||||
rm -f $(dir.fiddle)/fiddle-module.js \
|
||||
$(dir.fiddle)/*.wasm \
|
||||
$(dir.fiddle)/sqlite3-opfs-*.js \
|
||||
$(dir.fiddle)/*.gz \
|
||||
$(dir.fiddle)/index.html \
|
||||
$(EXPORTED_FUNCTIONS.fiddle)
|
||||
rm -fr $(dir.fiddle-debug)
|
||||
distclean: distclean-fiddle
|
||||
distclean-fiddle:
|
||||
rm -fr $(dir.fiddle)/jqterm
|
||||
fiddle.c.in = $(dir.top)/shell.c $(sqlite3-wasm.c)
|
||||
|
||||
#
|
||||
# WASMFS build - unsupported and untested. We used WASMFS
|
||||
@@ -1221,7 +1212,7 @@ $(foreach B,$(b.names),$(eval post: $(post-js.$(B).js)))
|
||||
# These flags get applied via $(bin.mkwb).
|
||||
emcc.speedtest1.common = $(emcc_opt_full)
|
||||
emcc.speedtest1 = -I. -I$(dir $(sqlite3.canonical.c))
|
||||
emcc.speedtest1 += -sENVIRONMENT=web,worker
|
||||
emcc.speedtest1 += -sENVIRONMENT=web
|
||||
emcc.speedtest1 += -sALLOW_MEMORY_GROWTH
|
||||
emcc.speedtest1 += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.32)
|
||||
emcc.speedtest1.common += -sINVOKE_RUN=0
|
||||
@@ -1264,33 +1255,23 @@ $(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api)
|
||||
@$(call b.mkdir@); $(call b.echo,@,$(emo.disk)); \
|
||||
{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api); } > $@ || exit
|
||||
speedtest1: b-speedtest1
|
||||
st: speedtest1
|
||||
|
||||
#
|
||||
# Generate 64-bit variants of speedtest1*.{js,html}
|
||||
#
|
||||
# $1 = input file
|
||||
# $2 = output file
|
||||
#
|
||||
# TODO: preprocess these like we do the rest.
|
||||
#
|
||||
define gen-st64
|
||||
$(2): $(1)
|
||||
@$$(call b.echo,speedtest164,$$(emo.disk)$(emo.lock) Creating from $$<)
|
||||
rm -f $$@; \
|
||||
sed -e 's/speedtest1\.js/speedtest1-64bit\.js/' \
|
||||
-e 's/speedtest1-worker\.js/speedtest1-worker-64bit\.js/' \
|
||||
< $$< > $$@; \
|
||||
@rm -f $$@; \
|
||||
sed -e 's/$(3)\.js/$(3)-64bit\.js/' < $$< > $$@; \
|
||||
chmod -w $$@
|
||||
$(2): b-speedtest164
|
||||
speedtest1: $(1) $(2)
|
||||
b-speedtest164: $(2)
|
||||
CLEAN_FILES += $(2)
|
||||
endef
|
||||
speedtest1: b-speedtest164
|
||||
|
||||
$(eval $(call gen-st64,speedtest1.html,speedtest1-64bit.html))
|
||||
$(eval $(call gen-st64,speedtest1-worker.html,speedtest1-worker-64bit.html))
|
||||
$(eval $(call gen-st64,speedtest1-worker.js,speedtest1-worker-64bit.js))
|
||||
$(eval $(call gen-st64,speedtest1.html,speedtest1-64bit.html,speedtest1))
|
||||
$(eval $(call gen-st64,speedtest1-worker.html,speedtest1-worker-64bit.html,speedtest1-worker))
|
||||
$(eval $(call gen-st64,speedtest1-worker.js,speedtest1-worker-64bit.js,speedtest1-worker))
|
||||
# end speedtest1.js
|
||||
########################################################################
|
||||
|
||||
@@ -1391,54 +1372,6 @@ all: tester1
|
||||
# end tester1
|
||||
#
|
||||
|
||||
#
|
||||
# jquery.terminal support for fiddle:
|
||||
#
|
||||
# If a clone of https://github.com/jcubic/jquery.terminal
|
||||
# is found in $(JQTERM), defaulting to $(HOME)/src/jquery.terminal
|
||||
# then add jquery.terminal support to fiddle.
|
||||
#
|
||||
# To build that package, from its checkout dir:
|
||||
#
|
||||
# npm install
|
||||
# make
|
||||
#
|
||||
c-pp.D.fiddle ?=
|
||||
JQTERM ?= $(HOME)/src/jquery.terminal
|
||||
dir.jqtermExt = $(firstword $(wildcard $(JQTERM)))
|
||||
#$(info dir.jqtermExt=$(dir.jqtermExt))
|
||||
ifeq (0,$(MAKING_CLEAN))
|
||||
ifeq (,$(wildcard $(dir.jqtermExt)/js/jquery.terminal.min.js))
|
||||
$(info $(emo.magic) To add jquery.terminal support to fiddle, set JQTERM=/path/to/its/built/checkout)
|
||||
else
|
||||
$(info $(emo.magic) jquery.terminal found in $(dir.jqtermExt) - adding it to fiddle. Make sure it is built!)
|
||||
|
||||
dir.jqterm = $(dir.fiddle)/jqterm
|
||||
$(dir.fiddle)/jqterm/jquery.terminal.bundle.min.js:
|
||||
@$(call b.mkdir@)
|
||||
cat $(dir.jqtermExt)/js/jquery-1*.min.js \
|
||||
$(dir.jqtermExt)/js/jquery.terminal.min.js > $@
|
||||
|
||||
$(dir.fiddle)/jqterm/jquery.terminal.min.css: $(dir.jqtermExt)/css/jquery.terminal.min.css
|
||||
@$(call b.mkdir@)
|
||||
@$(call b.cp,fiddle,$<,$(dir $@))
|
||||
|
||||
$(dir.fiddle)/index.html: $(dir.fiddle)/jqterm/jquery.terminal.bundle.min.js \
|
||||
$(dir.fiddle)/jqterm/jquery.terminal.min.css
|
||||
c-pp.D.fiddle += -Djqterm
|
||||
endif
|
||||
endif
|
||||
# ^^^ JQTERM/MAKING_CLEAN
|
||||
|
||||
#
|
||||
# Generate fiddle/index.html. Must come after JQTERM is handled.
|
||||
#
|
||||
$(dir.fiddle)/index.html: $(dir.fiddle)/index.c-pp.html
|
||||
$(eval $(call b.c-pp.target,fiddle,\
|
||||
$(dir.fiddle)/index.c-pp.html,$(dir.fiddle)/index.html,$(c-pp.D.fiddle)))
|
||||
$(out.fiddle.wasm): $(dir.fiddle)/index.html
|
||||
|
||||
|
||||
#
|
||||
# Convenience rules to rebuild with various -Ox levels. Much
|
||||
# experimentation shows -O2 to be the clear winner in terms of speed.
|
||||
@@ -1528,9 +1461,9 @@ update-docs:
|
||||
exit 127
|
||||
else
|
||||
wasm.docs.jswasm = $(wasm.docs.home)/jswasm
|
||||
update-docs: $(bin.stripccomments) $(out.vanilla.js) $(out.vanilla.wasm)
|
||||
update-docs: $(bin.stripccomments) $(out.sqlite3.js) $(out.sqlite3.wasm)
|
||||
@echo "Copying files to the /wasm docs. Be sure to use an -Oz build for this!";
|
||||
cp -p $(out.vanilla.wasm) $(wasm.docs.jswasm)/.
|
||||
cp -p $(sqlite3.wasm) $(wasm.docs.jswasm)/.
|
||||
$(bin.stripccomments) -k -k < $(out.vanilla.js) \
|
||||
| sed -e '/^[ \t]*$$/d' > $(wasm.docs.jswasm)/sqlite3.js
|
||||
cp -p demo-123.js demo-123.html demo-123-worker.html $(wasm.docs.home)/.
|
||||
@@ -1593,39 +1526,6 @@ endif
|
||||
# ^^^ making dist/snapshot
|
||||
CLEAN_FILES += $(wildcard sqlite-wasm-*.zip)
|
||||
|
||||
########################################################################
|
||||
# The npm target is specifically for preparing files for the downstream
|
||||
# https://github.com/sqlite/sqlite-wasm (npm) distribution.
|
||||
#
|
||||
# Per agreement with that project's maintainers, these filenames need
|
||||
# to remain stable. To avoid breakage in their deployment process, any
|
||||
# changes (like renaming files) which potentially break their deployment
|
||||
# needs to be communicated to that project via opening a new ticket or
|
||||
# direct coordination with its maintainers.
|
||||
#
|
||||
# This target does a full clean/rebuild so that we can ensure that the
|
||||
# optimization level is set consistently across all files.
|
||||
#
|
||||
npm.bundle.zip = npm-bundle.zip
|
||||
CLEAN_FILES += $(npm.bundle.zip)
|
||||
# Distributables which need to be built for npm:
|
||||
npm_files = $(addprefix $(dir.dout)/, \
|
||||
sqlite3-bundler-friendly.mjs \
|
||||
sqlite3-opfs-async-proxy.js \
|
||||
sqlite3-worker1-bundler-friendly.mjs \
|
||||
sqlite3-worker1-promiser.mjs \
|
||||
sqlite3-worker1.mjs \
|
||||
sqlite3.mjs \
|
||||
sqlite3.wasm \
|
||||
sqlite3-node.mjs \
|
||||
)
|
||||
npm: $(sqlite3.canonical.c)
|
||||
@echo "$(emo.cleanup) Forcing a clean rebuild to ensure consistent optimization flags."
|
||||
$(MAKE) clean
|
||||
$(MAKE) -e "emcc_opt=-Oz $(emcc-opt-extra)" $(npm_files)
|
||||
rm -f $(npm.bundle.zip); zip -r $(npm.bundle.zip) $(npm_files)
|
||||
unzip -l $(npm.bundle.zip)
|
||||
|
||||
########################################################################
|
||||
# Explanation of, and some commentary on, various emcc build flags
|
||||
# follows. Full docs for these can be found at:
|
||||
|
||||
@@ -62,7 +62,7 @@ by concatenating the following files together in their listed order:
|
||||
|
||||
- **`sqlite3-api-prologue.js`**
|
||||
Contains the initial bootstrap setup of the sqlite3 API
|
||||
objects. This is exposed as a bootstrapping function so that
|
||||
objects. This is exposed as a function, rather than objects, so that
|
||||
the next step can pass in a config object which abstracts away parts
|
||||
of the WASM environment, to facilitate plugging it in to arbitrary
|
||||
WASM toolchains. The bootstrapping function gets removed from the
|
||||
@@ -116,10 +116,10 @@ by concatenating the following files together in their listed order:
|
||||
a Promise-based interface into the Worker #1 API. This is
|
||||
a far user-friendlier way to interface with databases running
|
||||
in a Worker thread.
|
||||
- **`sqlite3-vfs-helper.c-pp.js`**
|
||||
- **`sqlite3-vfs-helper.js`**
|
||||
Installs the `sqlite3.vfs` namespace, which contain helpers for use
|
||||
by downstream code which creates `sqlite3_vfs` implementations.
|
||||
- **`sqlite3-vtab-helper.c-pp.js`**
|
||||
- **`sqlite3-vtab-helper.js`**
|
||||
Installs the `sqlite3.vtab` namespace, which contain helpers for use
|
||||
by downstream code which creates `sqlite3_module` implementations.
|
||||
- **`sqlite3-vfs-opfs.c-pp.js`**
|
||||
|
||||
@@ -73,8 +73,6 @@ const toExportForESM =
|
||||
|
||||
const sIM = globalThis.sqlite3InitModule = function ff(...args){
|
||||
//console.warn("Using replaced sqlite3InitModule()",globalThis.location);
|
||||
sIMS.emscriptenLocateFile = args[0]?.locateFile /* see pre-js.c-pp.js [tag:locateFile] */;
|
||||
sIMS.emscriptenInstantiateWasm = args[0]?.instantiateWasm /* see pre-js.c-pp.js [tag:locateFile] */;
|
||||
return originalInit(...args).then((EmscriptenModule)=>{
|
||||
sIMS.debugModule("sqlite3InitModule() sIMS =",sIMS);
|
||||
sIMS.debugModule("sqlite3InitModule() EmscriptenModule =",EmscriptenModule);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
This file was preprocessed using:
|
||||
|
||||
//#@policy error
|
||||
@c-pp::argv@
|
||||
@c-pp::ARGV@
|
||||
//#@policy off
|
||||
*/
|
||||
//#if unsupported-build
|
||||
@@ -27,13 +27,10 @@
|
||||
|
||||
This SQLite JS build configuration is entirely unsupported! It has
|
||||
not been tested beyond the ability to compile it. It may not
|
||||
load. It may not work properly. Only builds _directly_ targeting
|
||||
browser environments ("vanilla" JS and ESM modules) are supported
|
||||
and tested. Builds which _indirectly_ target browsers (namely
|
||||
bundler-friendly builds) are not supported deliverables.
|
||||
load. It may not work properly. Only builds targeting browser
|
||||
environments are supported and tested.
|
||||
*/
|
||||
//#endif
|
||||
//#if not target:es6-bundler-friendly
|
||||
(function(Module){
|
||||
const sIMS =
|
||||
globalThis.sqlite3InitModuleState/*from extern-post-js.c-pp.js*/
|
||||
@@ -71,14 +68,6 @@
|
||||
approach.
|
||||
*/
|
||||
Module['locateFile'] = function(path, prefix) {
|
||||
if( this.emscriptenLocateFile instanceof Function ){
|
||||
/* [tag:locateFile] Client-overridden impl. We do not support
|
||||
this but offer it as a back-door which will go away the
|
||||
moment either Emscripten changes that interface or we manage
|
||||
to get non-Emscripten builds working.
|
||||
https://sqlite.org/forum/forumpost/1eec339854c935bd */
|
||||
return this.emscriptenLocateFile(path, prefix);
|
||||
}
|
||||
//#if target:es6-module
|
||||
return new URL(path, import.meta.url).href;
|
||||
//#else
|
||||
@@ -104,7 +93,7 @@
|
||||
//#endif target:es6-module
|
||||
}.bind(sIMS);
|
||||
|
||||
//#if Module.instantiateWasm and not wasmfs and not target:node
|
||||
//#if Module.instantiateWasm and not wasmfs
|
||||
/**
|
||||
Override Module.instantiateWasm().
|
||||
|
||||
@@ -113,15 +102,8 @@
|
||||
https://github.com/emscripten-core/emscripten/issues/17951
|
||||
|
||||
In such builds we must disable this.
|
||||
|
||||
It's disabled in the (unsupported/untested) node builds because
|
||||
node does not do fetch().
|
||||
*/
|
||||
Module['instantiateWasm'] = function callee(imports,onSuccess){
|
||||
if( this.emscriptenInstantiateWasm instanceof Function ){
|
||||
/* See [tag:locateFile]. Same story here */
|
||||
return this.emscriptenInstantiateWasm(imports, onSuccess);
|
||||
}
|
||||
const sims = this;
|
||||
const uri = Module.locateFile(
|
||||
sims.wasmFilename, (
|
||||
@@ -149,5 +131,4 @@
|
||||
}.bind(sIMS);
|
||||
//#endif Module.instantiateWasm and not wasmfs
|
||||
})(Module);
|
||||
//#endif not target:es6-bundler-friendly
|
||||
/* END FILE: api/pre-js.js. */
|
||||
|
||||
@@ -26,20 +26,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
the sqlite3 binding if, e.g., the wrapper is in the main thread
|
||||
and the sqlite3 API is in a worker. */
|
||||
|
||||
const outWrapper = function(f){
|
||||
return (...args)=>f("sqlite3.oo1:",...args);
|
||||
};
|
||||
|
||||
const debug = sqlite3.__isUnderTest
|
||||
? outWrapper(console.debug.bind(console))
|
||||
: outWrapper(sqlite3.config.debug);
|
||||
const warn = sqlite3.__isUnderTest
|
||||
? outWrapper(console.warn.bind(console))
|
||||
: outWrapper(sqlite3.config.warn);
|
||||
const error = sqlite3.__isUnderTest
|
||||
? outWrapper(console.error.bind(console))
|
||||
: outWrapper(sqlite3.config.error);
|
||||
|
||||
/**
|
||||
In order to keep clients from manipulating, perhaps
|
||||
inadvertently, the underlying pointer values of DB and Stmt
|
||||
@@ -102,8 +88,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
wasm.installFunction('i(ippp)', function(t,c,p,x){
|
||||
if(capi.SQLITE_TRACE_STMT===t){
|
||||
// x == SQL, p == sqlite3_stmt*
|
||||
console.log("SQL TRACE #"+(++this.counter),
|
||||
'via sqlite3@'+c+'['+capi.sqlite3_db_filename(c,null)+']',
|
||||
console.log("SQL TRACE #"+(++this.counter)+' via sqlite3@'+c+':',
|
||||
wasm.cstrToJs(x));
|
||||
}
|
||||
}.bind({counter: 0}));
|
||||
@@ -228,18 +213,41 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
properties:
|
||||
|
||||
- `.filename`: the db filename. It may be a special name like ":memory:"
|
||||
or "". It may also be a URI-style name.
|
||||
or "".
|
||||
|
||||
- `.flags`: as documented in the DB constructor.
|
||||
|
||||
- `.vfs`: as documented in the DB constructor.
|
||||
|
||||
It also accepts those as the first 3 arguments.
|
||||
|
||||
In non-default builds it may accept additional configuration
|
||||
options.
|
||||
*/
|
||||
const dbCtorHelper = function ctor(...args){
|
||||
if(!ctor._name2vfs){
|
||||
/**
|
||||
Map special filenames which we handle here (instead of in C)
|
||||
to some helpful metadata...
|
||||
|
||||
As of 2022-09-20, the C API supports the names :localStorage:
|
||||
and :sessionStorage: for kvvfs. However, C code cannot
|
||||
determine (without embedded JS code, e.g. via Emscripten's
|
||||
EM_JS()) whether the kvvfs is legal in the current browser
|
||||
context (namely the main UI thread). In order to help client
|
||||
code fail early on, instead of it being delayed until they
|
||||
try to read or write a kvvfs-backed db, we'll check for those
|
||||
names here and throw if they're not legal in the current
|
||||
context.
|
||||
*/
|
||||
ctor._name2vfs = Object.create(null);
|
||||
const isWorkerThread = ('function'===typeof importScripts/*===running in worker thread*/)
|
||||
? (n)=>toss3("VFS",n,"is only available in the main window thread.")
|
||||
: false;
|
||||
ctor._name2vfs[':localStorage:'] = {
|
||||
vfs: 'kvvfs', filename: isWorkerThread || (()=>'local')
|
||||
};
|
||||
ctor._name2vfs[':sessionStorage:'] = {
|
||||
vfs: 'kvvfs', filename: isWorkerThread || (()=>'session')
|
||||
};
|
||||
}
|
||||
const opt = ctor.normalizeArgs(...args);
|
||||
//sqlite3.config.debug("DB ctor",opt);
|
||||
let pDb;
|
||||
@@ -261,6 +269,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
sqlite3.config.error("Invalid DB ctor args",opt,arguments);
|
||||
toss3("Invalid arguments for DB constructor:", arguments, "opts:", opt);
|
||||
}
|
||||
let fnJs = wasm.isPtr(fn) ? wasm.cstrToJs(fn) : fn;
|
||||
const vfsCheck = ctor._name2vfs[fnJs];
|
||||
if(vfsCheck){
|
||||
vfsName = vfsCheck.vfs;
|
||||
fn = fnJs = vfsCheck.filename(fnJs);
|
||||
}
|
||||
let oflags = 0;
|
||||
if( flagsStr.indexOf('c')>=0 ){
|
||||
oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
|
||||
@@ -285,15 +299,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}finally{
|
||||
wasm.pstack.restore(stack);
|
||||
}
|
||||
this.filename =
|
||||
/* A poor design choice we have to keep: this.filename may be
|
||||
in the form "file:....?....". It really should have been
|
||||
sqlite3_db_filename(pDb) but that discrepancy went too long
|
||||
unnoticed to be able to change without risk of
|
||||
breakage. DB.dbFilename() can be used to fetch _just_ the
|
||||
name part.
|
||||
*/ wasm.isPtr(fn) ? wasm.cstrToJs(fn) : fn;
|
||||
|
||||
this.filename = fnJs;
|
||||
}
|
||||
__ptrMap.set(this, pDb);
|
||||
__stmtMap.set(this, Object.create(null));
|
||||
@@ -384,12 +390,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
The given db filename must be resolvable using whatever
|
||||
filesystem layer (virtual or otherwise) is set up for the default
|
||||
sqlite3 VFS or a VFS which can resolve it must be specified.
|
||||
sqlite3 VFS.
|
||||
|
||||
The special sqlite3 db names ":memory:" and "" (temporary db)
|
||||
have their normal special meanings here and need not resolve to
|
||||
real filenames, but "" uses an on-storage temporary database and
|
||||
requires that the VFS support that.
|
||||
Note that the special sqlite3 db names ":memory:" and ""
|
||||
(temporary db) have their normal special meanings here and need
|
||||
not resolve to real filenames, but "" uses an on-storage
|
||||
temporary database and requires that the VFS support that.
|
||||
|
||||
The second argument specifies the open/create mode for the
|
||||
database. It must be string containing a sequence of letters (in
|
||||
@@ -802,9 +808,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
sqlite3_db_filename() value for the given database name,
|
||||
defaulting to "main". The argument may be either a JS string
|
||||
or a pointer to a WASM-allocated C-string.
|
||||
|
||||
this.filename may be in the form of a URI-style string, whereas
|
||||
the returned string contains only the filename part.
|
||||
*/
|
||||
dbFilename: function(dbName='main'){
|
||||
return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName);
|
||||
@@ -926,15 +929,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
result set, but only if that statement has any result rows. The
|
||||
callback's "this" is the options object, noting that this
|
||||
function synthesizes one if the caller does not pass one to
|
||||
exec(). The first argument passed to the callback is described
|
||||
below. The second argument is always the current Stmt object,
|
||||
as it's needed if the caller wants to fetch the column names or
|
||||
some such (noting that they could also be fetched via
|
||||
`this.columnNames`, if the client provides the `columnNames`
|
||||
option). If the callback returns a literal `false` (as opposed
|
||||
to any other falsy value, e.g. an implicit `undefined` return),
|
||||
any ongoing statement-`step()` iteration stops without an
|
||||
error. The return value of the callback is otherwise ignored.
|
||||
exec(). The second argument passed to the callback is always
|
||||
the current Stmt object, as it's needed if the caller wants to
|
||||
fetch the column names or some such (noting that they could
|
||||
also be fetched via `this.columnNames`, if the client provides
|
||||
the `columnNames` option). If the callback returns a literal
|
||||
`false` (as opposed to any other falsy value, e.g. an implicit
|
||||
`undefined` return), any ongoing statement-`step()` iteration
|
||||
stops without an error. The return value of the callback is
|
||||
otherwise ignored.
|
||||
|
||||
ACHTUNG: The callback MUST NOT modify the Stmt object. Calling
|
||||
any of the Stmt.get() variants, Stmt.getColumnName(), or
|
||||
@@ -967,23 +970,20 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
A.3) `'stmt'` causes the current Stmt to be passed to the
|
||||
callback, but this mode will trigger an exception if
|
||||
`resultRows` is an array because appending the transient
|
||||
statement to the array would be downright unhelpful. This
|
||||
option is a legacy feature, retained for backwards
|
||||
compatibility. The statement object is passed as the second
|
||||
argument to the callback, as described above.
|
||||
statement to the array would be downright unhelpful.
|
||||
|
||||
B) An integer, indicating a zero-based column in the result
|
||||
row. Only that one single value, in JS form, will be passed on.
|
||||
row. Only that one single value will be passed on.
|
||||
|
||||
C) A string with a minimum length of 2 and leading character of
|
||||
'$' will fetch the row as an object, extract that one field,
|
||||
and pass that field's value to the callback. These keys are
|
||||
case-sensitive so must match the case used in the
|
||||
and pass that field's value to the callback. Note that these
|
||||
keys are case-sensitive so must match the case used in the
|
||||
SQL. e.g. `"select a A from t"` with a `rowMode` of `'$A'`
|
||||
would work but `'$a'` would not. A reference to a column not in
|
||||
the result set will trigger an exception on the first row (as
|
||||
the check is not performed until rows are fetched). Note that
|
||||
`$` is a legal identifier character in JS so need not be
|
||||
the check is not performed until rows are fetched). Note also
|
||||
that `$` is a legal identifier character in JS so need not be
|
||||
quoted.
|
||||
|
||||
Any other `rowMode` value triggers an exception.
|
||||
@@ -1023,7 +1023,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
- `callback` and `resultRows`: permit an array entries with
|
||||
semantics similar to those described for `bind` above.
|
||||
|
||||
OTOH, this function already does too much.
|
||||
*/
|
||||
exec: function(/*(sql [,obj]) || (obj)*/){
|
||||
affirmDbOpen(this);
|
||||
@@ -1047,7 +1046,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
/* Optimization: if the SQL is a TypedArray we can save some string
|
||||
conversion costs. */;
|
||||
/* Allocate the two output pointers (ppStmt, pzTail) and heap
|
||||
space for the SQL (pSql). When prepare_v3() returns, pzTail
|
||||
space for the SQL (pSql). When prepare_v2() returns, pzTail
|
||||
will point to somewhere in pSql. */
|
||||
let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql);
|
||||
const ppStmt = wasm.scopedAlloc(
|
||||
@@ -1059,8 +1058,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
const pSqlEnd = wasm.ptr.add(pSql, sqlByteLen);
|
||||
if(isTA) wasm.heap8().set(arg.sql, pSql);
|
||||
else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false);
|
||||
wasm.poke8(wasm.ptr.add(pSql, sqlByteLen), 0/*NUL terminator*/);
|
||||
while(pSql && wasm.peek8(pSql)
|
||||
wasm.poke(wasm.ptr.add(pSql, sqlByteLen), 0/*NUL terminator*/);
|
||||
while(pSql && wasm.peek(pSql, 'i8')
|
||||
/* Maintenance reminder:^^^ _must_ be 'i8' or else we
|
||||
will very likely cause an endless loop. What that's
|
||||
doing is checking for a terminating NUL byte. If we
|
||||
@@ -1124,7 +1123,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
/* In order to trigger an exception in the
|
||||
INSERT...RETURNING locking scenario:
|
||||
https://sqlite.org/forum/forumpost/36f7a2e7494897df
|
||||
[tag:insert-returning-reset]
|
||||
*/).finalize();
|
||||
stmt = null;
|
||||
}/*prepare() loop*/
|
||||
@@ -1132,141 +1130,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
sqlite3.config.warn("DB.exec() is propagating exception",opt,e);
|
||||
throw e;
|
||||
}*/finally{
|
||||
wasm.scopedAllocPop(stack);
|
||||
if(stmt){
|
||||
__execLock.delete(stmt);
|
||||
stmt.finalize();
|
||||
}
|
||||
wasm.scopedAllocPop(stack);
|
||||
}
|
||||
return arg.returnVal();
|
||||
}/*exec()*/,
|
||||
|
||||
//#if nope
|
||||
/**
|
||||
Experimental and untested - do not use.
|
||||
|
||||
Prepares one or more SQL statements, passing each to a callback
|
||||
for processing.
|
||||
|
||||
It requires an options object with the following properties:
|
||||
|
||||
- "sql": SQL in any format accepted by exec().
|
||||
|
||||
- "callback" (function): gets passed each prepared statement,
|
||||
as described below.
|
||||
|
||||
- "asPointer" (bool=false): if true, the callback is passed the
|
||||
WASM (sqlite3*) pointer instead of a Stmt object.
|
||||
|
||||
- "saveSql" (array): if set, the SQL of each prepared statement
|
||||
is appended to this array. This can be used without a callback
|
||||
to split SQL into its component statements. Purely empty
|
||||
statements (for for which sqlite3_prepare() returns a NULL
|
||||
sqlite3_stmt, i.e. spaces and comments) are not added to this
|
||||
list unless...
|
||||
|
||||
- "saveEmpty" (bool=false): If true, empty statements are
|
||||
retained in opt.saveSql, but their leading/trailing whitespace
|
||||
is trimmed (as for queries) so they may be empty.
|
||||
|
||||
For each statement in the input SQL:
|
||||
|
||||
1) If opt.saveSql is set, the SQL is appended to it.
|
||||
|
||||
2) If callback is set, callback(S) is called, where S is either
|
||||
a Stmt object (by default) or an (sqlite3*) WASM pointer (if
|
||||
opt.asPointer is true). If the callback returns a literal true
|
||||
(as opposed to any other truthy value), ownership of S is
|
||||
transferred to the callback, otherwise S is reset and finalized
|
||||
as soon as the callback returns. If the callback throws, S is
|
||||
unconditionally finalized.
|
||||
|
||||
If neither of opt.saveSql nor opt.callback are set, this
|
||||
function does nothing more than prepare and finalize each
|
||||
statement, which will trigger an exception if any of them
|
||||
contain invalid SQL.
|
||||
*/
|
||||
forEachStmt: function(opt){
|
||||
affirmDbOpen(this);
|
||||
opt ??= Object.create(null);
|
||||
if(!opt.sql){
|
||||
return toss3("exec() requires an SQL string.");
|
||||
}
|
||||
const sql = util.flexibleString(opt.sql);
|
||||
const callback = opt.callback;
|
||||
let stmt, pStmt;
|
||||
const stack = wasm.scopedAllocPush();
|
||||
const saveSql = Array.isArray(opt.saveSql) ? opt.saveSql : undefined;
|
||||
try{
|
||||
const isTA = util.isSQLableTypedArray(opt.sql)
|
||||
/* Optimization: if the SQL is a TypedArray we can save some string
|
||||
conversion costs. */;
|
||||
/* Allocate the two output pointers (ppStmt, pzTail) and heap
|
||||
space for the SQL (pSql). When prepare_v3() returns, pzTail
|
||||
will point to somewhere in pSql. */
|
||||
let sqlByteLen = isTA ? opt.sql.byteLength : wasm.jstrlen(sql);
|
||||
const ppStmt = wasm.scopedAlloc(
|
||||
/* output (sqlite3_stmt**) arg and pzTail */
|
||||
(2 * wasm.ptr.size) + (sqlByteLen + 1/* SQL + NUL */)
|
||||
);
|
||||
const pzTail = wasm.ptr.add(ppStmt, wasm.ptr.size) /* final arg to sqlite3_prepare_v2() */;
|
||||
let pSql = wasm.ptr.add(pzTail, wasm.ptr.size) /* start of the SQL string */;
|
||||
const pSqlEnd = wasm.ptr.add(pSql, sqlByteLen);
|
||||
if(isTA) wasm.heap8().set(sql, pSql);
|
||||
else wasm.jstrcpy(sql, wasm.heap8(), pSql, sqlByteLen, false);
|
||||
wasm.poke8(wasm.ptr.add(pSql, sqlByteLen), 0/*NUL terminator*/);
|
||||
while( pSql && wasm.peek8(pSql) ){
|
||||
pStmt = stmt = null;
|
||||
wasm.pokePtr([ppStmt, pzTail], 0);
|
||||
const zHead = pSql;
|
||||
DB.checkRc(this, capi.sqlite3_prepare_v3(
|
||||
this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail
|
||||
));
|
||||
[pStmt, pSql] = wasm.peekPtr([ppStmt, pzTail]);
|
||||
sqlByteLen = wasm.ptr.addn(pSqlEnd,-pSql);
|
||||
if(opt.saveSql){
|
||||
if( pStmt ) opt.saveSql.push(capi.sqlite3_sql(pStmt).trim());
|
||||
else if( opt.saveEmpty ){
|
||||
saveSql.push(wasm.typedArrayToString(
|
||||
wasm.heap8u(), Number(zHead),
|
||||
wasm.ptr.addn(zHead, sqlByteLen)
|
||||
).trim(/*arguable*/));
|
||||
}
|
||||
}
|
||||
if(!pStmt) continue;
|
||||
//sqlite3.config.debug("forEachStmt() pSql =",capi.sqlite3_sql(pStmt));
|
||||
if( !opt.callback ){
|
||||
capi.sqlite3_finalize(pStmt);
|
||||
pStmt = null;
|
||||
continue;
|
||||
}
|
||||
stmt = opt.asPointer ? null : new Stmt(this, pStmt, BindTypes);
|
||||
if( true===callaback(stmt || pStmt) ){
|
||||
stmt = pStmt = null /*callback took ownership */;
|
||||
}else if(stmt){
|
||||
pStmt = null;
|
||||
stmt.reset(
|
||||
/* See [tag:insert-returning-reset]. The thinking here is
|
||||
that if the callback didn't throw for this, it
|
||||
probably should have.
|
||||
*/).finalize();
|
||||
stmt = null;
|
||||
}else{
|
||||
const rx = capi.sqlite3_reset(pStmt/*[tag:insert-returning-reset]*/);
|
||||
capi.sqlite3_finalize(pStmt);
|
||||
pStmt = null;
|
||||
DB.checkRc(this, rx);
|
||||
}
|
||||
}/*prepare() loop*/
|
||||
}finally{
|
||||
if(stmt) stmt.finalize();
|
||||
else if(pStmt) capi.sqlite3_finalize(pStmt);
|
||||
wasm.scopedAllocPop(stack);
|
||||
}
|
||||
return this;
|
||||
}/*forEachStmt()*/,
|
||||
//#endif nope
|
||||
|
||||
/**
|
||||
Creates a new UDF (User-Defined Function) which is accessible
|
||||
via SQL code. This function may be called in any of the
|
||||
|
||||
@@ -752,11 +752,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
toss: function(...args){throw new Error(args.join(' '))},
|
||||
toss3,
|
||||
typedArrayPart: wasm.typedArrayPart,
|
||||
assert: function(arg,msg){
|
||||
if( !arg ){
|
||||
util.toss("Assertion failed:",msg);
|
||||
}
|
||||
},
|
||||
/**
|
||||
Given a byte array or ArrayBuffer, this function throws if the
|
||||
lead bytes of that buffer do not hold a SQLite3 database header,
|
||||
@@ -892,7 +887,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
|
||||
Like this.alloc.impl(), this.realloc.impl() is a direct binding
|
||||
to the underlying realloc() implementation which does not throw
|
||||
exceptions, instead returning 0 (or 0n) on allocation error.
|
||||
exceptions, instead returning 0 on allocation error.
|
||||
*/
|
||||
realloc: undefined/*installed later*/,
|
||||
|
||||
@@ -1413,7 +1408,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
or not provided, then "main" is assumed.
|
||||
*/
|
||||
capi.sqlite3_js_db_vfs =
|
||||
(dbPointer, dbName=wasm.ptr.null)=>util.sqlite3__wasm_db_vfs(dbPointer, dbName);
|
||||
(dbPointer, dbName=0)=>util.sqlite3__wasm_db_vfs(dbPointer, dbName);
|
||||
|
||||
/**
|
||||
A thin wrapper around capi.sqlite3_aggregate_context() which
|
||||
@@ -2034,9 +2029,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
*/
|
||||
scriptInfo: undefined
|
||||
};
|
||||
if( ('undefined'!==typeof sqlite3IsUnderTest/* from post-js-header.js */) ){
|
||||
sqlite3.__isUnderTest = !!sqlite3IsUnderTest;
|
||||
}
|
||||
try{
|
||||
sqlite3ApiBootstrap.initializers.forEach((f)=>{
|
||||
f(sqlite3);
|
||||
@@ -2059,6 +2051,9 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
builds, this would need to be injected in somewhere to get
|
||||
that VFS loading. */ = sqlite3InitScriptInfo;
|
||||
}
|
||||
sqlite3.__isUnderTest =
|
||||
('undefined'===typeof sqlite3IsUnderTest /* from post-js-header.js */)
|
||||
? false : !!sqlite3IsUnderTest;
|
||||
if( sqlite3.__isUnderTest ){
|
||||
if( 'undefined'!==typeof EmscriptenModule ){
|
||||
sqlite3.config.emscripten = EmscriptenModule;
|
||||
@@ -2095,11 +2090,9 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
delete sqlite3ApiBootstrap.defaultConfig;
|
||||
return sqlite3.asyncPostInit().then((s)=>{
|
||||
if( 'undefined'!==typeof sqlite3InitScriptInfo/* from post-js-header.js */ ){
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3.asyncPostInit() complete", s
|
||||
);
|
||||
}
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3.asyncPostInit() complete", sqlite3
|
||||
);
|
||||
delete s.asyncPostInit;
|
||||
delete s.scriptInfo;
|
||||
delete s.emscripten;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* @preserve
|
||||
**
|
||||
/*
|
||||
** LICENSE for the sqlite3 WebAssembly/JavaScript APIs.
|
||||
**
|
||||
** This bundle (typically released as sqlite3.js or sqlite3.mjs)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* @preserve
|
||||
/*
|
||||
2022-09-16
|
||||
|
||||
The author disclaims copyright to this source code. In place of a
|
||||
|
||||
+230
-1984
File diff suppressed because it is too large
Load Diff
@@ -358,7 +358,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
try{
|
||||
const [cMsg, n] = wasm.scopedAllocCString(e.message, true);
|
||||
wasm.cstrncpy(pOut, cMsg, nOut);
|
||||
if(n > nOut) wasm.poke8(wasm.ptr.add(pOut,nOut,-1), 0);
|
||||
if(n > nOut) wasm.poke8(pOut + nOut - 1, 0);
|
||||
}catch(e){
|
||||
return capi.SQLITE_NOMEM;
|
||||
}finally{
|
||||
@@ -410,7 +410,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}/*vfsMethods*/;
|
||||
|
||||
/**
|
||||
Creates, initializes, and returns an sqlite3_vfs instance for an
|
||||
Creates and initializes an sqlite3_vfs instance for an
|
||||
OpfsSAHPool. The argument is the VFS's name (JS string).
|
||||
|
||||
Throws if the VFS name is already registered or if something
|
||||
@@ -1157,9 +1157,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
described at the end of these docs.
|
||||
|
||||
This function accepts an options object to configure certain
|
||||
parts but it is only acknowledged for the very first call for
|
||||
each distinct name and ignored for all subsequent calls with that
|
||||
same name.
|
||||
parts but it is only acknowledged for the very first call and
|
||||
ignored for all subsequent calls.
|
||||
|
||||
The options, in alphabetical order:
|
||||
|
||||
@@ -1225,14 +1224,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
- Paths given to it _must_ be absolute. Relative paths will not
|
||||
be properly recognized. This is arguably a bug but correcting it
|
||||
requires some hoop-jumping in routines which have no business
|
||||
doing such tricks. (2026-01-19 (2.5 years later): the specifics
|
||||
are lost to history, but this was a side effect of xOpen()
|
||||
receiving an immutable C-string filename, to which no implicit
|
||||
"/" can be prefixed without causing a discrepancy between what
|
||||
the user provided and what the VFS stores. Its conceivable that
|
||||
that quirk could be glossed over in xFullPathname(), but
|
||||
regressions when doing so cannot be ruled out, so there are no
|
||||
current plans to change this behavior.)
|
||||
doing such tricks.
|
||||
|
||||
- It is possible to install multiple instances under different
|
||||
names, each sandboxed from one another inside their own private
|
||||
|
||||
@@ -172,7 +172,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
Works like unget() plus it calls dispose() on the
|
||||
StructType object.
|
||||
*/
|
||||
dispose: (pCObj)=>__xWrap(pCObj,true)?.dispose?.()
|
||||
dispose: (pCObj)=>{
|
||||
const o = __xWrap(pCObj,true);
|
||||
if(o) o.dispose();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
+141
-135
@@ -229,18 +229,15 @@
|
||||
** not by client code, so an argument can be made for reducing their
|
||||
** visibility by not including them in any build-time export lists.
|
||||
**
|
||||
** 2025-12-01: for use in non-Emscripten builds, we need a more
|
||||
** invasive macro which explicitly names the export:
|
||||
** SQLITE_WASM_EXPORT2.
|
||||
** 2022-09-11: it's not yet _proven_ that this approach works in
|
||||
** non-Emscripten builds. If not, such builds will need to export
|
||||
** those using the --export=... wasm-ld flag (or equivalent). As of
|
||||
** this writing we are tied to Emscripten for various reasons
|
||||
** and cannot test the library with other build environments.
|
||||
*/
|
||||
#define SQLITE_WASM_EXPORT __attribute__((used,visibility("default")))
|
||||
#define SQLITE_WASM_EXPORT_NAMED(X) __attribute__((export_name(#X),used,visibility("default")))
|
||||
#define SQLITE_WASM_EXPORT2(RETTYPE,NAME,SIG) SQLITE_WASM_EXPORT_NAMED(NAME) RETTYPE NAME SIG
|
||||
|
||||
#if 1
|
||||
/** Increase the kvvfs key size limit from 32. */
|
||||
#define KVRECORD_KEY_SZ 128
|
||||
#endif
|
||||
// See also:
|
||||
//__attribute__((export_name("theExportedName"), used, visibility("default")))
|
||||
|
||||
/*
|
||||
** Which sqlite3.c we're using needs to be configurable to enable
|
||||
@@ -264,6 +261,45 @@
|
||||
#undef INC__STRINGIFY
|
||||
#undef SQLITE_C
|
||||
|
||||
#if 0
|
||||
/*
|
||||
** An EXPERIMENT in implementing a stack-based allocator analog to
|
||||
** Emscripten's stackSave(), stackAlloc(), stackRestore().
|
||||
** Unfortunately, this cannot work together with Emscripten because
|
||||
** Emscripten defines its own native one and we'd stomp on each
|
||||
** other's memory. Other than that complication, basic tests show it
|
||||
** to work just fine.
|
||||
**
|
||||
** Another option is to malloc() a chunk of our own and call that our
|
||||
** "stack".
|
||||
*/
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_end(void){
|
||||
extern void __heap_base
|
||||
/* see https://stackoverflow.com/questions/10038964 */;
|
||||
return &__heap_base;
|
||||
}
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_begin(void){
|
||||
extern void __data_end;
|
||||
return &__data_end;
|
||||
}
|
||||
static void * pWasmStackPtr = 0;
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_ptr(void){
|
||||
if(!pWasmStackPtr) pWasmStackPtr = sqlite3__wasm_stack_end();
|
||||
return pWasmStackPtr;
|
||||
}
|
||||
SQLITE_WASM_EXPORT void sqlite3__wasm_stack_restore(void * p){
|
||||
pWasmStackPtr = p;
|
||||
}
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_alloc(int n){
|
||||
if(n<=0) return 0;
|
||||
n = (n + 7) & ~7 /* align to 8-byte boundary */;
|
||||
unsigned char * const p = (unsigned char *)sqlite3__wasm_stack_ptr();
|
||||
unsigned const char * const b = (unsigned const char *)sqlite3__wasm_stack_begin();
|
||||
if(b + n >= p || b + n < b/*overflow*/) return 0;
|
||||
return pWasmStackPtr = p - n;
|
||||
}
|
||||
#endif /* stack allocator experiment */
|
||||
|
||||
/*
|
||||
** State for the "pseudo-stack" allocator implemented in
|
||||
** sqlite3__wasm_pstack_xyz(). In order to avoid colliding with
|
||||
@@ -312,10 +348,10 @@ SQLITE_WASM_EXPORT void sqlite3__wasm_pstack_restore(unsigned char * p){
|
||||
** the memory on success, 0 on error (including a negative n value). n
|
||||
** is always adjusted to be a multiple of 8 and returned memory is
|
||||
** always zeroed out before returning (because this keeps the client
|
||||
** JS code from having to do so, and most uses of the pstack call for
|
||||
** doing so).
|
||||
** JS code from having to do so, and most uses of the pstack will
|
||||
** call for doing so).
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(void *,sqlite3__wasm_pstack_alloc,(int n)){
|
||||
SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_alloc(int n){
|
||||
if( n<=0 ) return 0;
|
||||
n = (n + 7) & ~7 /* align to 8-byte boundary */;
|
||||
if( PStack.pBegin + n > PStack.pPos /*not enough space left*/
|
||||
@@ -327,7 +363,7 @@ SQLITE_WASM_EXPORT2(void *,sqlite3__wasm_pstack_alloc,(int n)){
|
||||
** Return the number of bytes left which can be
|
||||
** sqlite3__wasm_pstack_alloc()'d.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_pstack_remaining,(void)){
|
||||
SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_remaining(void){
|
||||
assert(PStack.pPos >= PStack.pBegin);
|
||||
assert(PStack.pPos <= PStack.pEnd);
|
||||
return (int)(PStack.pPos - PStack.pBegin);
|
||||
@@ -338,7 +374,7 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_pstack_remaining,(void)){
|
||||
** any space which is currently allocated. This value is a
|
||||
** compile-time constant.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_pstack_quota,(void)){
|
||||
SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_quota(void){
|
||||
return (int)(PStack.pEnd - PStack.pBegin);
|
||||
}
|
||||
|
||||
@@ -351,7 +387,8 @@ struct WasmTestStruct {
|
||||
void (*xFunc)(void*);
|
||||
};
|
||||
typedef struct WasmTestStruct WasmTestStruct;
|
||||
SQLITE_WASM_EXPORT2(void,sqlite3__wasm_test_struct,(WasmTestStruct * s)){
|
||||
SQLITE_WASM_EXPORT
|
||||
void sqlite3__wasm_test_struct(WasmTestStruct * s){
|
||||
if(s){
|
||||
if( 0 ){
|
||||
/* Do not be alarmed by the small (and odd) pointer values.
|
||||
@@ -391,7 +428,8 @@ SQLITE_WASM_EXPORT2(void,sqlite3__wasm_test_struct,(WasmTestStruct * s)){
|
||||
** fails to compile with "tables may not be 64-bit" but does not tell
|
||||
** us where it's happening.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){
|
||||
SQLITE_WASM_EXPORT
|
||||
const char * sqlite3__wasm_enum_json(void){
|
||||
static char aBuffer[1024 * 20] =
|
||||
{0} /* where the JSON goes. 2025-09-19: output size=19295, but
|
||||
that can vary slightly from build to build, so a little
|
||||
@@ -594,7 +632,6 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){
|
||||
DefGroup(encodings) {
|
||||
/* Noting that the wasm binding only aims to support UTF-8. */
|
||||
DefInt(SQLITE_UTF8);
|
||||
DefInt(SQLITE_UTF8_ZT);
|
||||
DefInt(SQLITE_UTF16LE);
|
||||
DefInt(SQLITE_UTF16BE);
|
||||
DefInt(SQLITE_UTF16);
|
||||
@@ -982,15 +1019,13 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){
|
||||
/** ^^^ indirection needed to expand CurrentStruct */
|
||||
#define StructBinder StructBinder_(CurrentStruct)
|
||||
#define _StructBinder CloseBrace(2)
|
||||
#define M3(MEMBER,SIG,READONLY) \
|
||||
outf("%s\"%s\": " \
|
||||
"{\"offset\":%d,\"sizeof\":%d,\"signature\":\"%s\"%s}", \
|
||||
(n++ ? ", " : ""), #MEMBER, \
|
||||
(int)offsetof(CurrentStruct,MEMBER), \
|
||||
(int)sizeof(((CurrentStruct*)0)->MEMBER), \
|
||||
SIG, (READONLY ? ",\"readOnly\":true" : ""))
|
||||
#define M(MEMBER,SIG) M3(MEMBER,SIG,0)
|
||||
#define MRO(MEMBER,SIG) M3(MEMBER,SIG,1)
|
||||
#define M(MEMBER,SIG) \
|
||||
outf("%s\"%s\": " \
|
||||
"{\"offset\":%d,\"sizeof\": %d,\"signature\":\"%s\"}", \
|
||||
(n++ ? ", " : ""), #MEMBER, \
|
||||
(int)offsetof(CurrentStruct,MEMBER), \
|
||||
(int)sizeof(((CurrentStruct*)0)->MEMBER), \
|
||||
SIG)
|
||||
|
||||
nStruct = 0;
|
||||
out(", \"structs\": ["); {
|
||||
@@ -1053,30 +1088,11 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){
|
||||
#undef CurrentStruct
|
||||
|
||||
#define CurrentStruct sqlite3_kvvfs_methods
|
||||
/* From os_kv.c */
|
||||
StructBinder {
|
||||
M(xRcrdRead, "i(sspi)");
|
||||
M(xRcrdWrite, "i(sss)");
|
||||
M(xRcrdDelete, "i(ss)");
|
||||
MRO(nKeySize, "i");
|
||||
MRO(nBufferSize, "i");
|
||||
M(pVfs, "p");
|
||||
M(pIoDb, "p");
|
||||
M(pIoJrnl, "p");
|
||||
} _StructBinder;
|
||||
#undef CurrentStruct
|
||||
|
||||
#define CurrentStruct KVVfsFile
|
||||
/* From os_kv.c */
|
||||
StructBinder {
|
||||
M(base, "p")/*sqlite3_file base*/;
|
||||
M(zClass, "s");
|
||||
M(isJournal, "i");
|
||||
M(nJrnl, "i")/*actually unsigned!*/;
|
||||
M(aJrnl, "p");
|
||||
M(szPage, "i");
|
||||
M(szDb, "j");
|
||||
M(aData, "p");
|
||||
M(xRead, "i(sspi)");
|
||||
M(xWrite, "i(sss)");
|
||||
M(xDelete, "i(ss)");
|
||||
M(nKeySize, "i");
|
||||
} _StructBinder;
|
||||
#undef CurrentStruct
|
||||
|
||||
@@ -1133,13 +1149,7 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){
|
||||
** sqlite3_index_info, we have to uplift those into constructs we
|
||||
** can access by type name. These structs _must_ match their
|
||||
** in-sqlite3_index_info counterparts byte for byte.
|
||||
**
|
||||
** 2025-11-21: this uplifing is no longer necessary, as Jaccwabyt
|
||||
** can now handle nested structs, but "it ain't broke" so there's
|
||||
** no pressing need to rewire this. Also, it's conceivable that
|
||||
** rewiring it might break downstream vtab impls, so it shouldn't
|
||||
** be rewired.
|
||||
*/
|
||||
*/
|
||||
typedef struct {
|
||||
int iColumn;
|
||||
unsigned char op;
|
||||
@@ -1234,8 +1244,6 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){
|
||||
#undef StructBinder_
|
||||
#undef StructBinder__
|
||||
#undef M
|
||||
#undef MRO
|
||||
#undef M3
|
||||
#undef _StructBinder
|
||||
#undef CloseBrace
|
||||
#undef out
|
||||
@@ -1253,7 +1261,8 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){
|
||||
** method, SQLITE_MISUSE is returned, else the result of the xDelete()
|
||||
** call is returned.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vfs_unlink,(sqlite3_vfs *pVfs, const char *zName)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
|
||||
int rc = SQLITE_MISUSE /* ??? */;
|
||||
if( 0==pVfs && 0!=zName ) pVfs = sqlite3_vfs_find(0);
|
||||
if( zName && pVfs && pVfs->xDelete ){
|
||||
@@ -1270,7 +1279,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vfs_unlink,(sqlite3_vfs *pVfs, const char
|
||||
** defaulting to "main" if zDbName is 0. Returns 0 if no db with the
|
||||
** given name is open.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(sqlite3_vfs *,sqlite3__wasm_db_vfs,(sqlite3 *pDb, const char *zDbName)){
|
||||
SQLITE_WASM_EXPORT
|
||||
sqlite3_vfs * sqlite3__wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
|
||||
sqlite3_vfs * pVfs = 0;
|
||||
sqlite3_file_control(pDb, zDbName ? zDbName : "main",
|
||||
SQLITE_FCNTL_VFS_POINTER, &pVfs);
|
||||
@@ -1292,7 +1302,8 @@ SQLITE_WASM_EXPORT2(sqlite3_vfs *,sqlite3__wasm_db_vfs,(sqlite3 *pDb, const char
|
||||
** Returns 0 on success, an SQLITE_xxx code on error. Returns
|
||||
** SQLITE_MISUSE if pDb is NULL.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_reset,(sqlite3 *pDb)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_db_reset(sqlite3 *pDb){
|
||||
int rc = SQLITE_MISUSE;
|
||||
if( pDb ){
|
||||
sqlite3_table_column_metadata(pDb, "main", 0, 0, 0, 0, 0, 0, 0);
|
||||
@@ -1373,10 +1384,10 @@ int sqlite3__wasm_db_export_chunked( sqlite3* pDb,
|
||||
** If `*pOut` is not NULL, the caller is responsible for passing it to
|
||||
** sqlite3_free() to free it.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_serialize,
|
||||
(sqlite3 *pDb, const char *zSchema,
|
||||
unsigned char **pOut,
|
||||
sqlite3_int64 *nOut, unsigned int mFlags)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
|
||||
unsigned char **pOut,
|
||||
sqlite3_int64 *nOut, unsigned int mFlags ){
|
||||
unsigned char * z;
|
||||
if( !pDb || !pOut ) return SQLITE_MISUSE;
|
||||
if( nOut ) *nOut = 0;
|
||||
@@ -1437,9 +1448,11 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_serialize,
|
||||
** portability, so that the API can still work in builds where BigInt
|
||||
** support is disabled or unavailable.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vfs_create_file,
|
||||
(sqlite3_vfs *pVfs, const char *zFilename,
|
||||
const unsigned char * pData, int nData)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_vfs_create_file( sqlite3_vfs *pVfs,
|
||||
const char *zFilename,
|
||||
const unsigned char * pData,
|
||||
int nData ){
|
||||
int rc;
|
||||
sqlite3_file *pFile = 0;
|
||||
sqlite3_io_methods const *pIo;
|
||||
@@ -1525,9 +1538,10 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vfs_create_file,
|
||||
** zFilename, appends pData bytes to it, and returns 0 on success or
|
||||
** SQLITE_IOERR on error.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_posix_create_file,
|
||||
(const char *zFilename, const unsigned char * pData,
|
||||
int nData)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_posix_create_file( const char *zFilename,
|
||||
const unsigned char * pData,
|
||||
int nData ){
|
||||
int rc;
|
||||
FILE * pFile = 0;
|
||||
int fileExisted = 0;
|
||||
@@ -1547,30 +1561,22 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_posix_create_file,
|
||||
** This function is NOT part of the sqlite3 public API. It is strictly
|
||||
** for use by the sqlite project's own JS/WASM bindings.
|
||||
**
|
||||
** This returns either a pointer to a static buffer or zKeyIn directly
|
||||
** (if zClass is NULL or empty).
|
||||
** Allocates sqlite3KvvfsMethods.nKeySize bytes from
|
||||
** sqlite3__wasm_pstack_alloc() and returns 0 if that allocation fails,
|
||||
** else it passes that string to kvstorageMakeKey() and returns a
|
||||
** NUL-terminated pointer to that string. It is up to the caller to
|
||||
** use sqlite3__wasm_pstack_restore() to free the returned pointer.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_kvvfsMakeKey,
|
||||
(const char *zClass, const char *zKeyIn)){
|
||||
static char buf[SQLITE_KVOS_SZ+1] = {0};
|
||||
SQLITE_WASM_EXPORT
|
||||
char * sqlite3__wasm_kvvfsMakeKeyOnPstack(const char *zClass,
|
||||
const char *zKeyIn){
|
||||
assert(sqlite3KvvfsMethods.nKeySize>24);
|
||||
if( zClass && *zClass ){
|
||||
kvrecordMakeKey(zClass, zKeyIn, buf);
|
||||
return buf;
|
||||
}else{
|
||||
#if 1
|
||||
/* We can return zKeyIn here only because the JS API takes special
|
||||
** care with its lifetime.*/
|
||||
return zKeyIn;
|
||||
#else
|
||||
/* It would be nice to be able to return zKeyIn directly here, but
|
||||
** it may have been allocated as part of the automated JS-to-WASM
|
||||
** conversions, in which case it will be freed before reaching the
|
||||
** caller. */
|
||||
sqlite3_snprintf(KVRECORD_KEY_SZ, buf, "%s", zKeyIn);
|
||||
return buf;
|
||||
#endif
|
||||
char *zKeyOut =
|
||||
(char *)sqlite3__wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize);
|
||||
if(zKeyOut){
|
||||
kvstorageMakeKey(zClass, zKeyIn, zKeyOut);
|
||||
}
|
||||
return zKeyOut;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1580,7 +1586,8 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_kvvfsMakeKey,
|
||||
** Returns the pointer to the singleton object which holds the kvvfs
|
||||
** I/O methods and associated state.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(sqlite3_kvvfs_methods *,sqlite3__wasm_kvvfs_methods,(void)){
|
||||
SQLITE_WASM_EXPORT
|
||||
sqlite3_kvvfs_methods * sqlite3__wasm_kvvfs_methods(void){
|
||||
return &sqlite3KvvfsMethods;
|
||||
}
|
||||
|
||||
@@ -1595,8 +1602,8 @@ SQLITE_WASM_EXPORT2(sqlite3_kvvfs_methods *,sqlite3__wasm_kvvfs_methods,(void)){
|
||||
** sqlite3_vtab_config(), or SQLITE_MISUSE if the 2nd arg is not a
|
||||
** valid value.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vtab_config,
|
||||
(sqlite3 *pDb, int op, int arg)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_vtab_config(sqlite3 *pDb, int op, int arg){
|
||||
switch(op){
|
||||
case SQLITE_VTAB_DIRECTONLY:
|
||||
case SQLITE_VTAB_INNOCUOUS:
|
||||
@@ -1616,8 +1623,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vtab_config,
|
||||
** Wrapper for the variants of sqlite3_db_config() which take
|
||||
** (int,int*) variadic args.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_ip,
|
||||
(sqlite3 *pDb, int op, int arg1, int* pArg2)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
|
||||
switch(op){
|
||||
case SQLITE_DBCONFIG_ENABLE_FKEY:
|
||||
case SQLITE_DBCONFIG_ENABLE_TRIGGER:
|
||||
@@ -1652,9 +1659,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_ip,
|
||||
** Wrapper for the variants of sqlite3_db_config() which take
|
||||
** (void*,int,int) variadic args.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_pii,
|
||||
(sqlite3 *pDb, int op, void * pArg1, int arg2,
|
||||
int arg3)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){
|
||||
switch(op){
|
||||
case SQLITE_DBCONFIG_LOOKASIDE:
|
||||
return sqlite3_db_config(pDb, op, pArg1, arg2, arg3);
|
||||
@@ -1669,8 +1675,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_pii,
|
||||
** Wrapper for the variants of sqlite3_db_config() which take
|
||||
** (const char *) variadic args.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_s,(sqlite3 *pDb, int op,
|
||||
const char *zArg)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
|
||||
switch(op){
|
||||
case SQLITE_DBCONFIG_MAINDBNAME:
|
||||
return sqlite3_db_config(pDb, op, zArg);
|
||||
@@ -1686,7 +1692,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_s,(sqlite3 *pDb, int op,
|
||||
** Binding for combinations of sqlite3_config() arguments which take
|
||||
** a single integer argument.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_i,(int op, int arg)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_config_i(int op, int arg){
|
||||
return sqlite3_config(op, arg);
|
||||
}
|
||||
|
||||
@@ -1697,7 +1704,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_i,(int op, int arg)){
|
||||
** Binding for combinations of sqlite3_config() arguments which take
|
||||
** two int arguments.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_ii,(int op, int arg1, int arg2)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_config_ii(int op, int arg1, int arg2){
|
||||
return sqlite3_config(op, arg1, arg2);
|
||||
}
|
||||
|
||||
@@ -1708,7 +1716,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_ii,(int op, int arg1, int arg2)){
|
||||
** Binding for combinations of sqlite3_config() arguments which take
|
||||
** a single i64 argument.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_j,(int op, sqlite3_int64 arg)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_config_j(int op, sqlite3_int64 arg){
|
||||
return sqlite3_config(op, arg);
|
||||
}
|
||||
|
||||
@@ -1720,7 +1729,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_j,(int op, sqlite3_int64 arg)){
|
||||
** sqlite3_mprintf()'s %Q modifier (if addQuotes is true) or %q (if
|
||||
** addQuotes is 0). Returns NULL if z is NULL or on OOM.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(char *,sqlite3__wasm_qfmt_token,(char *z, int addQuotes)){
|
||||
SQLITE_WASM_EXPORT
|
||||
char * sqlite3__wasm_qfmt_token(char *z, int addQuotes){
|
||||
char * rc = 0;
|
||||
if( z ){
|
||||
rc = addQuotes
|
||||
@@ -1730,21 +1740,6 @@ SQLITE_WASM_EXPORT2(char *,sqlite3__wasm_qfmt_token,(char *z, int addQuotes)){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is NOT part of the sqlite3 public API. It is strictly
|
||||
** for use by the sqlite project's own JS/WASM bindings.
|
||||
**
|
||||
** A WASM wrapper for the interal os_kv.c:kvvfsDecode() for internal
|
||||
** use by the kvvfs v2 API.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_kvvfs_decode,(const char *a, char *aOut, int nOut)){
|
||||
return kvvfsDecode(a, aOut, nOut);
|
||||
}
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_kvvfs_encode,(const char *a, int nA, char *aOut)){
|
||||
return kvvfsEncode(a, nA, aOut);
|
||||
}
|
||||
|
||||
|
||||
#if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS)
|
||||
#include <emscripten/console.h>
|
||||
#include <emscripten/wasmfs.h>
|
||||
@@ -1770,7 +1765,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_kvvfs_encode,(const char *a, int nA, char
|
||||
** the virtual FS fails. In builds compiled without SQLITE_ENABLE_WASMFS
|
||||
** defined, SQLITE_NOTFOUND is returned without side effects.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_init_wasmfs,(const char *zMountPoint)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_init_wasmfs(const char *zMountPoint){
|
||||
static backend_t pOpfs = 0;
|
||||
if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs";
|
||||
if( !pOpfs ){
|
||||
@@ -1789,7 +1785,8 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_init_wasmfs,(const char *zMountPoint)){
|
||||
return pOpfs ? 0 : SQLITE_NOMEM;
|
||||
}
|
||||
#else
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_init_wasmfs,(const char *zUnused)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_init_wasmfs(const char *zUnused){
|
||||
//emscripten_console_warn("WASMFS OPFS is not compiled in.");
|
||||
(void)zUnused;
|
||||
return SQLITE_NOTFOUND;
|
||||
@@ -1798,43 +1795,52 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_init_wasmfs,(const char *zUnused)){
|
||||
|
||||
#if SQLITE_WASM_ENABLE_C_TESTS
|
||||
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_test_intptr,(int * p)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_test_intptr(int * p){
|
||||
return *p = *p * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT2(void *,sqlite3__wasm_test_voidptr,(void * p)){
|
||||
SQLITE_WASM_EXPORT
|
||||
void * sqlite3__wasm_test_voidptr(void * p){
|
||||
return p;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT2(int64_t,sqlite3__wasm_test_int64_max,(void)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int64_t sqlite3__wasm_test_int64_max(void){
|
||||
return (int64_t)0x7fffffffffffffff;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT2(int64_t,sqlite3__wasm_test_int64_min,(void)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int64_t sqlite3__wasm_test_int64_min(void){
|
||||
return ~sqlite3__wasm_test_int64_max();
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT2(int64_t,sqlite3__wasm_test_int64_times2,(int64_t x)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int64_t sqlite3__wasm_test_int64_times2(int64_t x){
|
||||
return x * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT2(void,sqlite3__wasm_test_int64_minmax,(int64_t * min, int64_t *max)){
|
||||
SQLITE_WASM_EXPORT
|
||||
void sqlite3__wasm_test_int64_minmax(int64_t * min, int64_t *max){
|
||||
*max = sqlite3__wasm_test_int64_max();
|
||||
*min = sqlite3__wasm_test_int64_min();
|
||||
/*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT2(int64_t,sqlite3__wasm_test_int64ptr,(int64_t * p)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int64_t sqlite3__wasm_test_int64ptr(int64_t * p){
|
||||
/*printf("sqlite3__wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
|
||||
return *p = *p * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT2(void,sqlite3__wasm_test_stack_overflow,(int recurse)){
|
||||
SQLITE_WASM_EXPORT
|
||||
void sqlite3__wasm_test_stack_overflow(int recurse){
|
||||
if(recurse) sqlite3__wasm_test_stack_overflow(recurse);
|
||||
}
|
||||
|
||||
/* For testing the 'string:dealloc' whwasmutil.xWrap() conversion. */
|
||||
SQLITE_WASM_EXPORT2(char *,sqlite3__wasm_test_str_hello,(int fail)){
|
||||
SQLITE_WASM_EXPORT
|
||||
char * sqlite3__wasm_test_str_hello(int fail){
|
||||
char * s = fail ? 0 : (char *)sqlite3_malloc(6);
|
||||
if(s){
|
||||
memcpy(s, "hello", 5);
|
||||
@@ -1948,8 +1954,8 @@ static int sqlite3__wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
|
||||
return *z==0;
|
||||
}
|
||||
|
||||
SQLITE_WASM_EXPORT2(int,sqlite3__wasm_SQLTester_strglob,
|
||||
(const char *zGlob, const char *z)){
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3__wasm_SQLTester_strglob(const char *zGlob, const char *z){
|
||||
return !sqlite3__wasm_SQLTester_strnotglob(zGlob, z);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,10 @@
|
||||
slightly simpler client-side interface than the slightly-lower-level
|
||||
Worker API does.
|
||||
|
||||
In non-ESM builds this file necessarily exposes one global symbol,
|
||||
but clients may freely `delete` that symbol after calling it.
|
||||
This script necessarily exposes one global symbol, but clients may
|
||||
freely `delete` that symbol after calling it.
|
||||
*/
|
||||
//#if not defined target:es6-module
|
||||
'use strict';
|
||||
//#endif
|
||||
/**
|
||||
Configures an sqlite3 Worker API #1 Worker such that it can be
|
||||
manipulated via a Promise-based interface and returns a factory
|
||||
@@ -111,12 +109,10 @@
|
||||
the callback is called one time for each row of the result set,
|
||||
passed the same worker message format as the worker API emits:
|
||||
|
||||
{
|
||||
type:typeString,
|
||||
{type:typeString,
|
||||
row:VALUE,
|
||||
rowNumber:1-based-#,
|
||||
columnNames: array
|
||||
}
|
||||
columnNames: array}
|
||||
|
||||
Where `typeString` is an internally-synthesized message type string
|
||||
used temporarily for worker message dispatching. It can be ignored
|
||||
@@ -127,9 +123,10 @@
|
||||
callback.
|
||||
|
||||
At the end of the result set, the same event is fired with
|
||||
(row=undefined, rowNumber=null) to indicate that the end of the
|
||||
result set has been reached. The rows arrive via worker-posted
|
||||
messages, with all the implications of that.
|
||||
(row=undefined, rowNumber=null) to indicate that
|
||||
the end of the result set has been reached. Note that the rows
|
||||
arrive via worker-posted messages, with all the implications
|
||||
of that.
|
||||
|
||||
Notable shortcomings:
|
||||
|
||||
@@ -260,9 +257,7 @@ globalThis.sqlite3Worker1Promiser.defaultConfig = {
|
||||
type: 'module'
|
||||
});
|
||||
//#elif target:es6-module
|
||||
return new Worker(new URL("sqlite3-worker1.mjs", import.meta.url),{
|
||||
type: 'module'
|
||||
});
|
||||
return new Worker(new URL("sqlite3-worker1.js", import.meta.url));
|
||||
//#else
|
||||
let theJs = "sqlite3-worker1.js";
|
||||
if(this.currentScript){
|
||||
@@ -286,7 +281,7 @@ globalThis.sqlite3Worker1Promiser.defaultConfig = {
|
||||
})
|
||||
//#endif
|
||||
,
|
||||
onerror: (...args)=>console.error('sqlite3Worker1Promiser():',...args)
|
||||
onerror: (...args)=>console.error('worker1 promiser error',...args)
|
||||
}/*defaultConfig*/;
|
||||
|
||||
/**
|
||||
@@ -348,7 +343,6 @@ globalThis.sqlite3Worker1Promiser.v2.defaultConfig =
|
||||
incompatibility.
|
||||
*/
|
||||
export default sqlite3Worker1Promiser.v2;
|
||||
delete globalThis.sqlite3Worker1Promiser;
|
||||
//#endif /* target:es6-module */
|
||||
//#else
|
||||
/* Built with the omit-oo1 flag. */
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
directory from which `sqlite3.js` will be loaded.
|
||||
*/
|
||||
//#if target:es6-bundler-friendly
|
||||
import sqlite3InitModule from './sqlite3-bundler-friendly.mjs';
|
||||
import {default as sqlite3InitModule} from './sqlite3-bundler-friendly.mjs';
|
||||
//#elif target:es6-module
|
||||
import sqlite3InitModule from './sqlite3.mjs';
|
||||
return new Worker(new URL("sqlite3.js", import.meta.url));
|
||||
//#else
|
||||
"use strict";
|
||||
{
|
||||
|
||||
@@ -2603,7 +2603,7 @@ static int arg_is_flag( char const *zFlag, char const *zArg,
|
||||
|
||||
static void define_argv(int argc, char const * const * argv){
|
||||
sqlite3_str * const s = sqlite3_str_new(g.db);
|
||||
sqlite3_str_append(s, "c-pp::argv=", 11);
|
||||
sqlite3_str_append(s, "c-pp::ARGV=", 11);
|
||||
for( int i = 0; i < argc; ++i ){
|
||||
if( i ) sqlite3_str_appendchar(s, 1, ' ');
|
||||
sqlite3_str_appendf(s, "%s", argv[i]);
|
||||
|
||||
@@ -44,8 +44,7 @@
|
||||
/** abort() if expr is false. If expr is a function, it
|
||||
is called and its result is evaluated.
|
||||
*/
|
||||
assert: function f(expr, ...msg){
|
||||
msg = msg?.join?.(' ');
|
||||
assert: function f(expr, msg){
|
||||
if(!f._){
|
||||
f._ = ('undefined'===typeof abort
|
||||
? (msg)=>{throw new Error(msg)}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
(function(){
|
||||
const T = globalThis.SqliteTestUtil;
|
||||
const T = self.SqliteTestUtil;
|
||||
const toss = function(...args){throw new Error(args.join(' '))};
|
||||
const debug = console.debug.bind(console);
|
||||
const eOutput = document.querySelector('#test-output');
|
||||
@@ -40,7 +40,7 @@
|
||||
const error = function(...args){
|
||||
logHtml('error',...args);
|
||||
};
|
||||
|
||||
|
||||
const runTests = function(sqlite3){
|
||||
const capi = sqlite3.capi,
|
||||
oo = sqlite3.oo1,
|
||||
@@ -51,7 +51,7 @@
|
||||
error("This build is not kvvfs-capable.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const dbStorage = 0 ? 'session' : 'local';
|
||||
const theStore = 's'===dbStorage[0] ? sessionStorage : localStorage;
|
||||
const db = new oo.JsStorageDb( dbStorage );
|
||||
@@ -108,7 +108,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
sqlite3InitModule(globalThis.sqlite3TestModule).then((sqlite3)=>{
|
||||
sqlite3InitModule(self.sqlite3TestModule).then((sqlite3)=>{
|
||||
runTests(sqlite3);
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
<link rel="stylesheet" href="common/emscripten.css"/>
|
||||
<link rel="stylesheet" href="common/testing.css"/>
|
||||
//#if target:es6-module
|
||||
<title>Worker1-promiser (ESM) tests</title>
|
||||
//#if target=es6-module
|
||||
<title>worker-promise (via ESM) tests</title>
|
||||
//#else
|
||||
<title>Worker1-promiser tests</title>
|
||||
<title>worker-promise tests</title>
|
||||
//#endif
|
||||
</head>
|
||||
<body>
|
||||
@@ -32,7 +32,7 @@
|
||||
<hr>
|
||||
<div id='test-output'></div>
|
||||
<script src="common/SqliteTestUtil.js"></script>
|
||||
//#if target:es6-module
|
||||
//#if target=es6-module
|
||||
<script src="demo-worker1-promiser.mjs" type="module"></script>
|
||||
//#else
|
||||
<script src="jswasm/sqlite3-worker1-promiser.js"></script>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
(function(){
|
||||
const T = globalThis.SqliteTestUtil;
|
||||
const T = self.SqliteTestUtil;
|
||||
const SW = new Worker("jswasm/sqlite3-worker1.js");
|
||||
const DbState = {
|
||||
id: undefined
|
||||
@@ -323,7 +323,7 @@
|
||||
switch(ev.result){
|
||||
case 'worker1-ready':
|
||||
log("Message:",ev);
|
||||
globalThis.sqlite3TestModule.setStatus(null);
|
||||
self.sqlite3TestModule.setStatus(null);
|
||||
runTests();
|
||||
return;
|
||||
default:
|
||||
@@ -344,5 +344,5 @@
|
||||
};
|
||||
log("Init complete, but async init bits may still be running.");
|
||||
log("Installing Worker into global scope SW for dev purposes.");
|
||||
globalThis.SW = SW;
|
||||
self.SW = SW;
|
||||
})();
|
||||
|
||||
@@ -175,6 +175,10 @@
|
||||
"features (e.g. upload) do not yet work with OPFS.");
|
||||
}
|
||||
stdout('\nEnter ".help" for usage hints.');
|
||||
this.exec([ // initialization commands...
|
||||
'.nullvalue NULL',
|
||||
'.headers on'
|
||||
].join('\n'));
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -5,29 +5,20 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>SQLite3 Fiddle</title>
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
//#if jqterm
|
||||
<!--
|
||||
To add a terminal-style view using jquery.terminal[^1],
|
||||
uncomment the following two HTML lines and ensure that these
|
||||
files are on the web server.
|
||||
|
||||
jquery.terminal.bundle.min.js is a concatenation of jquery.min.js from
|
||||
jquery-bundle.min.js is a concatenation of jquery.min.js from
|
||||
[^2] and jquery.terminal.min.js from [^1].
|
||||
jquery.terminal.min.css is from [^1]. Alterntely, jquery-VERSION.min.js
|
||||
can be found in jquery.terminal's source tree.
|
||||
|
||||
Fiddle automatically enables support for this if it's installed.
|
||||
|
||||
In the canonical build process, if the JQTERM env var is set
|
||||
to a dir containing a clone of [^1] then this block gets
|
||||
enabled and a copy of [^1] is integrated automatically.
|
||||
jquery.terminal.min.css is from [^1].
|
||||
|
||||
[^1]: https://github.com/jcubic/jquery.terminal
|
||||
[^2]: https://jquery.com
|
||||
-->
|
||||
<script src="jqterm/jquery.terminal.bundle.min.js"></script>
|
||||
<link rel="stylesheet" href="jqterm/jquery.terminal.min.css">
|
||||
//#endif
|
||||
<!--script src="jqterm/jqterm-bundle.min.js"></script>
|
||||
<link rel="stylesheet" href="jqterm/jquery.terminal.min.css"-->
|
||||
<style>
|
||||
/* The following styles are for app-level use. */
|
||||
:root {
|
||||
@@ -105,11 +105,6 @@
|
||||
(<a href='speedtest1-worker.html?size=15'>32-bit</a>,
|
||||
<a href='speedtest1-worker-64bit.html?size=15'>64-bit</a>):
|
||||
an interactive Worker-thread variant of speedtest1.</li>
|
||||
<li>speedtest1-worker?vfs=kvvfs
|
||||
(<a href='speedtest1-worker.html?vfs=kvvfs&size=10'>32-bit</a>,
|
||||
<a href='speedtest1-worker-64bit.html?vfs=kvvfs&size=10'>64-bit</a>):
|
||||
speedtest1-worker with the
|
||||
kvvfs VFS preselected and configured for a moderate workload.</li>
|
||||
<li>speedtest1-worker?vfs=opfs
|
||||
(<a href='speedtest1-worker.html?vfs=opfs&size=10'>32-bit</a>,
|
||||
<a href='speedtest1-worker-64bit.html?vfs=opfs&size=10'>64-bit</a>):
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ for arg in $@; do
|
||||
;;
|
||||
|
||||
--snapshot)
|
||||
snapshotSuffix=-snapshot-$(date +%Y%m%d)
|
||||
snapshotSuffix=$(date +%Y%m%d)
|
||||
;;
|
||||
|
||||
-?|--help)
|
||||
|
||||
+14
-25
@@ -40,22 +40,14 @@
|
||||
/*
|
||||
** Flags for use with BuildDef::flags.
|
||||
**
|
||||
** Maintenance reminder: do not combine F_... flags within this enum,
|
||||
** e.g. F_BUNDLER_FRIENDLY=0x02|F_ESM, as that will lead to breakage
|
||||
** in some of the flag checks.
|
||||
** Maintenance reminder: do not combine flags within this enum,
|
||||
** e.g. F_BUNDLER_FRIENDLY=0x02|F_ESM, as that will lead
|
||||
** to breakage in some of the flag checks.
|
||||
*/
|
||||
enum BuildDefFlags {
|
||||
/* Indicates an ESM module build. */
|
||||
F_ESM = 0x01,
|
||||
/* Indicates a "bundler-friendly" build mode. These are untested and
|
||||
** unsupported, provided solely for the downstream npm subproject
|
||||
** (who is responsible for any testing of these).
|
||||
**
|
||||
** The only difference beween bundler-friendly and esm builds is
|
||||
** that bundlers require static filename strings in a few places due
|
||||
** to limitations of bundler tooling, whereas vanilla and JS can
|
||||
** both work with dynamic strings.
|
||||
*/
|
||||
/* Indicates a "bundler-friendly" build mode. */
|
||||
F_BUNDLER_FRIENDLY = 1<<1,
|
||||
/* Indicates that this build is unsupported. Such builds are not
|
||||
** added to the 'all' target. The unsupported builds exist primarily
|
||||
@@ -65,11 +57,8 @@ enum BuildDefFlags {
|
||||
F_NOT_IN_ALL = 1<<3,
|
||||
/* If it's a 64-bit build. */
|
||||
F_64BIT = 1<<4,
|
||||
/* Indicates a node.js-for-node.js build. This build is very
|
||||
** specificially untested and unsupported, but the downstream npm
|
||||
** project makes use of it. None of our JS code is specific to node,
|
||||
** but Emscripten's generated sqlite3.js differs between
|
||||
** for-the-browser and for-node builds. */
|
||||
/* Indicates a node.js-for-node.js build (untested and
|
||||
** unsupported). */
|
||||
F_NODEJS = 1<<5,
|
||||
/* Indicates a wasmfs build (untested and unsupported). */
|
||||
F_WASMFS = 1<<6,
|
||||
@@ -88,7 +77,7 @@ enum BuildDefFlags {
|
||||
** differ, however.
|
||||
*/
|
||||
CP_JS = 1 << 30, /* X.js or X.mjs, depending on F_ESM */
|
||||
CP_WASM = 1 << 31, /* X.wasm */
|
||||
CP_WASM = 1 << 31, /* X,wasm */
|
||||
CP_ALL = CP_JS | CP_WASM
|
||||
};
|
||||
|
||||
@@ -151,7 +140,7 @@ struct BuildDef {
|
||||
**
|
||||
** The convention for 32- vs 64-bit pairs is to give them similar
|
||||
** emoji, e.g. a cookie for 32-bit and a donut or cake for 64.
|
||||
** Alternately, the same emoji with a "64" suffix, except that that
|
||||
** Alternately, the same emoji a "64" suffix, except that that
|
||||
** throws off the output alignment in parallel builds ;).
|
||||
*/
|
||||
const char *zEmo;
|
||||
@@ -175,7 +164,7 @@ struct BuildDef {
|
||||
** Makefile code "ifeq (...)". If set, this build is enclosed in a
|
||||
** $zIfCond/endif block.
|
||||
*/
|
||||
const char *zIfCond;
|
||||
const char *zIfCond; /* makefile "ifeq (...)" or similar */
|
||||
int flags; /* Flags from BuildDefFlags */
|
||||
};
|
||||
typedef struct BuildDef BuildDef;
|
||||
@@ -191,7 +180,7 @@ typedef struct BuildDef BuildDef;
|
||||
** logtag.NAME = Used for decorating log output
|
||||
**
|
||||
** etc.
|
||||
*/
|
||||
***/
|
||||
#define BuildDefs_map(E) \
|
||||
E(vanilla) E(vanilla64) \
|
||||
E(esm) E(esm64) \
|
||||
@@ -352,7 +341,7 @@ const BuildDefs oBuildDefs = {
|
||||
.zEnv = 0,
|
||||
.zDeps = 0,
|
||||
.zIfCond = 0,
|
||||
.flags = CP_JS | F_BUNDLER_FRIENDLY | F_ESM | F_NOT_IN_ALL
|
||||
.flags = CP_JS | F_BUNDLER_FRIENDLY | F_ESM
|
||||
},
|
||||
|
||||
/* 64-bit bundler-friendly. */
|
||||
@@ -493,8 +482,8 @@ static void mk_prologue(void){
|
||||
** configuration). Comments like "saves nothing" may not be
|
||||
** technically correct: "nothing" means "some neglible amount."
|
||||
**
|
||||
** Performance gains or losses are _not_ taken into account
|
||||
** here, only wasm file size.
|
||||
** Note that performance gains/losses are _not_ taken into
|
||||
** account here: only wasm file size.
|
||||
*/
|
||||
"--enable-bulk-memory-opt " /* required */
|
||||
"--all-features " /* required */
|
||||
@@ -1063,7 +1052,7 @@ int main(int argc, char const ** argv){
|
||||
BuildDefs_map(E) if( 0==strcmp("prologue",zArg) ){
|
||||
mk_prologue();
|
||||
}else {
|
||||
fprintf(stderr,"Unknown build name: %s\n", zArg);
|
||||
fprintf(stderr,"Unkown build name: %s\n", zArg);
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
(function(){
|
||||
let speedtestJs = 'speedtest1.js';
|
||||
const urlParams = new URL(globalThis.location.href).searchParams;
|
||||
const urlParams = new URL(self.location.href).searchParams;
|
||||
if(urlParams.has('sqlite3.dir')){
|
||||
speedtestJs = urlParams.get('sqlite3.dir') + '/' + speedtestJs;
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
const wasmfsDir = function f(wasmUtil){
|
||||
if(undefined !== f._) return f._;
|
||||
const pdir = '/opfs';
|
||||
if( !globalThis.FileSystemHandle
|
||||
|| !globalThis.FileSystemDirectoryHandle
|
||||
|| !globalThis.FileSystemFileHandle){
|
||||
if( !self.FileSystemHandle
|
||||
|| !self.FileSystemDirectoryHandle
|
||||
|| !self.FileSystemFileHandle){
|
||||
return f._ = "";
|
||||
}
|
||||
try{
|
||||
@@ -92,7 +92,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
globalThis.onmessage = function(msg){
|
||||
self.onmessage = function(msg){
|
||||
msg = msg.data;
|
||||
switch(msg.type){
|
||||
case 'run':
|
||||
@@ -111,8 +111,7 @@
|
||||
setStatus: (text)=>mPost('load-status',text)
|
||||
};
|
||||
log("Initializing speedtest1 module...");
|
||||
globalThis.sqlite3InitModule.__isUnderTest = true;
|
||||
globalThis.sqlite3InitModule(EmscriptenModule).then(async (sqlite3)=>{
|
||||
self.sqlite3InitModule(EmscriptenModule).then(async (sqlite3)=>{
|
||||
const S = globalThis.S = App.sqlite3 = sqlite3;
|
||||
log("Loaded speedtest1 module. Setting up...");
|
||||
App.pDir = wasmfsDir(S.wasm);
|
||||
|
||||
+99
-104
@@ -44,137 +44,132 @@
|
||||
mounted, else it returns an empty string.
|
||||
*/
|
||||
const wasmfsDir = function f(wasmUtil){
|
||||
if(undefined !== f._) return f._;
|
||||
const pdir = '/persistent';
|
||||
if( !self.FileSystemHandle
|
||||
|| !self.FileSystemDirectoryHandle
|
||||
|| !self.FileSystemFileHandle){
|
||||
return f._ = "";
|
||||
}
|
||||
try{
|
||||
if(0===wasmUtil.xCallWrapped(
|
||||
'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
|
||||
)){
|
||||
return f._ = pdir;
|
||||
}else{
|
||||
return f._ = "";
|
||||
if(undefined !== f._) return f._;
|
||||
const pdir = '/persistent';
|
||||
if( !self.FileSystemHandle
|
||||
|| !self.FileSystemDirectoryHandle
|
||||
|| !self.FileSystemFileHandle){
|
||||
return f._ = "";
|
||||
}
|
||||
try{
|
||||
if(0===wasmUtil.xCallWrapped(
|
||||
'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
|
||||
)){
|
||||
return f._ = pdir;
|
||||
}else{
|
||||
return f._ = "";
|
||||
}
|
||||
}catch(e){
|
||||
// sqlite3_wasm_init_wasmfs() is not available
|
||||
return f._ = "";
|
||||
}
|
||||
}catch(e){
|
||||
// sqlite3_wasm_init_wasmfs() is not available
|
||||
return f._ = "";
|
||||
}
|
||||
};
|
||||
wasmfsDir._ = undefined;
|
||||
|
||||
const eOut = document.querySelector('#test-output');
|
||||
const log2 = function(cssClass,...args){
|
||||
const ln = document.createElement('div');
|
||||
if(cssClass) ln.classList.add(cssClass);
|
||||
ln.append(document.createTextNode(args.join(' ')));
|
||||
eOut.append(ln);
|
||||
//this.e.output.lastElementChild.scrollIntoViewIfNeeded();
|
||||
const ln = document.createElement('div');
|
||||
if(cssClass) ln.classList.add(cssClass);
|
||||
ln.append(document.createTextNode(args.join(' ')));
|
||||
eOut.append(ln);
|
||||
//this.e.output.lastElementChild.scrollIntoViewIfNeeded();
|
||||
};
|
||||
const logList = [];
|
||||
const dumpLogList = function(){
|
||||
logList.forEach((v)=>log2('',v));
|
||||
logList.length = 0;
|
||||
logList.forEach((v)=>log2('',v));
|
||||
logList.length = 0;
|
||||
};
|
||||
/* we cannot update DOM while speedtest is running unless we run
|
||||
speedtest in a worker thread. */;
|
||||
const log = (...args)=>{
|
||||
console.log(...args);
|
||||
logList.push(args.join(' '));
|
||||
console.log(...args);
|
||||
logList.push(args.join(' '));
|
||||
};
|
||||
const logErr = function(...args){
|
||||
console.error(...args);
|
||||
logList.push('ERROR: '+args.join(' '));
|
||||
console.error(...args);
|
||||
logList.push('ERROR: '+args.join(' '));
|
||||
};
|
||||
|
||||
const runTests = function(sqlite3){
|
||||
globalThis.S = sqlite3;
|
||||
const capi = sqlite3.capi, wasm = sqlite3.wasm;
|
||||
//console.debug('sqlite3 (global S) =',sqlite3);
|
||||
const pDir = wasmfsDir(wasm);
|
||||
if(pDir){
|
||||
console.warn("wasmfs storage:",pDir);
|
||||
}
|
||||
const scope = wasm.scopedAllocPush();
|
||||
let dbFile = pDir+"/speedtest1.db";
|
||||
const urlParams = new URL(self.location.href).searchParams;
|
||||
const argv = ["speedtest1"];
|
||||
if(urlParams.has('flags')){
|
||||
argv.push(...(urlParams.get('flags').split(',')));
|
||||
}
|
||||
const capi = sqlite3.capi, wasm = sqlite3.wasm;
|
||||
//console.debug('sqlite3 =',sqlite3);
|
||||
const pDir = wasmfsDir(wasm);
|
||||
if(pDir){
|
||||
console.warn("Persistent storage:",pDir);
|
||||
}
|
||||
const scope = wasm.scopedAllocPush();
|
||||
let dbFile = pDir+"/speedtest1.db";
|
||||
const urlParams = new URL(self.location.href).searchParams;
|
||||
const argv = ["speedtest1"];
|
||||
if(urlParams.has('flags')){
|
||||
argv.push(...(urlParams.get('flags').split(',')));
|
||||
}
|
||||
|
||||
let forceSize = 0;
|
||||
let vfs, pVfs = 0;
|
||||
if(urlParams.has('vfs')){
|
||||
vfs = urlParams.get('vfs');
|
||||
pVfs = capi.sqlite3_vfs_find(vfs);
|
||||
if(!pVfs){
|
||||
log2('error',"Unknown VFS:",vfs);
|
||||
return;
|
||||
let forceSize = 0;
|
||||
let vfs, pVfs = 0;
|
||||
if(urlParams.has('vfs')){
|
||||
vfs = urlParams.get('vfs');
|
||||
pVfs = capi.sqlite3_vfs_find(vfs);
|
||||
if(!pVfs){
|
||||
log2('error',"Unknown VFS:",vfs);
|
||||
return;
|
||||
}
|
||||
argv.push("--vfs", vfs);
|
||||
log2('',"Using VFS:",vfs);
|
||||
if('kvvfs' === vfs){
|
||||
forceSize = 2 /* >2 is too big as of mid-2025 */;
|
||||
dbFile = 'session';
|
||||
log2('warning',"kvvfs VFS: forcing --size",forceSize,
|
||||
"and filename '"+dbFile+"'.");
|
||||
capi.sqlite3_js_kvvfs_clear(dbFile);
|
||||
}
|
||||
}
|
||||
argv.push("--vfs", vfs);
|
||||
log2('',"Using VFS:",vfs);
|
||||
if('kvvfs' === vfs){
|
||||
forceSize = 5
|
||||
/* --size > 2 is too big for local/session storage
|
||||
as of mid-2025, but kvvfs v2 (late 2025)
|
||||
lets us use transient storage. */;
|
||||
dbFile = 'transient';
|
||||
log2('warning',"kvvfs VFS: forcing --size",forceSize,
|
||||
"and filename '"+dbFile+"'.");
|
||||
capi.sqlite3_js_kvvfs_clear(dbFile);
|
||||
}
|
||||
}
|
||||
if(forceSize){
|
||||
argv.push('--size',forceSize);
|
||||
}else{
|
||||
[
|
||||
'size'
|
||||
].forEach(function(k){
|
||||
const v = urlParams.get(k);
|
||||
if(v && +v) argv.push('--'+k, urlParams[k]);
|
||||
});
|
||||
}
|
||||
argv.push(
|
||||
"--singlethread",
|
||||
//"--nomutex",
|
||||
//"--nosync",
|
||||
//"--memdb", // note that memdb trumps the filename arg
|
||||
"--nomemstat"
|
||||
);
|
||||
argv.push("--big-transactions"/*important for tests 410 and 510!*/,
|
||||
dbFile);
|
||||
console.log("argv =",argv);
|
||||
// These log messages are not emitted to the UI until after main() returns. Fixing that
|
||||
// requires moving the main() call and related cleanup into a timeout handler.
|
||||
if(pDir) wasm.sqlite3_wasm_vfs_unlink(pVfs,dbFile);
|
||||
log2('',"WASM heap size:",sqlite3.wasm.heap8().byteLength,"bytes");
|
||||
log2('',"WASM pointer size:",sqlite3.wasm.ptr.size);
|
||||
log2('',"Starting native app:\n ",argv.join(' '));
|
||||
log2('',"This will take a while and the browser might warn about the runaway JS.",
|
||||
"Give it time...");
|
||||
logList.length = 0;
|
||||
setTimeout(function(){
|
||||
wasm.xCall('wasm_main', argv.length,
|
||||
wasm.scopedAllocMainArgv(argv));
|
||||
wasm.scopedAllocPop(scope);
|
||||
if('kvvfs'===vfs){
|
||||
logList.unshift("KVVFS "+dbFile+" size = "+
|
||||
capi.sqlite3_js_kvvfs_size(dbFile));
|
||||
if(forceSize){
|
||||
argv.push('--size',forceSize);
|
||||
}else{
|
||||
[
|
||||
'size'
|
||||
].forEach(function(k){
|
||||
const v = urlParams.get(k);
|
||||
if(v) argv.push('--'+k, urlParams[k]);
|
||||
});
|
||||
}
|
||||
argv.push(
|
||||
"--singlethread",
|
||||
//"--nomutex",
|
||||
//"--nosync",
|
||||
//"--memdb", // note that memdb trumps the filename arg
|
||||
"--nomemstat"
|
||||
);
|
||||
argv.push("--big-transactions"/*important for tests 410 and 510!*/,
|
||||
dbFile);
|
||||
console.log("argv =",argv);
|
||||
// These log messages are not emitted to the UI until after main() returns. Fixing that
|
||||
// requires moving the main() call and related cleanup into a timeout handler.
|
||||
if(pDir) wasm.sqlite3_wasm_vfs_unlink(pVfs,dbFile);
|
||||
logList.unshift("Done running native main(). Output:");
|
||||
dumpLogList();
|
||||
log2('',"WASM heap size:",sqlite3.wasm.heap8().byteLength,"bytes");
|
||||
}, 50);
|
||||
log2('',"WASM pointer size:",sqlite3.wasm.ptr.size);
|
||||
log2('',"Starting native app:\n ",argv.join(' '));
|
||||
log2('',"This will take a while and the browser might warn about the runaway JS.",
|
||||
"Give it time...");
|
||||
logList.length = 0;
|
||||
setTimeout(function(){
|
||||
wasm.xCall('wasm_main', argv.length,
|
||||
wasm.scopedAllocMainArgv(argv));
|
||||
wasm.scopedAllocPop(scope);
|
||||
if('kvvfs'===vfs){
|
||||
logList.unshift("KVVFS "+dbFile+" size = "+
|
||||
capi.sqlite3_js_kvvfs_size(dbFile));
|
||||
}
|
||||
if(pDir) wasm.sqlite3_wasm_vfs_unlink(pVfs,dbFile);
|
||||
logList.unshift("Done running native main(). Output:");
|
||||
dumpLogList();
|
||||
log2('',"WASM heap size:",sqlite3.wasm.heap8().byteLength,"bytes");
|
||||
}, 50);
|
||||
}/*runTests()*/;
|
||||
|
||||
self.sqlite3TestModule.print = log;
|
||||
self.sqlite3TestModule.printErr = logErr;
|
||||
sqlite3InitModule.__isUnderTest = true;
|
||||
sqlite3InitModule(self.sqlite3TestModule).then(runTests);
|
||||
})();</script>
|
||||
</body>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1 id='color-target'>sqlite3 tester #1: Worker thread (@bitness@-bit WASM)</h1>
|
||||
<div>Variants:
|
||||
<div>Variants (32-bit):
|
||||
conventional UI thread:
|
||||
(<a href='tester1.html' target='tester1.html'>32-bit</a>,
|
||||
<a href='tester1-64bit.html' target='tester1-64bit.html'>64-bit</a>),
|
||||
|
||||
+25
-583
@@ -153,10 +153,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
logClass('error',...args);
|
||||
};
|
||||
|
||||
const debug = (...args)=>{
|
||||
console.debug('tester1',...args);
|
||||
};
|
||||
|
||||
const toss = (...args)=>{
|
||||
error(...args);
|
||||
throw new Error(args.join(' '));
|
||||
@@ -214,9 +210,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
filter.test(error.message) passes. If it's a function, the test
|
||||
passes if filter(error) returns truthy. If it's a string, the
|
||||
test passes if the filter matches the exception message
|
||||
precisely. If filter is a number then it is compared against
|
||||
the resultCode property of the exception. In all other cases
|
||||
the test fails, throwing an Error.
|
||||
precisely. In all other cases the test fails, throwing an
|
||||
Error.
|
||||
|
||||
If it throws, msg is used as the error report unless it's falsy,
|
||||
in which case a default is used.
|
||||
@@ -230,9 +225,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
if(filter instanceof RegExp) pass = filter.test(err.message);
|
||||
else if(filter instanceof Function) pass = filter(err);
|
||||
else if('string' === typeof filter) pass = (err.message === filter);
|
||||
else if('number' === typeof filter) pass = (err.resultCode === filter);
|
||||
if(!pass){
|
||||
console.error("Filter",filter,"rejected exception",err);
|
||||
throw new Error(msg || ("Filter rejected this exception: <<"+err.message+">>"));
|
||||
}
|
||||
return this;
|
||||
@@ -520,7 +513,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
assert(wasmCtypes.structs[1/*sqlite3_io_methods*/
|
||||
].members.xFileSize.offset>0);
|
||||
[ /* Spot-check a handful of constants to make sure they got installed... */
|
||||
'SQLITE_SCHEMA','SQLITE_NULL','SQLITE_UTF8','SQLITE_UTF8_ZT',
|
||||
'SQLITE_SCHEMA','SQLITE_NULL','SQLITE_UTF8',
|
||||
'SQLITE_STATIC', 'SQLITE_DIRECTONLY',
|
||||
'SQLITE_OPEN_CREATE', 'SQLITE_OPEN_DELETEONCLOSE'
|
||||
].forEach((k)=>T.assert('number' === typeof capi[k]));
|
||||
@@ -2635,7 +2628,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
.assert(wasm.isPtr(tmplMod.$xRowid))
|
||||
.assert(wasm.isPtr(tmplMod.$xCreate))
|
||||
.assert(tmplMod.$xCreate === tmplMod.$xConnect,
|
||||
"setupModule() must make these equivalent and "+
|
||||
"setup() must make these equivalent and "+
|
||||
"installMethods() must avoid re-compiling identical functions");
|
||||
tmplMod.$xCreate = wasm.ptr.null /* make tmplMod eponymous-only */;
|
||||
let rc = capi.sqlite3_create_module(
|
||||
@@ -2886,69 +2879,25 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
T.g('kvvfs')
|
||||
.t({
|
||||
name: 'kvvfs v1 API availability',
|
||||
name: 'kvvfs is disabled in worker',
|
||||
predicate: ()=>(isWorker() || "test is only valid in a Worker"),
|
||||
test: function(sqlite3){
|
||||
const capi = sqlite3.capi;
|
||||
if( isUIThread() ){
|
||||
T.assert( !!capi.sqlite3_js_kvvfs_size )
|
||||
.assert( !!capi.sqlite3_js_kvvfs_clear );
|
||||
}else{
|
||||
/* Historical behaviour retained not for compatibility but
|
||||
to help avoid some confusion between the v1 and v2 kvvfs
|
||||
APIs (namely in how the v1 variants handle empty
|
||||
strings). */
|
||||
T.assert( !capi.sqlite3_js_kvvfs_clear )
|
||||
.assert( !capi.sqlite3_js_kvvfs_size );
|
||||
}
|
||||
const k = sqlite3.kvvfs;
|
||||
T.assert( k && 'object'===typeof k );
|
||||
for(const n of ['reserve', 'import', 'export',
|
||||
'unlink', 'listen', 'unlisten',
|
||||
'exists',
|
||||
'estimateSize', 'clear'] ){
|
||||
T.assert( k[n] instanceof Function );
|
||||
}
|
||||
|
||||
if( 0 ){
|
||||
const scope = wasm.scopedAllocPush();
|
||||
try{
|
||||
const pg = [
|
||||
"53514C69746520666F726D61742033b20b0101b402020d02d02l01d0",
|
||||
"4l01jb02b2E91E00Dd011FD3b1FD3dxl2B010617171701377461626C",
|
||||
"656B767666736B7676667302435245415445205441424C45206B76766673286129"
|
||||
].join('');
|
||||
const n = pg.length;
|
||||
const pI = wasm.scopedAlloc( n+1 );
|
||||
const nO = 8192 * 2;
|
||||
const pO = wasm.scopedAlloc( nO );
|
||||
const heap = wasm.heap8u();
|
||||
let i;
|
||||
for( i=0; i<n; ++i ){
|
||||
heap[wasm.ptr.add(pI, i)] = pg.codePointAt(i) & 0xff;
|
||||
}
|
||||
heap[wasm.ptr.add(pI, i)] = 0;
|
||||
const rc = wasm.exports.sqlite3__wasm_kvvfs_decode(pI, pO, nO);
|
||||
const u = heap.slice(pO, wasm.ptr.add(pO,rc));
|
||||
debug("decode rc=", rc, u);
|
||||
}finally{
|
||||
wasm.scopedAllocPop(scope);
|
||||
}
|
||||
}
|
||||
T.assert(
|
||||
!capi.sqlite3_vfs_find('kvvfs'),
|
||||
"Expecting kvvfs to be unregistered."
|
||||
);
|
||||
}
|
||||
}/*kvvfs API availability*/)
|
||||
})
|
||||
.t({
|
||||
name: 'kvvfs sessionStorage',
|
||||
predicate: ()=>(globalThis.sessionStorage || "sessionStorage is unavailable"),
|
||||
name: 'kvvfs in main thread',
|
||||
predicate: ()=>(isUIThread()
|
||||
|| "local/sessionStorage are unavailable in a Worker"),
|
||||
test: function(sqlite3){
|
||||
const JDb = sqlite3.oo1.JsStorageDb;
|
||||
const filename = this.kvvfsDbFile = 'session';
|
||||
const pVfs = capi.sqlite3_vfs_find('kvvfs');
|
||||
T.assert(looksLikePtr(pVfs));
|
||||
let x = sqlite3.kvvfs.internal.storageForZClass('session');
|
||||
T.assert( 0 === x.files.length )
|
||||
.assert( globalThis.sessionStorage===x.storage )
|
||||
.assert( 'kvvfs-session-' === x.keyPrefix );
|
||||
const filename = this.kvvfsDbFile = 'session';
|
||||
const unlink = this.kvvfsUnlink = ()=>sqlite3.kvvfs.clear(filename);
|
||||
const JDb = this.JDb = sqlite3.oo1.JsStorageDb;
|
||||
const unlink = this.kvvfsUnlink = ()=>JDb.clearStorage(this.kvvfsDbFile);
|
||||
unlink();
|
||||
let db = new JDb(filename);
|
||||
try {
|
||||
@@ -2956,8 +2905,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
'create table kvvfs(a);',
|
||||
'insert into kvvfs(a) values(1),(2),(3)'
|
||||
]);
|
||||
T.assert(3 === db.selectValue('select count(*) from kvvfs'))
|
||||
.assert( db.storageSize() > 0, "Db size counting is broken" );
|
||||
T.assert(3 === db.selectValue('select count(*) from kvvfs'));
|
||||
db.close();
|
||||
db = undefined;
|
||||
db = new JDb(filename);
|
||||
@@ -2966,523 +2914,17 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
}finally{
|
||||
if( db ) db.close();
|
||||
}
|
||||
//console.debug("sessionStorage",globalThis.sessionStorage);
|
||||
}
|
||||
}/*kvvfs sanity checks*/)
|
||||
.t({
|
||||
name: 'transient kvvfs',
|
||||
//predicate: ()=>false,
|
||||
test: function(sqlite3){
|
||||
const filename = '.' /* preinstalled instance */;
|
||||
const JDb = sqlite3.oo1.JsStorageDb;
|
||||
const DB = sqlite3.oo1.DB;
|
||||
T.mustThrowMatching(()=>new JDb(""), capi.SQLITE_MISUSE);
|
||||
T.mustThrowMatching(()=>{
|
||||
new JDb("this\ns an illegal - contains control characters");
|
||||
/* We don't have a way to get error strings from xOpen()
|
||||
to this point? xOpen() does not have a handle to the
|
||||
db and SQLite is not calling xGetLastError() to fetch
|
||||
the error string. */
|
||||
}, capi.SQLITE_RANGE);
|
||||
T.mustThrowMatching(()=>{new JDb("foo-journal");},
|
||||
capi.SQLITE_MISUSE);
|
||||
T.mustThrowMatching(()=>{new JDb("foo-wal");},
|
||||
capi.SQLITE_MISUSE);
|
||||
T.mustThrowMatching(()=>{new JDb("foo-shm");},
|
||||
capi.SQLITE_MISUSE);
|
||||
T.mustThrowMatching(()=>{
|
||||
new JDb("01234567890123456789"+
|
||||
"01234567890123456789"+
|
||||
"01234567890123456789"+
|
||||
"01234567890123456789"+
|
||||
"01234567890123456789"+
|
||||
"01234567890123456789"+
|
||||
"0"/*too long*/);
|
||||
}, capi.SQLITE_RANGE);
|
||||
{
|
||||
const name = "01234567890123456789012" /* max name length */;
|
||||
(new JDb(name)).close();
|
||||
T.assert( sqlite3.kvvfs.unlink(name) );
|
||||
}
|
||||
|
||||
sqlite3.kvvfs.clear(filename);
|
||||
let db = new JDb(filename);
|
||||
const sqlSetup = [
|
||||
'create table kvvfs(a);',
|
||||
'insert into kvvfs(a) values(1),(2),(3)'
|
||||
];
|
||||
try {
|
||||
T.assert( 0===db.storageSize(), "expecting 0 storage size" );
|
||||
T.mustThrowMatching(()=>db.clearStorage(), /in-use/);
|
||||
//db.clearStorage();
|
||||
T.assert( 0===db.storageSize(), "expecting 0 storage size" );
|
||||
db.exec(sqlSetup);
|
||||
T.assert( 0<db.storageSize(), "expecting non-0 db size" );
|
||||
T.mustThrowMatching(()=>db.clearStorage(), /in-use/);
|
||||
//db.clearStorage(/*wiping everything out from under it*/);
|
||||
T.assert( 0<db.storageSize(), "expecting non-0 storage size" );
|
||||
//db.exec(sqlSetup/*that actually worked*/);
|
||||
/* Clearing the storage out from under the db does actually
|
||||
work so long as we re-initialize it before reading.
|
||||
It is tentatively disallowed for sanity's sake rather
|
||||
than it not working.
|
||||
*/
|
||||
T.assert( 0<db.storageSize(), "expecting non-0 db size" );
|
||||
const close = ()=>{
|
||||
db.close();
|
||||
db = undefined;
|
||||
};
|
||||
T.assert(3 === db.selectValue('select count(*) from kvvfs'));
|
||||
close();
|
||||
|
||||
const exportDb = sqlite3.kvvfs.export;
|
||||
db = new JDb(filename);
|
||||
db.exec('insert into kvvfs(a) values(4),(5),(6)');
|
||||
T.assert(6 === db.selectValue('select count(*) from kvvfs'));
|
||||
const exp = exportDb({name:filename,includeJournal:true});
|
||||
T.assert( filename===exp.name, "Broken export filename" )
|
||||
.assert( exp?.size > 0, "Missing db size" )
|
||||
.assert( exp?.pages?.length > 0, "Missing db pages" );
|
||||
console.debug("kvvfs to Object:",exp);
|
||||
close();
|
||||
|
||||
const dbFileRaw = 'file:new-storage?vfs=kvvfs&delete-on-close=1';
|
||||
db = new DB({
|
||||
filename: dbFileRaw,
|
||||
//flags: 'ct'
|
||||
});
|
||||
db.exec(sqlSetup);
|
||||
const dbFilename = db.dbFilename();
|
||||
//console.warn("db.dbFilename() =",dbFilename);
|
||||
T.assert(3 === db.selectValue('select count(*) from kvvfs'));
|
||||
debug("kvvfs to Object:",exportDb(dbFilename));
|
||||
const n = sqlite3.kvvfs.estimateSize( dbFilename );
|
||||
T.assert( n>0, "Db size count failed" );
|
||||
|
||||
if( 1 ){
|
||||
// Concurrent open of that same name uses the same storage
|
||||
const x = new JDb(dbFilename);
|
||||
T.assert(3 === db.selectValue('select count(*) from kvvfs'));
|
||||
x.close();
|
||||
}
|
||||
close();
|
||||
// When the final instance of a name is closed, the storage
|
||||
// disappears...
|
||||
T.mustThrowMatching(function(){
|
||||
/* Ensure that 'new-storage' was deleted when its refcount
|
||||
went to 0, because of its 'transient' flag. By default
|
||||
the objects are retained, like a filesystem would. */
|
||||
let ddb = new JDb(dbFilename);
|
||||
try{ddb.selectValue('select a from kvvfs')}
|
||||
finally{ddb.close()}
|
||||
}, /no such table: kvvfs/);
|
||||
}finally{
|
||||
if( db ) db.close();
|
||||
}
|
||||
}
|
||||
}/*transient kvvfs*/)
|
||||
.t({
|
||||
name: 'concurrent transient kvvfs',
|
||||
//predicate: ()=>false,
|
||||
test: function(sqlite3){
|
||||
const filename = 'myStorage';
|
||||
const kvvfs = sqlite3.kvvfs;
|
||||
const DB = sqlite3.oo1.DB;
|
||||
const JDb = sqlite3.oo1.JsStorageDb;
|
||||
let db;
|
||||
let duo;
|
||||
let q1, q2;
|
||||
const sqlSetup = [
|
||||
'create table kvvfs(a);',
|
||||
'insert into kvvfs(a) values(1),(2),(3)'
|
||||
];
|
||||
const sqlCount = 'select count(*) from kvvfs';
|
||||
|
||||
try {
|
||||
const exportDb = sqlite3.kvvfs.export;
|
||||
const dbFileRaw = 'file:'+filename+'?vfs=kvvfs&delete-on-close=1';
|
||||
sqlite3.kvvfs.clear(filename);
|
||||
db = new DB(dbFileRaw);
|
||||
db.exec(sqlSetup);
|
||||
T.assert(3 === db.selectValue(sqlCount));
|
||||
|
||||
duo = new JDb(filename);
|
||||
duo.exec('insert into kvvfs(a) values(4),(5),(6)');
|
||||
T.assert(6 === db.selectValue(sqlCount));
|
||||
const expOpt = {
|
||||
name: filename,
|
||||
decodePages: true
|
||||
};
|
||||
let exp = exportDb(expOpt);
|
||||
let expectRows = 6;
|
||||
debug("exported db",exp);
|
||||
db.close();
|
||||
T.assert(expectRows === duo.selectValue(sqlCount));
|
||||
duo.close();
|
||||
T.mustThrowMatching(function(){
|
||||
let ddb = new JDb(filename);
|
||||
try{ddb.selectValue('select a from kvvfs')}
|
||||
finally{ddb.close()}
|
||||
}, /.*no such table: kvvfs.*/);
|
||||
|
||||
T.assert( kvvfs.unlink(filename) )
|
||||
.assert( !kvvfs.exists(filename) );
|
||||
|
||||
const importDb = sqlite3.kvvfs.import;
|
||||
duo = new JDb(dbFileRaw);
|
||||
T.mustThrowMatching(()=>importDb(exp,true), /.*in use.*/);
|
||||
duo.close();
|
||||
importDb(exp, true);
|
||||
duo = new JDb(dbFileRaw);
|
||||
T.assert(expectRows === duo.selectValue(sqlCount));
|
||||
let newCount;
|
||||
try{
|
||||
duo.transaction(()=>{
|
||||
duo.exec("insert into kvvfs(a) values(7)");
|
||||
newCount = duo.selectValue(sqlCount);
|
||||
T.assert(false, "rolling back");
|
||||
});
|
||||
}catch(e){/*ignored*/}
|
||||
T.assert(7===newCount, "Unexpected row count before rollback")
|
||||
.assert(expectRows === duo.selectValue(sqlCount),
|
||||
"Unexpected row count after rollback");
|
||||
duo.close();
|
||||
|
||||
T.assert( kvvfs.unlink(filename) )
|
||||
.assert( !kvvfs.exists(filename) );
|
||||
|
||||
importDb(exp, true);
|
||||
db = new JDb({
|
||||
filename,
|
||||
flags: 'c'
|
||||
/* BUG: without the 'c' flag, the db works until we try to
|
||||
vacuum, at which point it fails with "read only db". */
|
||||
});
|
||||
duo = new JDb(filename);
|
||||
T.assert(expectRows === duo.selectValue(sqlCount));
|
||||
const sqlIns1 = "insert into kvvfs(a) values(?)";
|
||||
q1 = db.prepare(sqlIns1);
|
||||
q2 = duo.prepare(sqlIns1);
|
||||
if( 0 ){
|
||||
q1.bind('from q1').stepFinalize();
|
||||
++expectRows;
|
||||
T.assert(expectRows === duo.selectValue(sqlCount),
|
||||
"Unexpected record count.");
|
||||
q2.bind('from q1').stepFinalize();
|
||||
++expectRows;
|
||||
}else{
|
||||
q1.bind('from q1');
|
||||
T.assert(capi.SQLITE_DONE===capi.sqlite3_step(q1),
|
||||
"Unexpected step result");
|
||||
++expectRows;
|
||||
T.assert(expectRows === duo.selectValue(sqlCount),
|
||||
"Unexpected record count.");
|
||||
q2.bind('from q1').step();
|
||||
++expectRows;
|
||||
}
|
||||
T.assert(expectRows === db.selectValue(sqlCount),
|
||||
"Unexpected record count.");
|
||||
q1.finalize();
|
||||
q2.finalize();
|
||||
|
||||
if( 1 ){
|
||||
debug("Begin vacuum/page size test...");
|
||||
const defaultPageSize = 1024 * 8 /* build-time default */;
|
||||
const pageSize = 0
|
||||
? defaultPageSize
|
||||
: 1024 * 16 /* any valid value other than the default */;
|
||||
if( 0 ){
|
||||
debug("Export before vacuum", exportDb(expOpt));
|
||||
debug("page size before vacuum",
|
||||
db.selectArray(
|
||||
"select page_size from pragma_page_size()"
|
||||
));
|
||||
}
|
||||
//kvvfs.log.xFileControl = true;
|
||||
//kvvfs.log.xAccess = true;
|
||||
db.exec([
|
||||
"BEGIN;",
|
||||
"insert into kvvfs(a) values(randomblob(16000/*>pg size*/));",
|
||||
"COMMIT;",
|
||||
"delete from kvvfs where octet_length(a)>100;",
|
||||
"pragma page_size="+pageSize+";",
|
||||
"vacuum;",
|
||||
"select 1;"
|
||||
]);
|
||||
const expectPageSize = kvvfs.internal.disablePageSizeChange
|
||||
? defaultPageSize
|
||||
: pageSize;
|
||||
const gotPageSize = db.selectValue(
|
||||
"select page_size from pragma_page_size()"
|
||||
);
|
||||
T.assert(+gotPageSize === expectPageSize,
|
||||
"Expecting page size",expectPageSize,
|
||||
"got",gotPageSize);
|
||||
T.assert(expectRows === duo.selectValue(sqlCount),
|
||||
"Unexpected record count.");
|
||||
kvvfs.log.xAccess = kvvfs.log.xFileControl = false;
|
||||
T.assert(expectRows === duo.selectValue(sqlCount),
|
||||
"Unexpected record count.");
|
||||
exp = exportDb(expOpt);
|
||||
debug("Exported page-expanded db",exp);
|
||||
if( 0 ){
|
||||
debug("vacuumed export",exp);
|
||||
}
|
||||
debug("End vacuum/page size test.");
|
||||
}else{
|
||||
expectRows = 6;
|
||||
}
|
||||
|
||||
db.close();
|
||||
duo.close();
|
||||
T.assert( kvvfs.unlink(exp.name) )
|
||||
.assert( !kvvfs.exists(exp.name) );
|
||||
importDb(exp);
|
||||
T.assert( kvvfs.exists(exp.name) );
|
||||
db = new JDb(exp.name);
|
||||
//debug("column count after export",db.selectValue(sqlCount));
|
||||
T.assert(expectRows === db.selectValue(sqlCount),
|
||||
"Unexpected record count.");
|
||||
|
||||
/*
|
||||
TODO: more advanced concurrent use tests, e.g. looping
|
||||
over a query in one connection while writing from
|
||||
another. Currently that will probably corrupt the db, and
|
||||
kvvfs's journaling does not support multiple journals per
|
||||
storage unit. We need to test the locking and fix it as
|
||||
appropriate.
|
||||
*/
|
||||
}finally{
|
||||
q1?.finalize?.();
|
||||
q2?.finalize?.();
|
||||
db?.close?.();
|
||||
duo?.close?.();
|
||||
}
|
||||
}
|
||||
}/*concurrent transient kvvfs*/)
|
||||
|
||||
.t({
|
||||
name: 'kvvfs listeners (experiment)',
|
||||
test: function(sqlite3){
|
||||
const kvvfs = sqlite3.kvvfs;
|
||||
const filename = 'listen';
|
||||
let db;
|
||||
try {
|
||||
const DB = sqlite3.oo1.DB;
|
||||
const sqlSetup = [
|
||||
'create table kvvfs(a);',
|
||||
'insert into kvvfs(a) values(1),(2),(3)'
|
||||
];
|
||||
const sqlCount = "select count(*) from kvvfs";
|
||||
const sqlSelectSchema = "select * from sqlite_schema";
|
||||
const counts = Object.create(null);
|
||||
const incr = (key)=>counts[key] = 1 + (counts[key] ?? 0);
|
||||
const pglog = Object.assign(Object.create(null),{
|
||||
pages: [],
|
||||
jrnl: undefined,
|
||||
size: undefined,
|
||||
includeJournal: false,
|
||||
decodePages: true,
|
||||
exception: new Error("Testing that exceptions from listeners do not interfere")
|
||||
});
|
||||
const toss = ()=>{
|
||||
if( pglog.exception ){
|
||||
const e = pglog.exception;
|
||||
delete pglog.exception;
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
const listener = {
|
||||
storage: filename,
|
||||
reserve: true,
|
||||
includeJournal: pglog.includeJournal,
|
||||
decodePages: pglog.decodePages,
|
||||
events: {
|
||||
/**
|
||||
These may be async but must not be in this case
|
||||
because we can't test their result without a lot of
|
||||
hoop-jumping if they are. Kvvfs calls these
|
||||
asynchronously, though.
|
||||
*/
|
||||
'open': (ev)=>{
|
||||
//console.warn('open',ev);
|
||||
incr(ev.type);
|
||||
T.assert(filename===ev.storageName)
|
||||
.assert('number'===typeof ev.data);
|
||||
},
|
||||
'close': (ev)=>{
|
||||
//console.warn('close',ev);
|
||||
incr(ev.type);
|
||||
T.assert('number'===typeof ev.data);
|
||||
toss();
|
||||
},
|
||||
'delete': (ev)=>{
|
||||
//console.warn('delete',ev);
|
||||
incr(ev.type);
|
||||
T.assert('string'===typeof ev.data);
|
||||
switch(ev.data){
|
||||
case 'jrnl':
|
||||
T.assert(pglog.includeJournal);
|
||||
pglog.jrnl = null;
|
||||
break;
|
||||
default:{
|
||||
const n = +ev.data;
|
||||
T.assert( n>0, "Expecting positive db page number" );
|
||||
if( n < pglog.pages.length ){
|
||||
pglog.size = undefined;
|
||||
}
|
||||
pglog.pages[n] = undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
'sync': (ev)=>{
|
||||
incr(ev.data ? 'xSync' : 'xFileControlSync');
|
||||
},
|
||||
'write': (ev)=>{
|
||||
//console.warn('write',ev);
|
||||
incr(ev.type);
|
||||
T.assert(Array.isArray(ev.data));
|
||||
const key = ev.data[0], val = ev.data[1];
|
||||
T.assert('string'===typeof key);
|
||||
switch( key ){
|
||||
case 'jrnl':
|
||||
T.assert(pglog.includeJournal);
|
||||
pglog.jrnl = val;
|
||||
break;
|
||||
case 'sz':{
|
||||
const sz = +val;
|
||||
T.assert( sz>0, "Expecting a db page number" );
|
||||
if( sz < pglog.sz ){
|
||||
pglog.pages.length = sz / pglog.pages.length;
|
||||
}
|
||||
pglog.size = sz;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
T.assert( +key>0, "Expecting a positive db page number" );
|
||||
pglog.pages[+key] = val;
|
||||
if( pglog.decodePages ){
|
||||
T.assert( val instanceof Uint8Array );
|
||||
}else{
|
||||
T.assert( 'string'===typeof val );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
kvvfs.listen(listener);
|
||||
const dbFileRaw = 'file:'+filename+'?vfs=kvvfs&delete-on-close=1';
|
||||
const expOpt = {
|
||||
name: filename,
|
||||
//decodePages: true
|
||||
};
|
||||
db = new DB(dbFileRaw);
|
||||
db.exec(sqlSetup);
|
||||
T.assert(db.selectObjects(sqlSelectSchema)?.length>0,
|
||||
"Unexpected empty schema");
|
||||
db.close();
|
||||
debug("kvvfs listener counts:",counts);
|
||||
T.assert( counts.open );
|
||||
T.assert( counts.close );
|
||||
T.assert( listener.includeJournal ? counts.delete : !counts.delete );
|
||||
T.assert( counts.write );
|
||||
T.assert( counts.xSync );
|
||||
T.assert( counts.xFileControlSync>=counts.xSync );
|
||||
T.assert( counts.open===counts.close );
|
||||
T.assert( pglog.includeJournal
|
||||
? (null===pglog.jrnl)
|
||||
: (undefined===pglog.jrnl),
|
||||
"Unexpected pglog.jrnl value: "+pglog.jrnl );
|
||||
if( 1 ){
|
||||
T.assert(undefined===pglog.pages[0], "Expecting empty slot 0");
|
||||
pglog.pages.shift();
|
||||
//debug("kvvfs listener pageLog", pglog);
|
||||
}
|
||||
const before = JSON.stringify(counts);
|
||||
T.assert( kvvfs.unlisten(listener) );
|
||||
T.assert( !kvvfs.unlisten(listener) );
|
||||
db = new DB(dbFileRaw);
|
||||
T.assert( db.selectObjects(sqlSelectSchema)?.length>0 );
|
||||
const exp = kvvfs.export(expOpt);
|
||||
const expectRows = db.selectValue(sqlCount);
|
||||
db.exec("delete from kvvfs");
|
||||
db.close();
|
||||
const after = JSON.stringify(counts);
|
||||
T.assert( before===after, "Expecting no events after unlistening." );
|
||||
if( 0 ){
|
||||
exp = kvvfs.export(expOpt);
|
||||
debug("Post-delete export:",exp);
|
||||
}
|
||||
if( 1 ){
|
||||
// Replace the storage with the pglog state...
|
||||
const bogoExp = {
|
||||
name: filename,
|
||||
size: pglog.size,
|
||||
timestamp: Date.now(),
|
||||
pages: pglog.pages
|
||||
};
|
||||
//debug("exp",exp);
|
||||
//debug("bogoExp",bogoExp);
|
||||
kvvfs.import(bogoExp, true);
|
||||
//debug("Re-exported", kvvfs.export(expOpt));
|
||||
db = new DB(dbFileRaw);
|
||||
// Failing on the next line despite exports looking good
|
||||
T.assert(db.selectObjects(sqlSelectSchema)?.length>0,
|
||||
"Empty schema on imported db");
|
||||
T.assert(expectRows===db.selectValue(sqlCount));
|
||||
db.close();
|
||||
}
|
||||
}finally{
|
||||
db?.close?.();
|
||||
kvvfs.unlink(filename);
|
||||
}
|
||||
}
|
||||
})/*kvvfs listeners */
|
||||
|
||||
.t({
|
||||
name: 'kvvfs vtab',
|
||||
predicate: (sqlite3)=>!!sqlite3.kvvfs.create_module,
|
||||
test: function(sqlite3){
|
||||
const kvvfs = sqlite3.kvvfs;
|
||||
const db = new sqlite3.oo1.DB();
|
||||
const db2 = new sqlite3.oo1.DB('file:foo?vfs=kvvfs&delete-on-close=1');
|
||||
try{
|
||||
kvvfs.create_module(db);
|
||||
let rc = db.selectObjects("select * from sqlite_kvvfs order by name");
|
||||
debug("sqlite_kvvfs vtab:", rc);
|
||||
const nDb = rc.length;
|
||||
rc = db.selectObject("select * from sqlite_kvvfs where name='foo'");
|
||||
T.assert(rc, "Expecting foo storage record")
|
||||
.assert('foo'===rc.name, "Unexpected name")
|
||||
.assert(1===rc.nRef, "Unexpected refcount");
|
||||
db2.close();
|
||||
rc = db.selectObjects("select * from sqlite_kvvfs");
|
||||
T.assert( !rc.filter((o)=>o.name==='foo').length,
|
||||
"Expecting foo storage to be gone");
|
||||
debug("sqlite_kvvfs vtab:", rc);
|
||||
T.assert( rc.length+1 === nDb,
|
||||
"Unexpected storage count: got",rc.length,"expected",nDb);
|
||||
}finally{
|
||||
db.close();
|
||||
db2.close();
|
||||
}
|
||||
}
|
||||
})/* kvvfs vtab */
|
||||
|
||||
//#if enable-see
|
||||
.t({
|
||||
name: 'kvvfs SEE encryption in sessionStorage',
|
||||
predicate: ()=>(!!globalThis.sessionStorage
|
||||
|| "sessionStorage is not available"),
|
||||
name: 'kvvfs with SEE encryption',
|
||||
predicate: ()=>(isUIThread()
|
||||
|| "Only available in main thread."),
|
||||
test: function(sqlite3){
|
||||
const JDb = sqlite3.oo1.JsStorageDb;
|
||||
T.seeBaseCheck(JDb,
|
||||
(isInit)=>return {filename: "session"},
|
||||
()=>JDb.clearStorage('session'));
|
||||
T.seeBaseCheck(sqlite3.oo1.JsStorageDb, (isInit)=>{
|
||||
return {filename: "session"};
|
||||
}, ()=>this.kvvfsUnlink());
|
||||
}
|
||||
})/*kvvfs with SEE*/
|
||||
//#endif enable-see
|
||||
@@ -3497,7 +2939,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
let countCommit = 0, countRollback = 0;;
|
||||
const db = new sqlite3.oo1.DB(':memory:',1 ? 'c' : 'ct');
|
||||
let rc = capi.sqlite3_commit_hook(db, (p)=>{
|
||||
//debug("commit hook",arguments);
|
||||
//console.debug("commit hook",arguments);
|
||||
++countCommit;
|
||||
return (17 == p) ? 0 : capi.SQLITE_ERROR;
|
||||
}, 17);
|
||||
|
||||
@@ -1796,7 +1796,7 @@ TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
|
||||
testfixture$(T.exe): $(T.tcl.env.sh) has_tclsh85 $(TESTFIXTURE_SRC)
|
||||
$(T.link.tcl) -DSQLITE_NO_SYNC=1 $(TESTFIXTURE_FLAGS) \
|
||||
-o $@ $(TESTFIXTURE_SRC) \
|
||||
$$TCL_LIB_SPEC $$TCL_INCLUDE_SPEC $$TCL_LIBS \
|
||||
$$TCL_LIB_SPEC $$TCL_INCLUDE_SPEC \
|
||||
$(LDFLAGS.libsqlite3)
|
||||
|
||||
coretestprogs: testfixture$(B.exe) sqlite3$(B.exe)
|
||||
@@ -1863,15 +1863,6 @@ mdevtest: srctree-check has_tclsh85
|
||||
sdevtest: has_tclsh85
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl sdevtest $(TSTRNNR_OPTS)
|
||||
|
||||
retest: has_tclsh85
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl retest
|
||||
|
||||
errors:
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl errors
|
||||
|
||||
status:
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl status -d 2
|
||||
|
||||
# Like releasetest, except it omits srctree-check and verify-source so
|
||||
# that it can be used on a modified source tree.
|
||||
#
|
||||
@@ -2018,10 +2009,6 @@ showshm$(T.exe): $(TOP)/tool/showshm.c
|
||||
$(T.link) -o $@ $(TOP)/tool/showshm.c $(LDFLAGS.configure)
|
||||
xbin: showshm$(T.exe)
|
||||
|
||||
showtmlog$(T.exe): $(TOP)/tool/showtmlog.c
|
||||
$(T.link) -o $@ $(TOP)/tool/showtmlog.c $(LDFLAGS.configure)
|
||||
xbin: showshm$(T.exe)
|
||||
|
||||
index_usage$(T.exe): $(TOP)/tool/index_usage.c sqlite3.o
|
||||
$(T.link) $(SHELL_OPT) -o $@ $(TOP)/tool/index_usage.c sqlite3.o \
|
||||
$(LDFLAGS.libsqlite3)
|
||||
@@ -2120,19 +2107,16 @@ src-archives: sqlite-amalgamation.zip amalgamation-tarball sqlite-src.zip
|
||||
|
||||
# Build a ZIP archive containing various command-line tools.
|
||||
#
|
||||
tool-zip: sqlite3$(T.exe) sqldiff$(T.exe) \
|
||||
tool-zip: testfixture$(T.exe) sqlite3$(T.exe) sqldiff$(T.exe) \
|
||||
sqlite3_analyzer$(T.exe) sqlite3_rsync$(T.exe) $(TOP)/tool/mktoolzip.tcl
|
||||
strip sqlite3$(T.exe) sqldiff$(T.exe) sqlite3_analyzer$(T.exe) sqlite3_rsync$(T.exe)
|
||||
$(TCLSH_CMD) $(TOP)/tool/mktoolzip.tcl
|
||||
|
||||
./testfixture$(T.exe) $(TOP)/tool/mktoolzip.tcl
|
||||
snapshot-zip: testfixture$(T.exe) sqlite3$(T.exe) sqldiff$(T.exe) \
|
||||
sqlite3_analyzer$(T.exe) sqlite3_rsync$(T.exe) $(TOP)/tool/mktoolzip.tcl
|
||||
strip sqlite3$(T.exe) sqldiff$(T.exe) sqlite3_analyzer$(T.exe) sqlite3_rsync$(T.exe)
|
||||
$(TCLSH_CMD) $(TOP)/tool/mktoolzip.tcl --snapshot
|
||||
|
||||
./testfixture$(T.exe) $(TOP)/tool/mktoolzip.tcl --snapshot
|
||||
clean-tool-zip:
|
||||
rm -f sqlite-tools-*.zip
|
||||
|
||||
clean: clean-tool-zip
|
||||
|
||||
#
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
branch numeric-conversion-perf
|
||||
tag numeric-conversion-perf
|
||||
branch remove-sync-dataonly
|
||||
tag remove-sync-dataonly
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
a4540582b5b704af13b570b3dc609dbacada719302372a038cf74eee3688d5e7
|
||||
caefe4c746599b22aec446f3aeb296e53edaf8c54f8ae803381e8c21d5e29ab4
|
||||
|
||||
+74
-85
@@ -1368,8 +1368,8 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
sqlite3SelectPrep(pParse, pStep->pSelect, &sNC);
|
||||
if( pParse->nErr ) rc = pParse->rc;
|
||||
}
|
||||
if( rc==SQLITE_OK && pStep->pSrc ){
|
||||
SrcList *pSrc = sqlite3SrcListDup(db, pStep->pSrc, 0);
|
||||
if( rc==SQLITE_OK && pStep->zTarget ){
|
||||
SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
|
||||
if( pSrc ){
|
||||
Select *pSel = sqlite3SelectNew(
|
||||
pParse, pStep->pExprList, pSrc, 0, 0, 0, 0, 0, 0
|
||||
@@ -1397,10 +1397,10 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
pSel->pSrc = 0;
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
}
|
||||
if( ALWAYS(pStep->pSrc) ){
|
||||
if( pStep->pFrom ){
|
||||
int i;
|
||||
for(i=0; i<pStep->pSrc->nSrc && rc==SQLITE_OK; i++){
|
||||
SrcItem *p = &pStep->pSrc->a[i];
|
||||
for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
|
||||
SrcItem *p = &pStep->pFrom->a[i];
|
||||
if( p->fg.isSubquery ){
|
||||
assert( p->u4.pSubq!=0 );
|
||||
sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0);
|
||||
@@ -1469,13 +1469,13 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
|
||||
sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
|
||||
sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
|
||||
}
|
||||
if( pStep->pSrc ){
|
||||
if( pStep->pFrom ){
|
||||
int i;
|
||||
SrcList *pSrc = pStep->pSrc;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
if( pSrc->a[i].fg.isSubquery ){
|
||||
assert( pSrc->a[i].u4.pSubq!=0 );
|
||||
sqlite3WalkSelect(pWalker, pSrc->a[i].u4.pSubq->pSelect);
|
||||
SrcList *pFrom = pStep->pFrom;
|
||||
for(i=0; i<pFrom->nSrc; i++){
|
||||
if( pFrom->a[i].fg.isSubquery ){
|
||||
assert( pFrom->a[i].u4.pSubq!=0 );
|
||||
sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1646,8 +1646,8 @@ static void renameColumnFunc(
|
||||
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
||||
|
||||
for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->pSrc ){
|
||||
Table *pTarget = sqlite3LocateTableItem(&sParse, 0, &pStep->pSrc->a[0]);
|
||||
if( pStep->zTarget ){
|
||||
Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb);
|
||||
if( pTarget==pTab ){
|
||||
if( pStep->pUpsert ){
|
||||
ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet;
|
||||
@@ -1659,6 +1659,7 @@ static void renameColumnFunc(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Find tokens to edit in UPDATE OF clause */
|
||||
if( sParse.pTriggerTab==pTab ){
|
||||
renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld);
|
||||
@@ -1860,10 +1861,13 @@ static void renameTableFunc(
|
||||
if( rc==SQLITE_OK ){
|
||||
renameWalkTrigger(&sWalker, pTrigger);
|
||||
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->pSrc ){
|
||||
if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
|
||||
renameTokenFind(&sParse, &sCtx, pStep->zTarget);
|
||||
}
|
||||
if( pStep->pFrom ){
|
||||
int i;
|
||||
for(i=0; i<pStep->pSrc->nSrc; i++){
|
||||
SrcItem *pItem = &pStep->pSrc->a[i];
|
||||
for(i=0; i<pStep->pFrom->nSrc; i++){
|
||||
SrcItem *pItem = &pStep->pFrom->a[i];
|
||||
if( 0==sqlite3_stricmp(pItem->zName, zOld) ){
|
||||
renameTokenFind(&sParse, &sCtx, pItem->zName);
|
||||
}
|
||||
@@ -2110,57 +2114,6 @@ static void renameTableTest(
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return the number of bytes until the end of the next non-whitespace and
|
||||
** non-comment token. For the purpose of this function, a "(" token includes
|
||||
** all of the bytes through and including the matching ")", or until the
|
||||
** first illegal token, whichever comes first.
|
||||
**
|
||||
** Write the token type into *piToken.
|
||||
**
|
||||
** The value returned is the number of bytes in the token itself plus
|
||||
** the number of bytes of leading whitespace and comments skipped plus
|
||||
** all bytes through the next matching ")" if the token is TK_LP.
|
||||
**
|
||||
** Example: (Note: '.' used in place of '*' in the example z[] text)
|
||||
**
|
||||
** ,--------- *piToken := TK_RP
|
||||
** v
|
||||
** z[] = " /.comment./ --comment\n (two three four) five"
|
||||
** | |
|
||||
** |<-------------------------------------->|
|
||||
** |
|
||||
** `--- return value
|
||||
*/
|
||||
static int getConstraintToken(const u8 *z, int *piToken){
|
||||
int iOff = 0;
|
||||
int t = 0;
|
||||
do {
|
||||
iOff += sqlite3GetToken(&z[iOff], &t);
|
||||
}while( t==TK_SPACE || t==TK_COMMENT );
|
||||
|
||||
*piToken = t;
|
||||
|
||||
if( t==TK_LP ){
|
||||
int nNest = 1;
|
||||
while( nNest>0 ){
|
||||
iOff += sqlite3GetToken(&z[iOff], &t);
|
||||
if( t==TK_LP ){
|
||||
nNest++;
|
||||
}else if( t==TK_RP ){
|
||||
t = TK_LP;
|
||||
nNest--;
|
||||
}else if( t==TK_ILLEGAL ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*piToken = t;
|
||||
return iOff;
|
||||
}
|
||||
|
||||
/*
|
||||
** The implementation of internal UDF sqlite_drop_column().
|
||||
**
|
||||
@@ -2205,24 +2158,15 @@ static void dropColumnFunc(
|
||||
goto drop_column_done;
|
||||
}
|
||||
|
||||
pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName);
|
||||
if( iCol<pTab->nCol-1 ){
|
||||
RenameToken *pEnd;
|
||||
pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName);
|
||||
pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName);
|
||||
zEnd = (const char*)pEnd->t.z;
|
||||
}else{
|
||||
int eTok;
|
||||
assert( IsOrdinaryTable(pTab) );
|
||||
assert( iCol!=0 );
|
||||
/* Point pCol->t.z at the "," immediately preceding the definition of
|
||||
** the column being dropped. To do this, start at the name of the
|
||||
** previous column, and tokenize until the next ",". */
|
||||
pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol-1].zCnName);
|
||||
do {
|
||||
pCol->t.z += getConstraintToken((const u8*)pCol->t.z, &eTok);
|
||||
}while( eTok!=TK_COMMA );
|
||||
pCol->t.z--;
|
||||
zEnd = (const char*)&zSql[pTab->u.tab.addColOffset];
|
||||
while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--;
|
||||
}
|
||||
|
||||
zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd);
|
||||
@@ -2406,6 +2350,56 @@ static int getWhitespace(const u8 *z){
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return the number of bytes until the end of the next non-whitespace and
|
||||
** non-comment token. For the purpose of this function, a "(" token includes
|
||||
** all of the bytes through and including the matching ")", or until the
|
||||
** first illegal token, whichever comes first.
|
||||
**
|
||||
** Write the token type into *piToken.
|
||||
**
|
||||
** The value returned is the number of bytes in the token itself plus
|
||||
** the number of bytes of leading whitespace and comments skipped plus
|
||||
** all bytes through the next matching ")" if the token is TK_LP.
|
||||
**
|
||||
** Example: (Note: '.' used in place of '*' in the example z[] text)
|
||||
**
|
||||
** ,--------- *piToken := TK_RP
|
||||
** v
|
||||
** z[] = " /.comment./ --comment\n (two three four) five"
|
||||
** | |
|
||||
** |<-------------------------------------->|
|
||||
** |
|
||||
** `--- return value
|
||||
*/
|
||||
static int getConstraintToken(const u8 *z, int *piToken){
|
||||
int iOff = 0;
|
||||
int t = 0;
|
||||
do {
|
||||
iOff += sqlite3GetToken(&z[iOff], &t);
|
||||
}while( t==TK_SPACE || t==TK_COMMENT );
|
||||
|
||||
*piToken = t;
|
||||
|
||||
if( t==TK_LP ){
|
||||
int nNest = 1;
|
||||
while( nNest>0 ){
|
||||
iOff += sqlite3GetToken(&z[iOff], &t);
|
||||
if( t==TK_LP ){
|
||||
nNest++;
|
||||
}else if( t==TK_RP ){
|
||||
t = TK_LP;
|
||||
nNest--;
|
||||
}else if( t==TK_ILLEGAL ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*piToken = t;
|
||||
return iOff;
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument z points into the body of a constraint - specifically the
|
||||
** second token of the constraint definition. For a named constraint,
|
||||
@@ -2455,7 +2449,6 @@ static int getConstraint(const u8 *z){
|
||||
*/
|
||||
static int quotedCompare(
|
||||
sqlite3_context *ctx, /* Function context on which to report errors */
|
||||
int t, /* Token type */
|
||||
const u8 *zQuote, /* Possibly quoted text. Not zero-terminated. */
|
||||
int nQuote, /* Length of zQuote in bytes */
|
||||
const u8 *zCmp, /* Zero-terminated, unquoted name to compare against */
|
||||
@@ -2463,10 +2456,6 @@ static int quotedCompare(
|
||||
){
|
||||
char *zCopy = 0; /* De-quoted, zero-terminated copy of zQuote[] */
|
||||
|
||||
if( t==TK_ILLEGAL ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
zCopy = sqlite3MallocZero(nQuote+1);
|
||||
if( zCopy==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
@@ -2565,7 +2554,7 @@ static void dropConstraintFunc(
|
||||
** the constraint being dropped. */
|
||||
nTok = getConstraintToken(&zSql[iOff], &t);
|
||||
if( zCons ){
|
||||
if( quotedCompare(ctx, t, &zSql[iOff], nTok, zCons, &cmp) ) return;
|
||||
if( quotedCompare(ctx, &zSql[iOff], nTok, zCons, &cmp) ) return;
|
||||
}
|
||||
iOff += nTok;
|
||||
|
||||
@@ -2959,7 +2948,7 @@ static void findConstraintFunc(
|
||||
int cmp = 0;
|
||||
iOff += getWhitespace(&zSql[iOff]);
|
||||
nTok = getConstraintToken(&zSql[iOff], &t);
|
||||
if( quotedCompare(ctx, t, &zSql[iOff], nTok, zCons, &cmp) ) return;
|
||||
if( quotedCompare(ctx, &zSql[iOff], nTok, zCons, &cmp) ) return;
|
||||
if( cmp==0 ){
|
||||
sqlite3_result_int(ctx, 1);
|
||||
return;
|
||||
|
||||
+1
-1
@@ -596,7 +596,7 @@ int sqlite3FixTriggerStep(
|
||||
if( sqlite3WalkSelect(&pFix->w, pStep->pSelect)
|
||||
|| sqlite3WalkExpr(&pFix->w, pStep->pWhere)
|
||||
|| sqlite3WalkExprList(&pFix->w, pStep->pExprList)
|
||||
|| sqlite3FixSrcList(pFix, pStep->pSrc)
|
||||
|| sqlite3FixSrcList(pFix, pStep->pFrom)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ int sqlite3_set_authorizer(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->xAuth = (sqlite3_xauth)xAuth;
|
||||
db->pAuthArg = pArg;
|
||||
sqlite3ExpirePreparedStatements(db, 1);
|
||||
if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+2
-2
@@ -5144,7 +5144,7 @@ static int accessPayload(
|
||||
|
||||
getCellInfo(pCur);
|
||||
aPayload = pCur->info.pPayload;
|
||||
assert( (u64)offset+(u64)amt <= (u64)pCur->info.nPayload );
|
||||
assert( offset+amt <= pCur->info.nPayload );
|
||||
|
||||
assert( aPayload > pPage->aData );
|
||||
if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
|
||||
@@ -5701,7 +5701,7 @@ int sqlite3BtreeIsEmpty(BtCursor *pCur, int *pRes){
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
if( NEVER(pCur->eState==CURSOR_VALID) ){
|
||||
if( pCur->eState==CURSOR_VALID ){
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+6
-8
@@ -2059,8 +2059,8 @@ void sqlite3ChangeCookie(Parse *pParse, int iDb){
|
||||
** The estimate is conservative. It might be larger that what is
|
||||
** really needed.
|
||||
*/
|
||||
static i64 identLength(const char *z){
|
||||
i64 n;
|
||||
static int identLength(const char *z){
|
||||
int n;
|
||||
for(n=0; *z; n++, z++){
|
||||
if( *z=='"' ){ n++; }
|
||||
}
|
||||
@@ -2570,14 +2570,13 @@ void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){
|
||||
** restored to its original value prior to this routine returning.
|
||||
*/
|
||||
int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
|
||||
const char *zTail; /* Pointer to the last "_" in zName */
|
||||
char *zTail; /* Pointer to the last "_" in zName */
|
||||
Table *pTab; /* Table that zName is a shadow of */
|
||||
char *zCopy;
|
||||
zTail = strrchr(zName, '_');
|
||||
if( zTail==0 ) return 0;
|
||||
zCopy = sqlite3DbStrNDup(db, zName, (int)(zTail-zName));
|
||||
pTab = zCopy ? sqlite3FindTable(db, zCopy, 0) : 0;
|
||||
sqlite3DbFree(db, zCopy);
|
||||
*zTail = 0;
|
||||
pTab = sqlite3FindTable(db, zName, 0);
|
||||
*zTail = '_';
|
||||
if( pTab==0 ) return 0;
|
||||
if( !IsVirtual(pTab) ) return 0;
|
||||
return sqlite3IsShadowTableOf(db, pTab, zName);
|
||||
@@ -4621,7 +4620,6 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_INDEX;
|
||||
|
||||
+4
-35
@@ -79,7 +79,6 @@ struct carray_bind {
|
||||
int nData; /* Number of elements */
|
||||
int mFlags; /* Control flags */
|
||||
void (*xDel)(void*); /* Destructor for aData */
|
||||
void *pDel; /* Alternative argument to xDel() */
|
||||
};
|
||||
|
||||
|
||||
@@ -412,7 +411,7 @@ static sqlite3_module carrayModule = {
|
||||
static void carrayBindDel(void *pPtr){
|
||||
carray_bind *p = (carray_bind*)pPtr;
|
||||
if( p->xDel!=SQLITE_STATIC ){
|
||||
p->xDel(p->pDel);
|
||||
p->xDel(p->aData);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
}
|
||||
@@ -420,26 +419,14 @@ static void carrayBindDel(void *pPtr){
|
||||
/*
|
||||
** Invoke this interface in order to bind to the single-argument
|
||||
** version of CARRAY().
|
||||
**
|
||||
** pStmt The prepared statement to which to bind
|
||||
** idx The index of the parameter of pStmt to which to bind
|
||||
** aData The data to be bound
|
||||
** nData The number of elements in aData
|
||||
** mFlags One of SQLITE_CARRAY_xxxx indicating datatype of aData
|
||||
** xDestroy Destructor for pDestroy or aData if pDestroy==NULL.
|
||||
** pDestroy Invoke xDestroy on this pointer if not NULL
|
||||
**
|
||||
** The destructor is called pDestroy if pDestroy!=NULL, or against
|
||||
** aData if pDestroy==NULL.
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind_v2(
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt,
|
||||
int idx,
|
||||
void *aData,
|
||||
int nData,
|
||||
int mFlags,
|
||||
void (*xDestroy)(void*),
|
||||
void *pDestroy
|
||||
void (*xDestroy)(void*)
|
||||
){
|
||||
carray_bind *pNew = 0;
|
||||
int i;
|
||||
@@ -516,38 +503,20 @@ SQLITE_API int sqlite3_carray_bind_v2(
|
||||
memcpy(pNew->aData, aData, sz);
|
||||
}
|
||||
pNew->xDel = sqlite3_free;
|
||||
pNew->pDel = pNew->aData;
|
||||
}else{
|
||||
pNew->aData = aData;
|
||||
pNew->xDel = xDestroy;
|
||||
pNew->pDel = pDestroy;
|
||||
}
|
||||
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
|
||||
|
||||
carray_bind_error:
|
||||
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
|
||||
xDestroy(pDestroy);
|
||||
xDestroy(aData);
|
||||
}
|
||||
sqlite3_free(pNew);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this interface in order to bind to the single-argument
|
||||
** version of CARRAY(). Same as sqlite3_carray_bind_v2() with the
|
||||
** pDestroy parameter set to NULL.
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt,
|
||||
int idx,
|
||||
void *aData,
|
||||
int nData,
|
||||
int mFlags,
|
||||
void (*xDestroy)(void*)
|
||||
){
|
||||
return sqlite3_carray_bind_v2(pStmt,idx,aData,nData,mFlags,xDestroy,aData);
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this routine to register the carray() function.
|
||||
*/
|
||||
|
||||
+4
-10
@@ -429,7 +429,7 @@ static int parseDateOrTime(
|
||||
return 0;
|
||||
}else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){
|
||||
return setDateTimeToCurrent(context, p);
|
||||
}else if( sqlite3AtoF(zDate, &r)>0 ){
|
||||
}else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){
|
||||
setRawDateNumber(p, r);
|
||||
return 0;
|
||||
}else if( (sqlite3StrICmp(zDate,"subsec")==0
|
||||
@@ -875,7 +875,7 @@ static int parseModifier(
|
||||
** date is already on the appropriate weekday, this is a no-op.
|
||||
*/
|
||||
if( sqlite3_strnicmp(z, "weekday ", 8)==0
|
||||
&& sqlite3AtoF(&z[8], &r)>0
|
||||
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
|
||||
&& r>=0.0 && r<7.0 && (n=(int)r)==r ){
|
||||
sqlite3_int64 Z;
|
||||
computeYMD_HMS(p);
|
||||
@@ -946,11 +946,9 @@ static int parseModifier(
|
||||
case '8':
|
||||
case '9': {
|
||||
double rRounder;
|
||||
int i, rx;
|
||||
int i;
|
||||
int Y,M,D,h,m,x;
|
||||
const char *z2 = z;
|
||||
char *zCopy;
|
||||
sqlite3 *db = sqlite3_context_db_handle(pCtx);
|
||||
char z0 = z[0];
|
||||
for(n=1; z[n]; n++){
|
||||
if( z[n]==':' ) break;
|
||||
@@ -960,11 +958,7 @@ static int parseModifier(
|
||||
if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break;
|
||||
}
|
||||
}
|
||||
zCopy = sqlite3DbStrNDup(db, z, n);
|
||||
if( zCopy==0 ) break;
|
||||
rx = sqlite3AtoF(zCopy, &r)<=0;
|
||||
sqlite3DbFree(db, zCopy);
|
||||
if( rx ){
|
||||
if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){
|
||||
assert( rc==1 );
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-1
@@ -86,7 +86,7 @@ static int vtabIsReadOnly(Parse *pParse, Table *pTab){
|
||||
** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS
|
||||
** virtual tables if PRAGMA trusted_schema=ON.
|
||||
*/
|
||||
if( (pParse->pToplevel!=0 || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL))
|
||||
if( pParse->pToplevel!=0
|
||||
&& pTab->u.vtab.p->eVtabRisk >
|
||||
((pParse->db->flags & SQLITE_TrustedSchema)!=0)
|
||||
){
|
||||
@@ -924,6 +924,7 @@ void sqlite3GenerateRowIndexDelete(
|
||||
&iPartIdxLabel, pPrior, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
||||
sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
|
||||
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
||||
pPrior = pIdx;
|
||||
}
|
||||
|
||||
+38
-72
@@ -935,22 +935,34 @@ Expr *sqlite3ExprAlloc(
|
||||
int dequote /* True to dequote */
|
||||
){
|
||||
Expr *pNew;
|
||||
int nExtra = pToken ? pToken->n+1 : 0;
|
||||
int nExtra = 0;
|
||||
int iValue = 0;
|
||||
|
||||
assert( db!=0 );
|
||||
if( pToken ){
|
||||
if( op!=TK_INTEGER || pToken->z==0
|
||||
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
|
||||
nExtra = pToken->n+1; /* tag-20240227-a */
|
||||
assert( iValue>=0 );
|
||||
}
|
||||
}
|
||||
pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra);
|
||||
if( pNew ){
|
||||
memset(pNew, 0, sizeof(Expr));
|
||||
pNew->op = (u8)op;
|
||||
pNew->iAgg = -1;
|
||||
if( nExtra ){
|
||||
assert( pToken!=0 );
|
||||
pNew->u.zToken = (char*)&pNew[1];
|
||||
assert( pToken->z!=0 || pToken->n==0 );
|
||||
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
|
||||
pNew->u.zToken[pToken->n] = 0;
|
||||
if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
|
||||
sqlite3DequoteExpr(pNew);
|
||||
if( pToken ){
|
||||
if( nExtra==0 ){
|
||||
pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse);
|
||||
pNew->u.iValue = iValue;
|
||||
}else{
|
||||
pNew->u.zToken = (char*)&pNew[1];
|
||||
assert( pToken->z!=0 || pToken->n==0 );
|
||||
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
|
||||
pNew->u.zToken[pToken->n] = 0;
|
||||
if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
|
||||
sqlite3DequoteExpr(pNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if SQLITE_MAX_EXPR_DEPTH>0
|
||||
@@ -975,24 +987,6 @@ Expr *sqlite3Expr(
|
||||
return sqlite3ExprAlloc(db, op, &x, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate an expression for a 32-bit signed integer literal.
|
||||
*/
|
||||
Expr *sqlite3ExprInt32(sqlite3 *db, int iVal){
|
||||
Expr *pNew = sqlite3DbMallocRawNN(db, sizeof(Expr));
|
||||
if( pNew ){
|
||||
memset(pNew, 0, sizeof(Expr));
|
||||
pNew->op = TK_INTEGER;
|
||||
pNew->iAgg = -1;
|
||||
pNew->flags = EP_IntValue|EP_Leaf|(iVal?EP_IsTrue:EP_IsFalse);
|
||||
pNew->u.iValue = iVal;
|
||||
#if SQLITE_MAX_EXPR_DEPTH>0
|
||||
pNew->nHeight = 1;
|
||||
#endif
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attach subtrees pLeft and pRight to the Expr node pRoot.
|
||||
**
|
||||
@@ -1155,7 +1149,7 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
|
||||
){
|
||||
sqlite3ExprDeferredDelete(pParse, pLeft);
|
||||
sqlite3ExprDeferredDelete(pParse, pRight);
|
||||
return sqlite3ExprInt32(db, 0);
|
||||
return sqlite3Expr(db, TK_INTEGER, "0");
|
||||
}else{
|
||||
return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
|
||||
}
|
||||
@@ -1280,9 +1274,7 @@ void sqlite3ExprFunctionUsable(
|
||||
){
|
||||
assert( !IN_RENAME_OBJECT );
|
||||
assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 );
|
||||
if( ExprHasProperty(pExpr, EP_FromDDL)
|
||||
|| pParse->prepFlags & SQLITE_PREPARE_FROM_DDL
|
||||
){
|
||||
if( ExprHasProperty(pExpr, EP_FromDDL) ){
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
|
||||
|| (pParse->db->flags & SQLITE_TrustedSchema)==0
|
||||
){
|
||||
@@ -1978,7 +1970,9 @@ Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){
|
||||
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
|
||||
pNew->iLimit = 0;
|
||||
pNew->iOffset = 0;
|
||||
pNew->selFlags = p->selFlags;
|
||||
pNew->selFlags = p->selFlags & ~(u32)SF_UsesEphemeral;
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->nSelectRow = p->nSelectRow;
|
||||
pNew->pWith = sqlite3WithDup(db, p->pWith);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
@@ -2630,7 +2624,7 @@ static int exprIsConst(Parse *pParse, Expr *p, int initFlag){
|
||||
|
||||
/*
|
||||
** Walk an expression tree. Return non-zero if the expression is constant
|
||||
** or return zero if the expression involves variables or function calls.
|
||||
** and 0 if it involves variables or function calls.
|
||||
**
|
||||
** For the purposes of this function, a double-quoted string (ex: "abc")
|
||||
** is considered a variable but a single-quoted string (ex: 'abc') is
|
||||
@@ -3420,7 +3414,6 @@ int sqlite3FindInIndex(
|
||||
*/
|
||||
u32 savedNQueryLoop = pParse->nQueryLoop;
|
||||
int rMayHaveNull = 0;
|
||||
int bloomOk = (inFlags & IN_INDEX_MEMBERSHIP)!=0;
|
||||
eType = IN_INDEX_EPH;
|
||||
if( inFlags & IN_INDEX_LOOP ){
|
||||
pParse->nQueryLoop = 0;
|
||||
@@ -3428,13 +3421,7 @@ int sqlite3FindInIndex(
|
||||
*prRhsHasNull = rMayHaveNull = ++pParse->nMem;
|
||||
}
|
||||
assert( pX->op==TK_IN );
|
||||
if( !bloomOk
|
||||
&& ExprUseXSelect(pX)
|
||||
&& (pX->x.pSelect->selFlags & SF_ClonedRhsIn)!=0
|
||||
){
|
||||
bloomOk = 1;
|
||||
}
|
||||
sqlite3CodeRhsOfIN(pParse, pX, iTab, bloomOk);
|
||||
sqlite3CodeRhsOfIN(pParse, pX, iTab);
|
||||
if( rMayHaveNull ){
|
||||
sqlite3SetHasNullFlag(v, iTab, rMayHaveNull);
|
||||
}
|
||||
@@ -3592,8 +3579,7 @@ static int findCompatibleInRhsSubrtn(
|
||||
void sqlite3CodeRhsOfIN(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pExpr, /* The IN operator */
|
||||
int iTab, /* Use this cursor number */
|
||||
int allowBloom /* True to allow the use of a Bloom filter */
|
||||
int iTab /* Use this cursor number */
|
||||
){
|
||||
int addrOnce = 0; /* Address of the OP_Once instruction at top */
|
||||
int addr; /* Address of OP_OpenEphemeral instruction */
|
||||
@@ -3715,10 +3701,7 @@ void sqlite3CodeRhsOfIN(
|
||||
sqlite3SelectDestInit(&dest, SRT_Set, iTab);
|
||||
dest.zAffSdst = exprINAffinity(pParse, pExpr);
|
||||
pSelect->iLimit = 0;
|
||||
if( addrOnce
|
||||
&& allowBloom
|
||||
&& OptimizationEnabled(pParse->db, SQLITE_BloomFilter)
|
||||
){
|
||||
if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
|
||||
int regBloom = ++pParse->nMem;
|
||||
addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom);
|
||||
VdbeComment((v, "Bloom filter"));
|
||||
@@ -3908,22 +3891,9 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
pParse->nMem += nReg;
|
||||
if( pExpr->op==TK_SELECT ){
|
||||
dest.eDest = SRT_Mem;
|
||||
if( (pSel->selFlags&SF_Distinct) && pSel->pLimit && pSel->pLimit->pRight ){
|
||||
/* If there is both a DISTINCT and an OFFSET clause, then allocate
|
||||
** a separate dest.iSdst array for sqlite3Select() and other
|
||||
** routines to populate. In this case results will be copied over
|
||||
** into the dest.iSDParm array only after OFFSET processing. This
|
||||
** ensures that in the case where OFFSET excludes all rows, the
|
||||
** dest.iSDParm array is not left populated with the contents of the
|
||||
** last row visited - it should be all NULLs if all rows were
|
||||
** excluded by OFFSET. */
|
||||
dest.iSdst = pParse->nMem+1;
|
||||
pParse->nMem += nReg;
|
||||
}else{
|
||||
dest.iSdst = dest.iSDParm;
|
||||
}
|
||||
dest.iSdst = dest.iSDParm;
|
||||
dest.nSdst = nReg;
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, pParse->nMem);
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
|
||||
VdbeComment((v, "Init subquery result"));
|
||||
}else{
|
||||
dest.eDest = SRT_Exists;
|
||||
@@ -3939,7 +3909,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
|| (pLeft->u.iValue!=1 && pLeft->u.iValue!=0)
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
pLimit = sqlite3ExprInt32(db, 0);
|
||||
pLimit = sqlite3Expr(db, TK_INTEGER, "0");
|
||||
if( pLimit ){
|
||||
pLimit->affExpr = SQLITE_AFF_NUMERIC;
|
||||
pLimit = sqlite3PExpr(pParse, TK_NE,
|
||||
@@ -3950,7 +3920,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
}else{
|
||||
/* If there is no pre-existing limit add a limit of 1 */
|
||||
pLimit = sqlite3ExprInt32(pParse->db, 1);
|
||||
pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1");
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
|
||||
}
|
||||
pSel->iLimit = 0;
|
||||
@@ -4211,9 +4181,8 @@ static void sqlite3ExprCodeIN(
|
||||
if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
||||
const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr);
|
||||
assert( pOp->opcode==OP_Once || pParse->nErr );
|
||||
if( pOp->p3>0 ){ /* tag-202407032019 */
|
||||
assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter)
|
||||
|| pParse->nErr );
|
||||
if( pOp->opcode==OP_Once && pOp->p3>0 ){ /* tag-202407032019 */
|
||||
assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) );
|
||||
sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse,
|
||||
rLhs, nVector); VdbeCoverage(v);
|
||||
}
|
||||
@@ -4303,7 +4272,7 @@ sqlite3ExprCodeIN_oom_error:
|
||||
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
|
||||
if( ALWAYS(z!=0) ){
|
||||
double value;
|
||||
sqlite3AtoF(z, &value);
|
||||
sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
|
||||
if( negateFlag ) value = -value;
|
||||
sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL);
|
||||
@@ -7404,10 +7373,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
if( pIEpr==0 ) break;
|
||||
if( NEVER(!ExprUseYTab(pExpr)) ) break;
|
||||
for(i=0; i<pSrcList->nSrc; i++){
|
||||
if( pSrcList->a[i].iCursor==pIEpr->iDataCur ){
|
||||
testcase( i>0 );
|
||||
break;
|
||||
}
|
||||
if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break;
|
||||
}
|
||||
if( i>=pSrcList->nSrc ) break;
|
||||
if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */
|
||||
|
||||
+5
-7
@@ -688,7 +688,6 @@ FKey *sqlite3FkReferences(Table *pTab){
|
||||
static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
|
||||
if( p ){
|
||||
TriggerStep *pStep = p->step_list;
|
||||
sqlite3SrcListDelete(dbMem, pStep->pSrc);
|
||||
sqlite3ExprDelete(dbMem, pStep->pWhere);
|
||||
sqlite3ExprListDelete(dbMem, pStep->pExprList);
|
||||
sqlite3SelectDelete(dbMem, pStep->pSelect);
|
||||
@@ -908,7 +907,6 @@ void sqlite3FkCheck(
|
||||
if( !IsOrdinaryTable(pTab) ) return;
|
||||
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb>=00 && iDb<db->nDb );
|
||||
zDb = db->aDb[iDb].zDbSName;
|
||||
|
||||
/* Loop through all the foreign key constraints for which pTab is the
|
||||
@@ -1356,14 +1354,14 @@ static Trigger *fkActionTrigger(
|
||||
|
||||
pTrigger = (Trigger *)sqlite3DbMallocZero(db,
|
||||
sizeof(Trigger) + /* struct Trigger */
|
||||
sizeof(TriggerStep) /* Single step in trigger program */
|
||||
sizeof(TriggerStep) + /* Single step in trigger program */
|
||||
nFrom + 1 /* Space for pStep->zTarget */
|
||||
);
|
||||
if( pTrigger ){
|
||||
pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
|
||||
pStep->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pStep->pSrc ){
|
||||
pStep->pSrc->a[0].zName = sqlite3DbStrNDup(db, zFrom, nFrom);
|
||||
}
|
||||
pStep->zTarget = (char *)&pStep[1];
|
||||
memcpy((char *)pStep->zTarget, zFrom, nFrom);
|
||||
|
||||
pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
|
||||
pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
||||
|
||||
+7
-7
@@ -466,7 +466,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
}
|
||||
sqlite3AtoF(zBuf, &r);
|
||||
sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8);
|
||||
sqlite3_free(zBuf);
|
||||
}
|
||||
sqlite3_result_double(context, r);
|
||||
@@ -1104,7 +1104,7 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){
|
||||
sqlite3_str_appendf(pStr, "%!0.15g", r1);
|
||||
zVal = sqlite3_str_value(pStr);
|
||||
if( zVal ){
|
||||
sqlite3AtoF(zVal, &r2);
|
||||
sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
|
||||
if( r1!=r2 ){
|
||||
sqlite3_str_reset(pStr);
|
||||
sqlite3_str_appendf(pStr, "%!0.20e", r1);
|
||||
@@ -1201,7 +1201,7 @@ static void unistrFunc(
|
||||
}
|
||||
i = j = 0;
|
||||
while( i<nIn ){
|
||||
const char *z = strchr(&zIn[i],'\\');
|
||||
char *z = strchr(&zIn[i],'\\');
|
||||
if( z==0 ){
|
||||
n = nIn - i;
|
||||
memmove(&zOut[j], &zIn[i], n);
|
||||
@@ -1238,7 +1238,7 @@ static void unistrFunc(
|
||||
}
|
||||
}
|
||||
zOut[j] = 0;
|
||||
sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8_ZT);
|
||||
sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8);
|
||||
return;
|
||||
|
||||
unistr_error:
|
||||
@@ -1331,7 +1331,7 @@ static void charFunc(
|
||||
} \
|
||||
}
|
||||
*zOut = 0;
|
||||
sqlite3_result_text64(context, (char*)z, zOut-z,sqlite3_free,SQLITE_UTF8_ZT);
|
||||
sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1360,7 +1360,7 @@ static void hexFunc(
|
||||
}
|
||||
*z = 0;
|
||||
sqlite3_result_text64(context, zHex, (u64)(z-zHex),
|
||||
sqlite3_free, SQLITE_UTF8_ZT);
|
||||
sqlite3_free, SQLITE_UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1698,7 +1698,7 @@ static void concatFuncCore(
|
||||
}
|
||||
z[j] = 0;
|
||||
assert( j<=n );
|
||||
sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8_ZT);
|
||||
sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+39
-74
@@ -328,10 +328,7 @@ struct JsonString {
|
||||
#define JSON_SQL 0x02 /* Result is always SQL */
|
||||
#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
|
||||
#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
|
||||
#define JSON_AINS 0x08 /* json_array_insert(), not json_insert() */
|
||||
#define JSON_BLOB 0x10 /* Use the BLOB output format */
|
||||
|
||||
#define JSON_INSERT_TYPE(X) (((X)&0xC)>>2)
|
||||
#define JSON_BLOB 0x08 /* Use the BLOB output format */
|
||||
|
||||
|
||||
/* A parsed JSON value. Lifecycle:
|
||||
@@ -377,7 +374,6 @@ struct JsonParse {
|
||||
#define JEDIT_REPL 2 /* Overwrite if exists */
|
||||
#define JEDIT_INS 3 /* Insert if not exists */
|
||||
#define JEDIT_SET 4 /* Insert or overwrite */
|
||||
#define JEDIT_AINS 5 /* array_insert() */
|
||||
|
||||
/*
|
||||
** Maximum nesting depth of JSON for this implementation.
|
||||
@@ -2874,8 +2870,7 @@ static int jsonLabelCompare(
|
||||
*/
|
||||
#define JSON_LOOKUP_ERROR 0xffffffff
|
||||
#define JSON_LOOKUP_NOTFOUND 0xfffffffe
|
||||
#define JSON_LOOKUP_NOTARRAY 0xfffffffd
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffc
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffd
|
||||
#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
|
||||
|
||||
/* Forward declaration */
|
||||
@@ -2904,7 +2899,7 @@ static u32 jsonLookupStep(JsonParse*,u32,const char*,u32);
|
||||
static u32 jsonCreateEditSubstructure(
|
||||
JsonParse *pParse, /* The original JSONB that is being edited */
|
||||
JsonParse *pIns, /* Populate this with the blob data to insert */
|
||||
const char *zTail /* Tail of the path that determines substructure */
|
||||
const char *zTail /* Tail of the path that determins substructure */
|
||||
){
|
||||
static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
|
||||
int rc;
|
||||
@@ -2939,9 +2934,9 @@ static u32 jsonCreateEditSubstructure(
|
||||
** Return one of the JSON_LOOKUP error codes if problems are seen.
|
||||
**
|
||||
** This routine will also modify the blob. If pParse->eEdit is one of
|
||||
** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, JEDIT_SET, or JEDIT_AINS, then changes
|
||||
** might be made to the selected value. If an edit is performed, then the
|
||||
** return value does not necessarily point to the select element. If an edit
|
||||
** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be
|
||||
** made to the selected value. If an edit is performed, then the return
|
||||
** value does not necessarily point to the select element. If an edit
|
||||
** is performed, the return value is only useful for detecting error
|
||||
** conditions.
|
||||
*/
|
||||
@@ -2967,13 +2962,6 @@ static u32 jsonLookupStep(
|
||||
jsonBlobEdit(pParse, iRoot, sz, 0, 0);
|
||||
}else if( pParse->eEdit==JEDIT_INS ){
|
||||
/* Already exists, so json_insert() is a no-op */
|
||||
}else if( pParse->eEdit==JEDIT_AINS ){
|
||||
/* json_array_insert() */
|
||||
if( zPath[-1]!=']' ){
|
||||
return JSON_LOOKUP_NOTARRAY;
|
||||
}else{
|
||||
jsonBlobEdit(pParse, iRoot, 0, pParse->aIns, pParse->nIns);
|
||||
}
|
||||
}else{
|
||||
/* json_set() or json_replace() */
|
||||
jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns);
|
||||
@@ -3045,10 +3033,6 @@ static u32 jsonLookupStep(
|
||||
JsonParse ix; /* Header of the label to be inserted */
|
||||
testcase( pParse->eEdit==JEDIT_INS );
|
||||
testcase( pParse->eEdit==JEDIT_SET );
|
||||
testcase( pParse->eEdit==JEDIT_AINS );
|
||||
if( pParse->eEdit==JEDIT_AINS && sqlite3_strglob("*]",&zPath[i])!=0 ){
|
||||
return JSON_LOOKUP_NOTARRAY;
|
||||
}
|
||||
memset(&ix, 0, sizeof(ix));
|
||||
ix.db = pParse->db;
|
||||
jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0);
|
||||
@@ -3076,32 +3060,28 @@ static u32 jsonLookupStep(
|
||||
return rc;
|
||||
}
|
||||
}else if( zPath[0]=='[' ){
|
||||
u64 kk = 0;
|
||||
x = pParse->aBlob[iRoot] & 0x0f;
|
||||
if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND;
|
||||
n = jsonbPayloadSize(pParse, iRoot, &sz);
|
||||
k = 0;
|
||||
i = 1;
|
||||
while( sqlite3Isdigit(zPath[i]) ){
|
||||
if( kk<0xffffffff ) kk = kk*10 + zPath[i] - '0';
|
||||
/* ^^^^^^^^^^--- Allow kk to be bigger than any JSON array so that
|
||||
** we get NOTFOUND instead of PATHERROR, without overflowing kk. */
|
||||
k = k*10 + zPath[i] - '0';
|
||||
i++;
|
||||
}
|
||||
if( i<2 || zPath[i]!=']' ){
|
||||
if( zPath[1]=='#' ){
|
||||
kk = jsonbArrayCount(pParse, iRoot);
|
||||
k = jsonbArrayCount(pParse, iRoot);
|
||||
i = 2;
|
||||
if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
|
||||
u64 nn = 0;
|
||||
unsigned int nn = 0;
|
||||
i = 3;
|
||||
do{
|
||||
if( nn<0xffffffff ) nn = nn*10 + zPath[i] - '0';
|
||||
/* ^^^^^^^^^^--- Allow nn to be bigger than any JSON array to
|
||||
** get NOTFOUND instead of PATHERROR, without overflowing nn. */
|
||||
nn = nn*10 + zPath[i] - '0';
|
||||
i++;
|
||||
}while( sqlite3Isdigit(zPath[i]) );
|
||||
if( nn>kk ) return JSON_LOOKUP_NOTFOUND;
|
||||
kk -= nn;
|
||||
if( nn>k ) return JSON_LOOKUP_NOTFOUND;
|
||||
k -= nn;
|
||||
}
|
||||
if( zPath[i]!=']' ){
|
||||
return JSON_LOOKUP_PATHERROR;
|
||||
@@ -3113,22 +3093,21 @@ static u32 jsonLookupStep(
|
||||
j = iRoot+n;
|
||||
iEnd = j+sz;
|
||||
while( j<iEnd ){
|
||||
if( kk==0 ){
|
||||
if( k==0 ){
|
||||
rc = jsonLookupStep(pParse, j, &zPath[i+1], 0);
|
||||
if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
|
||||
return rc;
|
||||
}
|
||||
kk--;
|
||||
k--;
|
||||
n = jsonbPayloadSize(pParse, j, &sz);
|
||||
if( n==0 ) return JSON_LOOKUP_ERROR;
|
||||
j += n+sz;
|
||||
}
|
||||
if( j>iEnd ) return JSON_LOOKUP_ERROR;
|
||||
if( kk>0 ) return JSON_LOOKUP_NOTFOUND;
|
||||
if( k>0 ) return JSON_LOOKUP_NOTFOUND;
|
||||
if( pParse->eEdit>=JEDIT_INS ){
|
||||
JsonParse v;
|
||||
testcase( pParse->eEdit==JEDIT_INS );
|
||||
testcase( pParse->eEdit==JEDIT_AINS );
|
||||
testcase( pParse->eEdit==JEDIT_SET );
|
||||
rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]);
|
||||
if( !JSON_LOOKUP_ISERROR(rc)
|
||||
@@ -3266,7 +3245,7 @@ static void jsonReturnFromBlob(
|
||||
to_double:
|
||||
z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
|
||||
if( z==0 ) goto returnfromblob_oom;
|
||||
rc = sqlite3AtoF(z, &r);
|
||||
rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
sqlite3DbFree(db, z);
|
||||
if( rc<=0 ) goto returnfromblob_malformed;
|
||||
sqlite3_result_double(pCtx, r);
|
||||
@@ -3453,15 +3432,9 @@ static int jsonFunctionArgToBlob(
|
||||
*/
|
||||
static char *jsonBadPathError(
|
||||
sqlite3_context *ctx, /* The function call containing the error */
|
||||
const char *zPath, /* The path with the problem */
|
||||
int rc /* Maybe JSON_LOOKUP_NOTARRAY */
|
||||
const char *zPath /* The path with the problem */
|
||||
){
|
||||
char *zMsg;
|
||||
if( rc==(int)JSON_LOOKUP_NOTARRAY ){
|
||||
zMsg = sqlite3_mprintf("not an array element: %Q", zPath);
|
||||
}else{
|
||||
zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
|
||||
}
|
||||
char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
|
||||
if( ctx==0 ) return zMsg;
|
||||
if( zMsg ){
|
||||
sqlite3_result_error(ctx, zMsg, -1);
|
||||
@@ -3478,13 +3451,13 @@ static char *jsonBadPathError(
|
||||
** and return the result.
|
||||
**
|
||||
** The specific operation is determined by eEdit, which can be one
|
||||
** of JEDIT_INS, JEDIT_REPL, JEDIT_SET, or JEDIT_AINS.
|
||||
** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET.
|
||||
*/
|
||||
static void jsonInsertIntoBlob(
|
||||
sqlite3_context *ctx,
|
||||
int argc,
|
||||
sqlite3_value **argv,
|
||||
int eEdit /* JEDIT_INS, JEDIT_REPL, JEDIT_SET, JEDIT_AINS */
|
||||
int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */
|
||||
){
|
||||
int i;
|
||||
u32 rc = 0;
|
||||
@@ -3536,7 +3509,7 @@ jsonInsertIntoBlob_patherror:
|
||||
if( rc==JSON_LOOKUP_ERROR ){
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
jsonBadPathError(ctx, zPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3978,7 +3951,7 @@ static void jsonArrayLengthFunc(
|
||||
if( i==JSON_LOOKUP_NOTFOUND ){
|
||||
/* no-op */
|
||||
}else if( i==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
jsonBadPathError(ctx, zPath);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -4083,7 +4056,7 @@ static void jsonExtractFunc(
|
||||
j = jsonLookupStep(p, 0, jx.zBuf, 0);
|
||||
jsonStringReset(&jx);
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
jsonBadPathError(ctx, zPath);
|
||||
goto json_extract_error;
|
||||
}
|
||||
if( j<p->nBlob ){
|
||||
@@ -4118,7 +4091,7 @@ static void jsonExtractFunc(
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
goto json_extract_error;
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
jsonBadPathError(ctx, zPath);
|
||||
goto json_extract_error;
|
||||
}
|
||||
}
|
||||
@@ -4447,7 +4420,7 @@ static void jsonRemoveFunc(
|
||||
if( rc==JSON_LOOKUP_NOTFOUND ){
|
||||
continue; /* No-op */
|
||||
}else if( rc==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
jsonBadPathError(ctx, zPath);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -4459,7 +4432,7 @@ static void jsonRemoveFunc(
|
||||
return;
|
||||
|
||||
json_remove_patherror:
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
jsonBadPathError(ctx, zPath);
|
||||
|
||||
json_remove_done:
|
||||
jsonParseFree(p);
|
||||
@@ -4503,18 +4476,16 @@ static void jsonSetFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
|
||||
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
|
||||
int eInsType = JSON_INSERT_TYPE(flags);
|
||||
static const char *azInsType[] = { "insert", "set", "array_insert" };
|
||||
static const u8 aEditType[] = { JEDIT_INS, JEDIT_SET, JEDIT_AINS };
|
||||
int bIsSet = (flags&JSON_ISSET)!=0;
|
||||
|
||||
if( argc<1 ) return;
|
||||
assert( eInsType>=0 && eInsType<=2 );
|
||||
if( (argc&1)==0 ) {
|
||||
jsonWrongNumArgs(ctx, azInsType[eInsType]);
|
||||
jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
|
||||
return;
|
||||
}
|
||||
jsonInsertIntoBlob(ctx, argc, argv, aEditType[eInsType]);
|
||||
jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4539,7 +4510,7 @@ static void jsonTypeFunc(
|
||||
zPath = (const char*)sqlite3_value_text(argv[1]);
|
||||
if( zPath==0 ) goto json_type_done;
|
||||
if( zPath[0]!='$' ){
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
jsonBadPathError(ctx, zPath);
|
||||
goto json_type_done;
|
||||
}
|
||||
i = jsonLookupStep(p, 0, zPath+1, 0);
|
||||
@@ -4547,7 +4518,7 @@ static void jsonTypeFunc(
|
||||
if( i==JSON_LOOKUP_NOTFOUND ){
|
||||
/* no-op */
|
||||
}else if( i==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
jsonBadPathError(ctx, zPath);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -4803,11 +4774,12 @@ static void jsonArrayStep(
|
||||
}
|
||||
static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
|
||||
JsonString *pStr;
|
||||
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
if( pStr ){
|
||||
int flags;
|
||||
pStr->pCtx = ctx;
|
||||
jsonAppendChar(pStr, ']');
|
||||
flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
|
||||
if( pStr->eErr ){
|
||||
jsonReturnString(pStr, 0, 0);
|
||||
return;
|
||||
@@ -4828,9 +4800,6 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
|
||||
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
|
||||
jsonStringTrimOneChar(pStr);
|
||||
}
|
||||
}else if( flags & JSON_BLOB ){
|
||||
static const u8 emptyArray = 0x0b;
|
||||
sqlite3_result_blob(ctx, &emptyArray, 1, SQLITE_STATIC);
|
||||
}else{
|
||||
sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
|
||||
}
|
||||
@@ -4927,11 +4896,12 @@ static void jsonObjectStep(
|
||||
}
|
||||
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
|
||||
JsonString *pStr;
|
||||
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
if( pStr ){
|
||||
int flags;
|
||||
jsonAppendChar(pStr, '}');
|
||||
pStr->pCtx = ctx;
|
||||
flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
|
||||
if( pStr->eErr ){
|
||||
jsonReturnString(pStr, 0, 0);
|
||||
return;
|
||||
@@ -4952,9 +4922,6 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
|
||||
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
|
||||
jsonStringTrimOneChar(pStr);
|
||||
}
|
||||
}else if( flags & JSON_BLOB ){
|
||||
static const unsigned char emptyObject = 0x0c;
|
||||
sqlite3_result_blob(ctx, &emptyObject, 1, SQLITE_STATIC);
|
||||
}else{
|
||||
sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
|
||||
}
|
||||
@@ -5455,7 +5422,7 @@ static int jsonEachFilter(
|
||||
if( zRoot==0 ) return SQLITE_OK;
|
||||
if( zRoot[0]!='$' ){
|
||||
sqlite3_free(cur->pVtab->zErrMsg);
|
||||
cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot, 0);
|
||||
cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
|
||||
jsonEachCursorReset(p);
|
||||
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
|
||||
}
|
||||
@@ -5473,7 +5440,7 @@ static int jsonEachFilter(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
sqlite3_free(cur->pVtab->zErrMsg);
|
||||
cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot, 0);
|
||||
cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
|
||||
jsonEachCursorReset(p);
|
||||
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
|
||||
}
|
||||
@@ -5563,8 +5530,6 @@ void sqlite3RegisterJsonFunctions(void){
|
||||
JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc),
|
||||
JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc),
|
||||
JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc),
|
||||
JFUNCTION(json_array_insert, -1,1,1, 1,0,JSON_AINS, jsonSetFunc),
|
||||
JFUNCTION(jsonb_array_insert,-1,1,0, 1,1,JSON_AINS, jsonSetFunc),
|
||||
JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc),
|
||||
JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc),
|
||||
JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc),
|
||||
|
||||
+14
-30
@@ -525,14 +525,7 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_db_status64,
|
||||
/* Version 3.52.0 and later */
|
||||
sqlite3_str_truncate,
|
||||
sqlite3_str_free,
|
||||
#ifdef SQLITE_ENABLE_CARRAY
|
||||
sqlite3_carray_bind,
|
||||
sqlite3_carray_bind_v2
|
||||
#else
|
||||
0,
|
||||
0
|
||||
#endif
|
||||
sqlite3_str_free
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
@@ -634,42 +627,33 @@ static int sqlite3LoadExtension(
|
||||
** entry point name "sqlite3_extension_init" was not found, then
|
||||
** construct an entry point name "sqlite3_X_init" where the X is
|
||||
** replaced by the lowercase value of every ASCII alphabetic
|
||||
** character in the filename after the last "/" up to the first ".",
|
||||
** and skipping the first three characters if they are "lib".
|
||||
** character in the filename after the last "/" upto the first ".",
|
||||
** and eliding the first three characters if they are "lib".
|
||||
** Examples:
|
||||
**
|
||||
** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init
|
||||
** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init
|
||||
**
|
||||
** If that still finds no entry point, repeat a second time but this
|
||||
** time include both alphabetic and numeric characters up to the first
|
||||
** ".". Example:
|
||||
**
|
||||
** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example5_init
|
||||
*/
|
||||
if( xInit==0 && zProc==0 ){
|
||||
int iFile, iEntry, c;
|
||||
int ncFile = sqlite3Strlen30(zFile);
|
||||
int cnt = 0;
|
||||
zAltEntry = sqlite3_malloc64(ncFile+30);
|
||||
if( zAltEntry==0 ){
|
||||
sqlite3OsDlClose(pVfs, handle);
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
do{
|
||||
memcpy(zAltEntry, "sqlite3_", 8);
|
||||
for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){}
|
||||
iFile++;
|
||||
if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
|
||||
for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
|
||||
if( sqlite3Isalpha(c) || (cnt && sqlite3Isdigit(c)) ){
|
||||
zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c];
|
||||
}
|
||||
memcpy(zAltEntry, "sqlite3_", 8);
|
||||
for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){}
|
||||
iFile++;
|
||||
if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
|
||||
for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
|
||||
if( sqlite3Isalpha(c) ){
|
||||
zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c];
|
||||
}
|
||||
memcpy(zAltEntry+iEntry, "_init", 6);
|
||||
zEntry = zAltEntry;
|
||||
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
|
||||
}while( xInit==0 && (++cnt)<2 );
|
||||
}
|
||||
memcpy(zAltEntry+iEntry, "_init", 6);
|
||||
zEntry = zAltEntry;
|
||||
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
|
||||
}
|
||||
if( xInit==0 ){
|
||||
if( pzErrMsg ){
|
||||
|
||||
+1
-11
@@ -2562,12 +2562,11 @@ int sqlite3_wal_checkpoint_v2(
|
||||
if( pnLog ) *pnLog = -1;
|
||||
if( pnCkpt ) *pnCkpt = -1;
|
||||
|
||||
assert( SQLITE_CHECKPOINT_NOOP==-1 );
|
||||
assert( SQLITE_CHECKPOINT_PASSIVE==0 );
|
||||
assert( SQLITE_CHECKPOINT_FULL==1 );
|
||||
assert( SQLITE_CHECKPOINT_RESTART==2 );
|
||||
assert( SQLITE_CHECKPOINT_TRUNCATE==3 );
|
||||
if( eMode<SQLITE_CHECKPOINT_NOOP || eMode>SQLITE_CHECKPOINT_TRUNCATE ){
|
||||
if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_TRUNCATE ){
|
||||
/* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint
|
||||
** mode: */
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
@@ -2946,9 +2945,6 @@ static const int aHardLimit[] = {
|
||||
#if SQLITE_MAX_SQL_LENGTH>SQLITE_MAX_LENGTH
|
||||
# error SQLITE_MAX_SQL_LENGTH must not be greater than SQLITE_MAX_LENGTH
|
||||
#endif
|
||||
#if SQLITE_MAX_SQL_LENGTH>2147482624 /* 1024 less than 2^31 */
|
||||
# error SQLITE_MAX_SQL_LENGTH must not be greater than 2147482624
|
||||
#endif
|
||||
#if SQLITE_MAX_COMPOUND_SELECT<2
|
||||
# error SQLITE_MAX_COMPOUND_SELECT must be at least 2
|
||||
#endif
|
||||
@@ -3844,12 +3840,6 @@ int sqlite3_collation_needed16(
|
||||
*/
|
||||
void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
|
||||
DbClientData *p;
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !zName || !sqlite3SafetyCheckOk(db) ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
for(p=db->pDbData; p; p=p->pNext){
|
||||
if( strcmp(p->zName, zName)==0 ){
|
||||
|
||||
+23
-1
@@ -289,6 +289,27 @@ static void mallocWithAlarm(int n, void **pp){
|
||||
*pp = p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Maximum size of any single memory allocation.
|
||||
**
|
||||
** This is not a limit on the total amount of memory used. This is
|
||||
** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc().
|
||||
**
|
||||
** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391
|
||||
** This provides a 256-byte safety margin for defense against 32-bit
|
||||
** signed integer overflow bugs when computing memory allocation sizes.
|
||||
** Paranoid applications might want to reduce the maximum allocation size
|
||||
** further for an even larger safety margin. 0x3fffffff or 0x0fffffff
|
||||
** or even smaller would be reasonable upper bounds on the size of a memory
|
||||
** allocations for most applications.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_ALLOCATION_SIZE
|
||||
# define SQLITE_MAX_ALLOCATION_SIZE 2147483391
|
||||
#endif
|
||||
#if SQLITE_MAX_ALLOCATION_SIZE>2147483391
|
||||
# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Allocate memory. This routine is like sqlite3_malloc() except that it
|
||||
** assumes the memory subsystem has already been initialized.
|
||||
@@ -512,7 +533,8 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
|
||||
sqlite3_free(pOld); /* IMP: R-26507-47431 */
|
||||
return 0;
|
||||
}
|
||||
if( nBytes>SQLITE_MAX_ALLOCATION_SIZE ){
|
||||
if( nBytes>=0x7fffff00 ){
|
||||
/* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */
|
||||
return 0;
|
||||
}
|
||||
nOld = sqlite3MallocSize(pOld);
|
||||
|
||||
@@ -129,7 +129,11 @@ static int winMutexInit(void){
|
||||
if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
|
||||
int i;
|
||||
for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
|
||||
#if SQLITE_OS_WINRT
|
||||
InitializeCriticalSectionEx(&winMutex_staticMutexes[i].mutex, 0, 0);
|
||||
#else
|
||||
InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);
|
||||
#endif
|
||||
}
|
||||
winMutex_isInit = 1;
|
||||
}else{
|
||||
@@ -219,7 +223,11 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
p->trace = 1;
|
||||
#endif
|
||||
#endif
|
||||
#if SQLITE_OS_WINRT
|
||||
InitializeCriticalSectionEx(&p->mutex, 0, 0);
|
||||
#else
|
||||
InitializeCriticalSection(&p->mutex);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+93
-175
@@ -21,7 +21,7 @@
|
||||
** Debugging logic
|
||||
*/
|
||||
|
||||
/* SQLITE_KV_TRACE() is used for tracing calls to kvrecord routines. */
|
||||
/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
|
||||
#if 0
|
||||
#define SQLITE_KV_TRACE(X) printf X
|
||||
#else
|
||||
@@ -35,6 +35,7 @@
|
||||
#define SQLITE_KV_LOG(X)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Forward declaration of objects used by this VFS implementation
|
||||
*/
|
||||
@@ -42,11 +43,6 @@ typedef struct KVVfsFile KVVfsFile;
|
||||
|
||||
/* A single open file. There are only two files represented by this
|
||||
** VFS - the database and the rollback journal.
|
||||
**
|
||||
** Maintenance reminder: if this struct changes in any way, the JSON
|
||||
** rendering of its structure must be updated in
|
||||
** sqlite3-wasm.c:sqlite3__wasm_enum_json(). There are no binary
|
||||
** compatibility concerns, so it does not need an iVersion member.
|
||||
*/
|
||||
struct KVVfsFile {
|
||||
sqlite3_file base; /* IO methods */
|
||||
@@ -96,7 +92,7 @@ static int kvvfsCurrentTime(sqlite3_vfs*, double*);
|
||||
static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
||||
|
||||
static sqlite3_vfs sqlite3OsKvvfsObject = {
|
||||
2, /* iVersion */
|
||||
1, /* iVersion */
|
||||
sizeof(KVVfsFile), /* szOsFile */
|
||||
1024, /* mxPathname */
|
||||
0, /* pNext */
|
||||
@@ -172,37 +168,23 @@ static sqlite3_io_methods kvvfs_jrnl_io_methods = {
|
||||
|
||||
/* Forward declarations for the low-level storage engine
|
||||
*/
|
||||
#ifndef SQLITE_WASM
|
||||
/* In WASM builds these are implemented in JS. */
|
||||
static int kvrecordWrite(const char*, const char *zKey, const char *zData);
|
||||
static int kvrecordDelete(const char*, const char *zKey);
|
||||
static int kvrecordRead(const char*, const char *zKey, char *zBuf, int nBuf);
|
||||
#endif
|
||||
#ifndef KVRECORD_KEY_SZ
|
||||
#define KVRECORD_KEY_SZ 32
|
||||
#endif
|
||||
static int kvstorageWrite(const char*, const char *zKey, const char *zData);
|
||||
static int kvstorageDelete(const char*, const char *zKey);
|
||||
static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
|
||||
#define KVSTORAGE_KEY_SZ 32
|
||||
|
||||
/* Expand the key name with an appropriate prefix and put the result
|
||||
** in zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
|
||||
** KVRECORD_KEY_SZ bytes.
|
||||
** KVSTORAGE_KEY_SZ bytes.
|
||||
*/
|
||||
static void kvrecordMakeKey(
|
||||
static void kvstorageMakeKey(
|
||||
const char *zClass,
|
||||
const char *zKeyIn,
|
||||
char *zKeyOut
|
||||
){
|
||||
assert( zKeyIn );
|
||||
assert( zKeyOut );
|
||||
assert( zClass );
|
||||
sqlite3_snprintf(KVRECORD_KEY_SZ, zKeyOut, "kvvfs-%s-%s",
|
||||
zClass, zKeyIn);
|
||||
sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_WASM
|
||||
/* In WASM builds do not define APIs which use fopen(), fwrite(),
|
||||
** and the like because those APIs are a portability issue for
|
||||
** WASM.
|
||||
*/
|
||||
/* Write content into a key. zClass is the particular namespace of the
|
||||
** underlying key/value store to use - either "local" or "session".
|
||||
**
|
||||
@@ -210,14 +192,14 @@ static void kvrecordMakeKey(
|
||||
**
|
||||
** Return the number of errors.
|
||||
*/
|
||||
static int kvrecordWrite(
|
||||
static int kvstorageWrite(
|
||||
const char *zClass,
|
||||
const char *zKey,
|
||||
const char *zData
|
||||
){
|
||||
FILE *fd;
|
||||
char zXKey[KVRECORD_KEY_SZ];
|
||||
kvrecordMakeKey(zClass, zKey, zXKey);
|
||||
char zXKey[KVSTORAGE_KEY_SZ];
|
||||
kvstorageMakeKey(zClass, zKey, zXKey);
|
||||
fd = fopen(zXKey, "wb");
|
||||
if( fd ){
|
||||
SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
|
||||
@@ -235,9 +217,9 @@ static int kvrecordWrite(
|
||||
** namespace given by zClass. If the key does not previously exist,
|
||||
** this routine is a no-op.
|
||||
*/
|
||||
static int kvrecordDelete(const char *zClass, const char *zKey){
|
||||
char zXKey[KVRECORD_KEY_SZ];
|
||||
kvrecordMakeKey(zClass, zKey, zXKey);
|
||||
static int kvstorageDelete(const char *zClass, const char *zKey){
|
||||
char zXKey[KVSTORAGE_KEY_SZ];
|
||||
kvstorageMakeKey(zClass, zKey, zXKey);
|
||||
unlink(zXKey);
|
||||
SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
|
||||
return 0;
|
||||
@@ -258,7 +240,7 @@ static int kvrecordDelete(const char *zClass, const char *zKey){
|
||||
** zero-terminates zBuf at zBuf[0] and returns the size of the data
|
||||
** without reading it.
|
||||
*/
|
||||
static int kvrecordRead(
|
||||
static int kvstorageRead(
|
||||
const char *zClass,
|
||||
const char *zKey,
|
||||
char *zBuf,
|
||||
@@ -266,8 +248,8 @@ static int kvrecordRead(
|
||||
){
|
||||
FILE *fd;
|
||||
struct stat buf;
|
||||
char zXKey[KVRECORD_KEY_SZ];
|
||||
kvrecordMakeKey(zClass, zKey, zXKey);
|
||||
char zXKey[KVSTORAGE_KEY_SZ];
|
||||
kvstorageMakeKey(zClass, zKey, zXKey);
|
||||
if( access(zXKey, R_OK)!=0
|
||||
|| stat(zXKey, &buf)!=0
|
||||
|| !S_ISREG(buf.st_mode)
|
||||
@@ -299,8 +281,6 @@ static int kvrecordRead(
|
||||
return (int)n;
|
||||
}
|
||||
}
|
||||
#endif /* #ifndef SQLITE_WASM */
|
||||
|
||||
|
||||
/*
|
||||
** An internal level of indirection which enables us to replace the
|
||||
@@ -308,27 +288,17 @@ static int kvrecordRead(
|
||||
** Maintenance reminder: if this struct changes in any way, the JSON
|
||||
** rendering of its structure must be updated in
|
||||
** sqlite3-wasm.c:sqlite3__wasm_enum_json(). There are no binary
|
||||
** compatibility concerns, so it does not need an iVersion member.
|
||||
** compatibility concerns, so it does not need an iVersion
|
||||
** member.
|
||||
*/
|
||||
typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods;
|
||||
struct sqlite3_kvvfs_methods {
|
||||
int (*xRcrdRead)(const char*, const char *zKey, char *zBuf, int nBuf);
|
||||
int (*xRcrdWrite)(const char*, const char *zKey, const char *zData);
|
||||
int (*xRcrdDelete)(const char*, const char *zKey);
|
||||
int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
|
||||
int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
|
||||
int (*xDelete)(const char *zClass, const char *zKey);
|
||||
const int nKeySize;
|
||||
const int nBufferSize;
|
||||
#ifndef SQLITE_WASM
|
||||
# define MAYBE_CONST const
|
||||
#else
|
||||
# define MAYBE_CONST
|
||||
#endif
|
||||
MAYBE_CONST sqlite3_vfs * pVfs;
|
||||
MAYBE_CONST sqlite3_io_methods *pIoDb;
|
||||
MAYBE_CONST sqlite3_io_methods *pIoJrnl;
|
||||
#undef MAYBE_CONST
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** This object holds the kvvfs I/O methods which may be swapped out
|
||||
** for JavaScript-side implementations in WASM builds. In such builds
|
||||
@@ -343,20 +313,10 @@ struct sqlite3_kvvfs_methods {
|
||||
const
|
||||
#endif
|
||||
sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
|
||||
#ifndef SQLITE_WASM
|
||||
.xRcrdRead = kvrecordRead,
|
||||
.xRcrdWrite = kvrecordWrite,
|
||||
.xRcrdDelete = kvrecordDelete,
|
||||
#else
|
||||
.xRcrdRead = 0,
|
||||
.xRcrdWrite = 0,
|
||||
.xRcrdDelete = 0,
|
||||
#endif
|
||||
.nKeySize = KVRECORD_KEY_SZ,
|
||||
.nBufferSize = SQLITE_KVOS_SZ,
|
||||
.pVfs = &sqlite3OsKvvfsObject,
|
||||
.pIoDb = &kvvfs_db_io_methods,
|
||||
.pIoJrnl = &kvvfs_jrnl_io_methods
|
||||
kvstorageRead,
|
||||
kvstorageWrite,
|
||||
kvstorageDelete,
|
||||
KVSTORAGE_KEY_SZ
|
||||
};
|
||||
|
||||
/****** Utility subroutines ************************************************/
|
||||
@@ -383,10 +343,7 @@ sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
|
||||
** of hexadecimal and base-26 numbers, it is always clear where
|
||||
** one stops and the next begins.
|
||||
*/
|
||||
#ifndef SQLITE_WASM
|
||||
static
|
||||
#endif
|
||||
int kvvfsEncode(const char *aData, int nData, char *aOut){
|
||||
static int kvvfsEncode(const char *aData, int nData, char *aOut){
|
||||
int i, j;
|
||||
const unsigned char *a = (const unsigned char*)aData;
|
||||
for(i=j=0; i<nData; i++){
|
||||
@@ -437,13 +394,9 @@ static const signed char kvvfsHexValue[256] = {
|
||||
** Decode the text encoding back to binary. The binary content is
|
||||
** written into pOut, which must be at least nOut bytes in length.
|
||||
**
|
||||
** The return value is the number of bytes actually written into aOut[], or
|
||||
** -1 for malformed inputs.
|
||||
** The return value is the number of bytes actually written into aOut[].
|
||||
*/
|
||||
#ifndef SQLITE_WASM
|
||||
static
|
||||
#endif
|
||||
int kvvfsDecode(const char *a, char *aOut, int nOut){
|
||||
static int kvvfsDecode(const char *a, char *aOut, int nOut){
|
||||
int i, j;
|
||||
int c;
|
||||
const unsigned char *aIn = (const unsigned char*)a;
|
||||
@@ -468,7 +421,7 @@ int kvvfsDecode(const char *a, char *aOut, int nOut){
|
||||
}else{
|
||||
aOut[j] = c<<4;
|
||||
c = kvvfsHexValue[aIn[++i]];
|
||||
if( c<0 ) return -1 /* hex bytes are always in pairs */;
|
||||
if( c<0 ) break;
|
||||
aOut[j++] += c;
|
||||
i++;
|
||||
}
|
||||
@@ -521,14 +474,13 @@ static void kvvfsDecodeJournal(
|
||||
static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
|
||||
char zData[50];
|
||||
zData[0] = 0;
|
||||
sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "sz", zData,
|
||||
sizeof(zData)-1);
|
||||
sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
|
||||
return strtoll(zData, 0, 0);
|
||||
}
|
||||
static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
|
||||
char zData[50];
|
||||
sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
|
||||
return sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, "sz", zData);
|
||||
return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
|
||||
}
|
||||
|
||||
/****** sqlite3_io_methods methods ******************************************/
|
||||
@@ -539,13 +491,10 @@ static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
|
||||
static int kvvfsClose(sqlite3_file *pProtoFile){
|
||||
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
||||
|
||||
SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
|
||||
SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
|
||||
pFile->isJournal ? "journal" : "db"));
|
||||
sqlite3_free(pFile->aJrnl);
|
||||
sqlite3_free(pFile->aData);
|
||||
#ifdef SQLITE_WASM
|
||||
memset(pFile, 0, sizeof(*pFile));
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -554,30 +503,24 @@ static int kvvfsClose(sqlite3_file *pProtoFile){
|
||||
*/
|
||||
static int kvvfsReadJrnl(
|
||||
sqlite3_file *pProtoFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
||||
assert( pFile->isJournal );
|
||||
SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
|
||||
if( pFile->aJrnl==0 ){
|
||||
int rc;
|
||||
int szTxt = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "jrnl",
|
||||
0, 0);
|
||||
int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
|
||||
char *aTxt;
|
||||
if( szTxt<=4 ){
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
aTxt = sqlite3_malloc64( szTxt+1 );
|
||||
if( aTxt==0 ) return SQLITE_NOMEM;
|
||||
rc = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "jrnl",
|
||||
aTxt, szTxt+1);
|
||||
if( rc>=0 ){
|
||||
kvvfsDecodeJournal(pFile, aTxt, szTxt);
|
||||
}
|
||||
kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
|
||||
kvvfsDecodeJournal(pFile, aTxt, szTxt);
|
||||
sqlite3_free(aTxt);
|
||||
if( rc ) return rc;
|
||||
if( pFile->aJrnl==0 ) return SQLITE_IOERR;
|
||||
}
|
||||
if( iOfst+iAmt>pFile->nJrnl ){
|
||||
@@ -592,8 +535,8 @@ static int kvvfsReadJrnl(
|
||||
*/
|
||||
static int kvvfsReadDb(
|
||||
sqlite3_file *pProtoFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
||||
@@ -617,8 +560,8 @@ static int kvvfsReadDb(
|
||||
pgno = 1;
|
||||
}
|
||||
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
|
||||
got = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, zKey,
|
||||
aData, SQLITE_KVOS_SZ-1);
|
||||
got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey,
|
||||
aData, SQLITE_KVOS_SZ-1);
|
||||
if( got<0 ){
|
||||
n = 0;
|
||||
}else{
|
||||
@@ -650,8 +593,8 @@ static int kvvfsReadDb(
|
||||
*/
|
||||
static int kvvfsWriteJrnl(
|
||||
sqlite3_file *pProtoFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
||||
@@ -678,15 +621,14 @@ static int kvvfsWriteJrnl(
|
||||
*/
|
||||
static int kvvfsWriteDb(
|
||||
sqlite3_file *pProtoFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
||||
unsigned int pgno;
|
||||
char zKey[30];
|
||||
char *aData = pFile->aData;
|
||||
int rc;
|
||||
SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
|
||||
assert( iAmt>=512 && iAmt<=65536 );
|
||||
assert( (iAmt & (iAmt-1))==0 );
|
||||
@@ -695,13 +637,13 @@ static int kvvfsWriteDb(
|
||||
pgno = 1 + iOfst/iAmt;
|
||||
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
|
||||
kvvfsEncode(zBuf, iAmt, aData);
|
||||
rc = sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, zKey, aData);
|
||||
if( 0==rc ){
|
||||
if( iOfst+iAmt > pFile->szDb ){
|
||||
pFile->szDb = iOfst + iAmt;
|
||||
}
|
||||
if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
return rc;
|
||||
if( iOfst+iAmt > pFile->szDb ){
|
||||
pFile->szDb = iOfst + iAmt;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -711,7 +653,7 @@ static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
|
||||
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
||||
SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
|
||||
assert( size==0 );
|
||||
sqlite3KvvfsMethods.xRcrdDelete(pFile->zClass, "jrnl");
|
||||
sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
|
||||
sqlite3_free(pFile->aJrnl);
|
||||
pFile->aJrnl = 0;
|
||||
pFile->nJrnl = 0;
|
||||
@@ -720,7 +662,7 @@ static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
|
||||
static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
|
||||
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
||||
if( pFile->szDb>size
|
||||
&& pFile->szPage>0
|
||||
&& pFile->szPage>0
|
||||
&& (size % pFile->szPage)==0
|
||||
){
|
||||
char zKey[50];
|
||||
@@ -730,7 +672,7 @@ static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
|
||||
pgnoMax = 2 + pFile->szDb/pFile->szPage;
|
||||
while( pgno<=pgnoMax ){
|
||||
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
|
||||
sqlite3KvvfsMethods.xRcrdDelete(pFile->zClass, zKey);
|
||||
sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
|
||||
pgno++;
|
||||
}
|
||||
pFile->szDb = size;
|
||||
@@ -762,7 +704,7 @@ static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
|
||||
}while( n>0 );
|
||||
zOut[i++] = ' ';
|
||||
kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
|
||||
i = sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, "jrnl", zOut);
|
||||
i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
|
||||
sqlite3_free(zOut);
|
||||
return i ? SQLITE_IOERR : SQLITE_OK;
|
||||
}
|
||||
@@ -876,32 +818,33 @@ static int kvvfsOpen(
|
||||
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
||||
if( zName==0 ) zName = "";
|
||||
SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
|
||||
assert(!pFile->zClass);
|
||||
assert(!pFile->aData);
|
||||
assert(!pFile->aJrnl);
|
||||
assert(!pFile->nJrnl);
|
||||
assert(!pFile->base.pMethods);
|
||||
pFile->szPage = -1;
|
||||
pFile->szDb = -1;
|
||||
if( 0==sqlite3_strglob("*-journal", zName) ){
|
||||
pFile->isJournal = 1;
|
||||
pFile->base.pMethods = &kvvfs_jrnl_io_methods;
|
||||
if( 0==strcmp("session-journal",zName) ){
|
||||
pFile->zClass = "session";
|
||||
}else if( 0==strcmp("local-journal",zName) ){
|
||||
pFile->zClass = "local";
|
||||
}
|
||||
}else{
|
||||
if( strcmp(zName, "local")==0
|
||||
|| strcmp(zName, "session")==0
|
||||
){
|
||||
pFile->isJournal = 0;
|
||||
pFile->base.pMethods = &kvvfs_db_io_methods;
|
||||
}else
|
||||
if( strcmp(zName, "local-journal")==0
|
||||
|| strcmp(zName, "session-journal")==0
|
||||
){
|
||||
pFile->isJournal = 1;
|
||||
pFile->base.pMethods = &kvvfs_jrnl_io_methods;
|
||||
}else{
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
if( !pFile->zClass ){
|
||||
pFile->zClass = zName;
|
||||
if( zName[0]=='s' ){
|
||||
pFile->zClass = "session";
|
||||
}else{
|
||||
pFile->zClass = "local";
|
||||
}
|
||||
pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ);
|
||||
if( pFile->aData==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pFile->aJrnl = 0;
|
||||
pFile->nJrnl = 0;
|
||||
pFile->szPage = -1;
|
||||
pFile->szDb = -1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -911,17 +854,13 @@ static int kvvfsOpen(
|
||||
** returning.
|
||||
*/
|
||||
static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
int rc /* The JS impl can fail with OOM in argument conversion */;
|
||||
if( strcmp(zPath, "local-journal")==0 ){
|
||||
rc = sqlite3KvvfsMethods.xRcrdDelete("local", "jrnl");
|
||||
sqlite3KvvfsMethods.xDelete("local", "jrnl");
|
||||
}else
|
||||
if( strcmp(zPath, "session-journal")==0 ){
|
||||
rc = sqlite3KvvfsMethods.xRcrdDelete("session", "jrnl");
|
||||
sqlite3KvvfsMethods.xDelete("session", "jrnl");
|
||||
}
|
||||
else{
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -929,48 +868,27 @@ static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
** is available, or false otherwise.
|
||||
*/
|
||||
static int kvvfsAccess(
|
||||
sqlite3_vfs *pProtoVfs,
|
||||
const char *zPath,
|
||||
int flags,
|
||||
sqlite3_vfs *pProtoVfs,
|
||||
const char *zPath,
|
||||
int flags,
|
||||
int *pResOut
|
||||
){
|
||||
SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
|
||||
#if 0 && defined(SQLITE_WASM)
|
||||
/*
|
||||
** This is not having the desired effect in the JS bindings.
|
||||
** It's ostensibly the same logic as the #else block, but
|
||||
** it's not behaving that way.
|
||||
**
|
||||
** In JS we map all zPaths to Storage objects, and -journal files
|
||||
** are mapped to the storage for the main db (which is is exactly
|
||||
** what the mapping of "local-journal" -> "local" is doing).
|
||||
*/
|
||||
const char *zKey = (0==sqlite3_strglob("*-journal", zPath))
|
||||
? "jrnl" : "sz";
|
||||
*pResOut =
|
||||
sqlite3KvvfsMethods.xRcrdRead(zPath, zKey, 0, 0)>0;
|
||||
#else
|
||||
if( strcmp(zPath, "local-journal")==0 ){
|
||||
*pResOut =
|
||||
sqlite3KvvfsMethods.xRcrdRead("local", "jrnl", 0, 0)>0;
|
||||
*pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
|
||||
}else
|
||||
if( strcmp(zPath, "session-journal")==0 ){
|
||||
*pResOut =
|
||||
sqlite3KvvfsMethods.xRcrdRead("session", "jrnl", 0, 0)>0;
|
||||
*pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
|
||||
}else
|
||||
if( strcmp(zPath, "local")==0 ){
|
||||
*pResOut =
|
||||
sqlite3KvvfsMethods.xRcrdRead("local", "sz", 0, 0)>0;
|
||||
*pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
|
||||
}else
|
||||
if( strcmp(zPath, "session")==0 ){
|
||||
*pResOut =
|
||||
sqlite3KvvfsMethods.xRcrdRead("session", "sz", 0, 0)>0;
|
||||
*pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
|
||||
}else
|
||||
{
|
||||
*pResOut = 0;
|
||||
}
|
||||
/*all current JS tests avoid triggering: assert( *pResOut == 0 ); */
|
||||
#endif
|
||||
SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -981,9 +899,9 @@ static int kvvfsAccess(
|
||||
** of at least (INST_MAX_PATHNAME+1) bytes.
|
||||
*/
|
||||
static int kvvfsFullPathname(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int nOut,
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int nOut,
|
||||
char *zOut
|
||||
){
|
||||
size_t nPath;
|
||||
@@ -1006,7 +924,7 @@ static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate the buffer pointed to by zBufOut with nByte bytes of
|
||||
** Populate the buffer pointed to by zBufOut with nByte bytes of
|
||||
** random data.
|
||||
*/
|
||||
static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
@@ -1015,7 +933,7 @@ static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
}
|
||||
|
||||
/*
|
||||
** Sleep for nMicro microseconds. Return the number of microseconds
|
||||
** Sleep for nMicro microseconds. Return the number of microseconds
|
||||
** actually slept.
|
||||
*/
|
||||
static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
@@ -1043,7 +961,7 @@ static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
|
||||
#endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
|
||||
|
||||
#if SQLITE_OS_KV
|
||||
/*
|
||||
/*
|
||||
** This routine is called initialize the KV-vfs as the default VFS.
|
||||
*/
|
||||
int sqlite3_os_init(void){
|
||||
|
||||
+34
-45
@@ -2027,18 +2027,12 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
||||
pInode->nLock++;
|
||||
pInode->nShared = 1;
|
||||
}
|
||||
}else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
|
||||
}else if( (eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1)
|
||||
|| unixIsSharingShmNode(pFile)
|
||||
){
|
||||
/* We are trying for an exclusive lock but another thread in this
|
||||
** same process is still holding a shared lock. */
|
||||
rc = SQLITE_BUSY;
|
||||
}else if( unixIsSharingShmNode(pFile) ){
|
||||
/* We are in WAL mode and attempting to delete the SHM and WAL
|
||||
** files due to closing the connection or changing out of WAL mode,
|
||||
** but another process still holds locks on the SHM file, thus
|
||||
** indicating that database locks have been broken, perhaps due
|
||||
** to a rogue close(open(dbFile)) or similar.
|
||||
*/
|
||||
rc = SQLITE_BUSY;
|
||||
}else{
|
||||
/* The request was for a RESERVED or EXCLUSIVE lock. It is
|
||||
** assumed that there is a SHARED or greater lock on the file
|
||||
@@ -3762,20 +3756,18 @@ int sqlite3_fullsync_count = 0;
|
||||
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
|
||||
** or power failure will likely corrupt the database file.
|
||||
**
|
||||
** SQLite sets the dataOnly flag if the size of the file is unchanged.
|
||||
** The idea behind dataOnly is that it should only write the file content
|
||||
** to disk, not the inode. We only set dataOnly if the file size is
|
||||
** unchanged since the file size is part of the inode. However,
|
||||
** Ted Ts'o tells us that fdatasync() will also write the inode if the
|
||||
** file size has changed. The only real difference between fdatasync()
|
||||
** and fsync(), Ted tells us, is that fdatasync() will not flush the
|
||||
** inode if the mtime or owner or other inode attributes have changed.
|
||||
** We only care about the file size, not the other file attributes, so
|
||||
** as far as SQLite is concerned, an fdatasync() is always adequate.
|
||||
** So, we always use fdatasync() if it is available, regardless of
|
||||
** the value of the dataOnly flag.
|
||||
** At one point we attempted to pass a flag to this function if the
|
||||
** file-size had not changed to tell it to use fdatasync() instead of
|
||||
** fsync() in this case. However, Ted Ts'o tells us that fdatasync() will
|
||||
** also write the inode if the file size has changed. The only real
|
||||
** difference between fdatasync() and fsync(), Ted tells us, is that
|
||||
** fdatasync() will not flush the inode if the mtime or owner or other
|
||||
** inode attributes have changed. We only care about the file size, not
|
||||
** the other file attributes, so as far as SQLite is concerned, an
|
||||
** fdatasync() is always adequate. So, we always use fdatasync() if it is
|
||||
** available.
|
||||
*/
|
||||
static int full_fsync(int fd, int fullSync, int dataOnly){
|
||||
static int full_fsync(int fd, int fullSync){
|
||||
int rc;
|
||||
|
||||
/* The following "ifdef/elif/else/" block has the same structure as
|
||||
@@ -3785,12 +3777,9 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
||||
#ifdef SQLITE_NO_SYNC
|
||||
UNUSED_PARAMETER(fd);
|
||||
UNUSED_PARAMETER(fullSync);
|
||||
UNUSED_PARAMETER(dataOnly);
|
||||
#elif HAVE_FULLFSYNC
|
||||
UNUSED_PARAMETER(dataOnly);
|
||||
#else
|
||||
UNUSED_PARAMETER(fullSync);
|
||||
UNUSED_PARAMETER(dataOnly);
|
||||
#endif
|
||||
|
||||
/* Record the number of times that we do a normal fsync() and
|
||||
@@ -3896,10 +3885,6 @@ static int openDirectory(const char *zFilename, int *pFd){
|
||||
/*
|
||||
** Make sure all writes to a particular file are committed to disk.
|
||||
**
|
||||
** If dataOnly==0 then both the file itself and its metadata (file
|
||||
** size, access time, etc) are synced. If dataOnly!=0 then only the
|
||||
** file data is synced.
|
||||
**
|
||||
** Under Unix, also make sure that the directory entry for the file
|
||||
** has been created by fsync-ing the directory that contains the file.
|
||||
** If we do not do this and we encounter a power failure, the directory
|
||||
@@ -3912,7 +3897,6 @@ static int unixSync(sqlite3_file *id, int flags){
|
||||
int rc;
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
|
||||
int isDataOnly = (flags&SQLITE_SYNC_DATAONLY);
|
||||
int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL;
|
||||
|
||||
/* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
|
||||
@@ -3927,7 +3911,7 @@ static int unixSync(sqlite3_file *id, int flags){
|
||||
|
||||
assert( pFile );
|
||||
OSTRACE(("SYNC %-3d\n", pFile->h));
|
||||
rc = full_fsync(pFile->h, isFullsync, isDataOnly);
|
||||
rc = full_fsync(pFile->h, isFullsync);
|
||||
SimulateIOError( rc=1 );
|
||||
if( rc ){
|
||||
storeLastErrno(pFile, errno);
|
||||
@@ -3944,7 +3928,7 @@ static int unixSync(sqlite3_file *id, int flags){
|
||||
HAVE_FULLFSYNC, isFullsync));
|
||||
rc = osOpenDirectory(pFile->zPath, &dirfd);
|
||||
if( rc==SQLITE_OK ){
|
||||
full_fsync(dirfd, 0, 0);
|
||||
full_fsync(dirfd, 0);
|
||||
robust_close(pFile, dirfd, __LINE__);
|
||||
}else{
|
||||
assert( rc==SQLITE_CANTOPEN );
|
||||
@@ -4677,21 +4661,26 @@ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){
|
||||
** still not a disaster.
|
||||
*/
|
||||
static int unixIsSharingShmNode(unixFile *pFile){
|
||||
int rc;
|
||||
unixShmNode *pShmNode;
|
||||
struct flock lock;
|
||||
if( pFile->pShm==0 ) return 0;
|
||||
if( pFile->ctrlFlags & UNIXFILE_EXCL ) return 0;
|
||||
pShmNode = pFile->pShm->pShmNode;
|
||||
#if SQLITE_ATOMIC_INTRINSICS
|
||||
assert( AtomicLoad(&pShmNode->nRef)==1 );
|
||||
#endif
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = UNIX_SHM_DMS;
|
||||
lock.l_len = 1;
|
||||
lock.l_type = F_WRLCK;
|
||||
osFcntl(pShmNode->hShm, F_GETLK, &lock);
|
||||
return (lock.l_type!=F_UNLCK);
|
||||
rc = 1;
|
||||
unixEnterMutex();
|
||||
if( ALWAYS(pShmNode->nRef==1) ){
|
||||
struct flock lock;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = UNIX_SHM_DMS;
|
||||
lock.l_len = 1;
|
||||
lock.l_type = F_WRLCK;
|
||||
osFcntl(pShmNode->hShm, F_GETLK, &lock);
|
||||
if( lock.l_type==F_UNLCK ){
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
unixLeaveMutex();
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6855,7 +6844,7 @@ static int unixDelete(
|
||||
int fd;
|
||||
rc = osOpenDirectory(zPath, &fd);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( full_fsync(fd,0,0) ){
|
||||
if( full_fsync(fd, 0) ){
|
||||
rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
|
||||
}
|
||||
robust_close(0, fd, __LINE__);
|
||||
@@ -7911,7 +7900,7 @@ static int proxyTakeConch(unixFile *pFile){
|
||||
writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
|
||||
robust_ftruncate(conchFile->h, writeSize);
|
||||
rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
|
||||
full_fsync(conchFile->h,0,0);
|
||||
full_fsync(conchFile->h, 0);
|
||||
/* If we created a new conch file (not just updated the contents of a
|
||||
** valid conch file), try to match the permissions of the database
|
||||
*/
|
||||
|
||||
+369
-67
File diff suppressed because it is too large
Load Diff
+9
-1
@@ -58,6 +58,14 @@
|
||||
# define SQLITE_OS_WINCE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with WinRT, which provides only a subset of
|
||||
** the full Win32 API.
|
||||
*/
|
||||
#if !defined(SQLITE_OS_WINRT)
|
||||
# define SQLITE_OS_WINRT 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For WinCE, some API function parameters do not appear to be declared as
|
||||
** volatile.
|
||||
@@ -72,7 +80,7 @@
|
||||
** For some Windows sub-platforms, the _beginthreadex() / _endthreadex()
|
||||
** functions are not available (e.g. those not using MSVC, Cygwin, etc).
|
||||
*/
|
||||
#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && \
|
||||
#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
|
||||
SQLITE_THREADSAFE>0 && !defined(__CYGWIN__)
|
||||
# define SQLITE_OS_WIN_THREADS 1
|
||||
#else
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user