Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 91694dbdd2 | |||
| d19866bb98 | |||
| ef42481224 | |||
| a41f2855e9 | |||
| a5da4ef4ad | |||
| 03491a1a1a | |||
| 8682e12190 | |||
| acd6fdee98 | |||
| 1fa6d9f96f | |||
| e37c0e1ce7 | |||
| afba1802a0 | |||
| 11be81d413 | |||
| 5e6f782f11 | |||
| 0476b95c43 | |||
| 4574db78a4 | |||
| 6b9986e84a | |||
| 9dea173154 | |||
| 1e506b5527 | |||
| f5c75626ff | |||
| 2f74b3c3ab | |||
| f2e8aa637e | |||
| acae8c3e5d | |||
| 411dfd4e6d | |||
| b3ec2e1f4a | |||
| 992fdfc5d8 | |||
| 370732a83a | |||
| b2b7274e10 | |||
| 7ee8836e08 | |||
| af23899318 | |||
| 5d7503a789 | |||
| 9a5efdec70 | |||
| c932033630 | |||
| 590522c18e | |||
| 91f7211caa | |||
| af2770f842 | |||
| 303b02cc0b | |||
| 8503d6451b | |||
| 47be3b23e9 | |||
| 1152250b44 | |||
| 3acaf4c07a | |||
| 104958cab0 | |||
| e55988074f | |||
| dfdfd8c7f2 | |||
| c76ed3d57d | |||
| 35100fb194 | |||
| 64c1990c00 | |||
| 9eb8dbad4d | |||
| d9620b8555 | |||
| 4d795ef7e4 | |||
| 595a0e2a4a | |||
| 9199ac1048 | |||
| cde7b77932 | |||
| 667a2a25ba | |||
| 1d315cf7b8 | |||
| ceba792a2f | |||
| c22b716e31 | |||
| 470fc9ddaa | |||
| 0cde0c62b1 | |||
| db0cb303ad | |||
| 373dc3bb3f | |||
| c64487b9c8 | |||
| b5090e4897 | |||
| 5a78b81b1b | |||
| 9ebfaad25d | |||
| 844cf56bc6 | |||
| 60ba57d9c5 | |||
| d1b51d4955 | |||
| dd2a43a225 | |||
| ac15e2d7cc | |||
| 233ff96ec5 | |||
| e483d349ab | |||
| 0d0547fec6 | |||
| 32b5fdcaea | |||
| 7d935ab46d | |||
| 06741a3c9b | |||
| 3f67ddf8f2 | |||
| ece4b0c172 | |||
| d4b56e5901 | |||
| 1ad3f61b81 | |||
| 2ad0949db4 | |||
| 88be020916 | |||
| 25c1218e73 | |||
| fd0245d771 | |||
| a0fcafe762 | |||
| cb6acda902 | |||
| 72afc3c5de | |||
| 7e8cf76c8a | |||
| 3be8b1a4f7 |
@@ -0,0 +1 @@
|
||||
compat
|
||||
@@ -0,0 +1 @@
|
||||
compat/*
|
||||
+19
-3
@@ -440,6 +440,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/ieee754.c \
|
||||
$(TOP)/ext/misc/mmapwarm.c \
|
||||
$(TOP)/ext/misc/nextchar.c \
|
||||
$(TOP)/ext/misc/normalize.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
@@ -447,7 +448,8 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/spellfix.c \
|
||||
$(TOP)/ext/misc/totype.c \
|
||||
$(TOP)/ext/misc/unionvtab.c \
|
||||
$(TOP)/ext/misc/wholenumber.c
|
||||
$(TOP)/ext/misc/wholenumber.c \
|
||||
$(TOP)/ext/misc/zipfile.c
|
||||
|
||||
# Source code to the library files needed by the test fixture
|
||||
#
|
||||
@@ -558,7 +560,8 @@ TESTPROGS = \
|
||||
sqlite3$(TEXE) \
|
||||
sqlite3_analyzer$(TEXE) \
|
||||
sqldiff$(TEXE) \
|
||||
dbhash$(TEXE)
|
||||
dbhash$(TEXE) \
|
||||
sqltclsh$(TEXE)
|
||||
|
||||
# Databases containing fuzzer test cases
|
||||
#
|
||||
@@ -583,6 +586,7 @@ SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
@@ -991,9 +995,15 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
|
||||
# Source files that go into making shell.c
|
||||
SHELL_SRC = \
|
||||
$(TOP)/src/shell.c.in \
|
||||
$(TOP)/ext/misc/appendvfs.c \
|
||||
$(TOP)/ext/misc/shathree.c \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/completion.c
|
||||
$(TOP)/ext/misc/completion.c \
|
||||
$(TOP)/ext/misc/sqlar.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
$(TOP)/src/test_windirent.c
|
||||
|
||||
shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
|
||||
$(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c
|
||||
@@ -1193,6 +1203,12 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
|
||||
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
|
||||
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in
|
||||
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh$(TEXE): sqltclsh.c
|
||||
$(LTLINK) sqltclsh.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
||||
sqlite3_expert$(TEXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
|
||||
$(LTLINK) $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert $(TLIBS)
|
||||
|
||||
|
||||
+138
-16
@@ -92,6 +92,29 @@ SPLIT_AMALGAMATION = 0
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# 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.
|
||||
#
|
||||
!IFNDEF USE_ZLIB
|
||||
USE_ZLIB = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to build zlib from source code. This is enabled by
|
||||
# default and in that case it will be assumed that the ZLIBDIR macro
|
||||
# points to the top-level source code directory for zlib.
|
||||
#
|
||||
!IFNDEF BUILD_ZLIB
|
||||
BUILD_ZLIB = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to use the International Components for Unicode (ICU).
|
||||
#
|
||||
!IFNDEF USE_ICU
|
||||
@@ -612,6 +635,15 @@ SHELL_CORE_DEP =
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# If zlib support is enabled, add the dependencies for it.
|
||||
#
|
||||
!IF $(USE_ZLIB)!=0 && $(BUILD_ZLIB)!=0
|
||||
SHELL_CORE_DEP = zlib $(SHELL_CORE_DEP)
|
||||
TESTFIXTURE_DEP = zlib $(TESTFIXTURE_DEP)
|
||||
!ENDIF
|
||||
# <</mark>>
|
||||
|
||||
# This is the core library that the shell executable should link with.
|
||||
#
|
||||
!IFNDEF SHELL_CORE_LIB
|
||||
@@ -802,12 +834,16 @@ RCC = $(RCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1
|
||||
# prior to running nmake in order to match the actual installed location and
|
||||
# version on this machine.
|
||||
#
|
||||
!IFNDEF TCLDIR
|
||||
TCLDIR = $(TOP)\compat\tcl
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF TCLINCDIR
|
||||
TCLINCDIR = c:\tcl\include
|
||||
TCLINCDIR = $(TCLDIR)\include
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF TCLLIBDIR
|
||||
TCLLIBDIR = c:\tcl\lib
|
||||
TCLLIBDIR = $(TCLDIR)\lib
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF LIBTCL
|
||||
@@ -819,7 +855,32 @@ LIBTCLSTUB = tclstub86.lib
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF LIBTCLPATH
|
||||
LIBTCLPATH = c:\tcl\bin
|
||||
LIBTCLPATH = $(TCLDIR)\bin
|
||||
!ENDIF
|
||||
|
||||
# The locations of the zlib header and library files. These variables
|
||||
# (ZLIBINCDIR, ZLIBLIBDIR, and ZLIBLIB) may be overridden via the environment
|
||||
# prior to running nmake in order to match the actual installed (or source
|
||||
# code) location on this machine.
|
||||
#
|
||||
!IFNDEF ZLIBDIR
|
||||
ZLIBDIR = $(TOP)\compat\zlib
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF ZLIBINCDIR
|
||||
ZLIBINCDIR = $(ZLIBDIR)
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF ZLIBLIBDIR
|
||||
ZLIBLIBDIR = $(ZLIBDIR)
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF ZLIBLIB
|
||||
!IF $(DYNAMIC_SHELL)!=0
|
||||
ZLIBLIB = zdll.lib
|
||||
!ELSE
|
||||
ZLIBLIB = zlib.lib
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# The locations of the ICU header and library files. These variables
|
||||
@@ -827,12 +888,16 @@ LIBTCLPATH = c:\tcl\bin
|
||||
# prior to running nmake in order to match the actual installed location on
|
||||
# this machine.
|
||||
#
|
||||
!IFNDEF ICUDIR
|
||||
ICUDIR = $(TOP)\compat\icu
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF ICUINCDIR
|
||||
ICUINCDIR = c:\icu\include
|
||||
ICUINCDIR = $(ICUDIR)\include
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF ICULIBDIR
|
||||
ICULIBDIR = c:\icu\lib
|
||||
ICULIBDIR = $(ICUDIR)\lib
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF LIBICU
|
||||
@@ -845,7 +910,11 @@ LIBICU = icuuc.lib icuin.lib
|
||||
# specific Tcl shell to use.
|
||||
#
|
||||
!IFNDEF TCLSH_CMD
|
||||
!IF $(USE_TCLSH_IN_PATH)!=0 || !EXIST("$(TCLDIR)\bin\tclsh.exe")
|
||||
TCLSH_CMD = tclsh
|
||||
!ELSE
|
||||
TCLSH_CMD = $(TCLDIR)\bin\tclsh.exe
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
# <</mark>>
|
||||
|
||||
@@ -951,6 +1020,15 @@ BCC = $(BCC) -Zi
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# If zlib support is enabled, add the compiler options for it.
|
||||
#
|
||||
!IF $(USE_ZLIB)!=0
|
||||
TCC = $(TCC) -DSQLITE_HAVE_ZLIB=1
|
||||
RCC = $(RCC) -DSQLITE_HAVE_ZLIB=1
|
||||
TCC = $(TCC) -I$(ZLIBINCDIR)
|
||||
RCC = $(RCC) -I$(ZLIBINCDIR)
|
||||
!ENDIF
|
||||
|
||||
# If ICU support is enabled, add the compiler options for it.
|
||||
#
|
||||
!IF $(USE_ICU)!=0
|
||||
@@ -1071,8 +1149,15 @@ LDFLAGS = $(LDOPTS)
|
||||
# Start with the Tcl related linker options.
|
||||
#
|
||||
!IF $(NO_TCL)==0
|
||||
LTLIBPATHS = /LIBPATH:$(TCLLIBDIR)
|
||||
LTLIBS = $(LTLIBS) $(LIBTCL)
|
||||
TCLLIBPATHS = $(TCLLIBPATHS) /LIBPATH:$(TCLLIBDIR)
|
||||
TCLLIBS = $(TCLLIBS) $(LIBTCL)
|
||||
!ENDIF
|
||||
|
||||
# If zlib support is enabled, add the linker options for it.
|
||||
#
|
||||
!IF $(USE_ZLIB)!=0
|
||||
LTLIBPATHS = $(LTLIBPATHS) /LIBPATH:$(ZLIBLIBDIR)
|
||||
LTLIBS = $(LTLIBS) $(ZLIBLIB)
|
||||
!ENDIF
|
||||
|
||||
# If ICU support is enabled, add the linker options for it.
|
||||
@@ -1415,6 +1500,7 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\ieee754.c \
|
||||
$(TOP)\ext\misc\mmapwarm.c \
|
||||
$(TOP)\ext\misc\nextchar.c \
|
||||
$(TOP)\ext\misc\normalize.c \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
$(TOP)\ext\misc\remember.c \
|
||||
@@ -1424,6 +1510,12 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\unionvtab.c \
|
||||
$(TOP)\ext\misc\wholenumber.c
|
||||
|
||||
# If use of zlib is enabled, add the "zipfile.c" source file.
|
||||
#
|
||||
!IF $(USE_ZLIB)!=0
|
||||
TESTEXT = $(TESTEXT) $(TOP)\ext\misc\zipfile.c
|
||||
!ENDIF
|
||||
|
||||
# Source code to the library files needed by the test fixture
|
||||
# (non-amalgamation)
|
||||
#
|
||||
@@ -1495,7 +1587,8 @@ TESTPROGS = \
|
||||
sqlite3_analyzer.exe \
|
||||
sqlite3_checker.exe \
|
||||
sqldiff.exe \
|
||||
dbhash.exe
|
||||
dbhash.exe \
|
||||
sqltclsh.exe
|
||||
|
||||
# Databases containing fuzzer test cases
|
||||
#
|
||||
@@ -1513,7 +1606,7 @@ FUZZDATA = \
|
||||
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC -DSQLITE_INTROSPECTION_PRAGMAS
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
@@ -1545,7 +1638,15 @@ ALL_TCL_TARGETS =
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
#
|
||||
all: dll libsqlite3.lib shell $(ALL_TCL_TARGETS)
|
||||
core: dll libsqlite3.lib shell
|
||||
|
||||
# Targets that require the Tcl library.
|
||||
#
|
||||
tcl: $(ALL_TCL_TARGETS)
|
||||
|
||||
# This Makefile target builds all of the standard binaries.
|
||||
#
|
||||
all: core tcl
|
||||
|
||||
# Dynamic link library section.
|
||||
#
|
||||
@@ -1940,7 +2041,7 @@ tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
|
||||
tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
# Rules to build opcodes.c and opcodes.h
|
||||
#
|
||||
@@ -1983,13 +2084,26 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
|
||||
# Source files that go into making shell.c
|
||||
SHELL_SRC = \
|
||||
$(TOP)\src\shell.c.in \
|
||||
$(TOP)\ext\misc\appendvfs.c \
|
||||
$(TOP)\ext\misc\shathree.c \
|
||||
$(TOP)\ext\misc\fileio.c \
|
||||
$(TOP)\ext\misc\completion.c
|
||||
$(TOP)\ext\misc\completion.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.h \
|
||||
$(TOP)\src\test_windirent.c
|
||||
|
||||
# If use of zlib is enabled, add the "zipfile.c" source file.
|
||||
#
|
||||
!IF $(USE_ZLIB)!=0
|
||||
SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\sqlar.c
|
||||
SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\zipfile.c
|
||||
!ENDIF
|
||||
|
||||
shell.c: $(SHELL_SRC) $(TOP)\tool\mkshellc.tcl
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkshellc.tcl > shell.c
|
||||
|
||||
zlib:
|
||||
pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd
|
||||
|
||||
# Rules to build the extension objects.
|
||||
#
|
||||
@@ -2167,11 +2281,11 @@ sqlite_tcl.h:
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "Tcl_HashEntry *(*createProc)" "Tcl_HashEntry *(SQLITE_TCLAPI *createProc)" >> $(SQLITETCLH)
|
||||
!ENDIF
|
||||
|
||||
testfixture.exe: $(TESTFIXTURE_SRC) $(SQLITE3H) $(LIBRESOBJS) $(HDR) $(SQLITE_TCL_DEP)
|
||||
testfixture.exe: $(TESTFIXTURE_SRC) $(TESTFIXTURE_DEP) $(SQLITE3H) $(LIBRESOBJS) $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTLINK) -DSQLITE_NO_SYNC=1 $(TESTFIXTURE_FLAGS) \
|
||||
-DBUILD_sqlite -I$(TCLINCDIR) \
|
||||
$(TESTFIXTURE_SRC) \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
extensiontest: testfixture.exe testloadext.dll
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
@@ -2221,7 +2335,14 @@ sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\s
|
||||
|
||||
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)\src\tclsqlite.c $(TOP)\tool\sqltclsh.tcl $(TOP)\ext\misc\appendvfs.c $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh.exe: sqltclsh.c
|
||||
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqltclsh.c \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(SQLITE3C) $(TLIBS)
|
||||
@@ -2241,7 +2362,7 @@ sqlite3_checker.c: $(CHECKER_DEPS)
|
||||
|
||||
sqlite3_checker.exe: sqlite3_checker.c $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_checker.c \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
dbdump.exe: $(TOP)\ext\misc\dbdump.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DDBDUMP_STANDALONE $(TOP)\ext\misc\dbdump.c $(SQLITE3C) \
|
||||
@@ -2342,6 +2463,7 @@ clean:
|
||||
del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
|
||||
del /Q sqlite-*-output.vsix 2>NUL
|
||||
del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL
|
||||
del /Q sqltclsh.exe 2>NUL
|
||||
del /Q fts5.* fts5parse.* 2>NUL
|
||||
del /Q lsm.h lsm1.c 2>NUL
|
||||
# <</mark>>
|
||||
|
||||
+11
-1
@@ -561,6 +561,7 @@ SHELL_CORE_DEP =
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
|
||||
# This is the core library that the shell executable should link with.
|
||||
#
|
||||
!IFNDEF SHELL_CORE_LIB
|
||||
@@ -929,13 +930,22 @@ LIBRESOBJS =
|
||||
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC -DSQLITE_INTROSPECTION_PRAGMAS
|
||||
!ENDIF
|
||||
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
#
|
||||
all: dll shell
|
||||
core: dll shell
|
||||
|
||||
# Targets that require the Tcl library.
|
||||
#
|
||||
tcl: $(ALL_TCL_TARGETS)
|
||||
|
||||
# This Makefile target builds all of the standard binaries.
|
||||
#
|
||||
all: core tcl
|
||||
|
||||
# Dynamic link library section.
|
||||
#
|
||||
|
||||
+1
-1
@@ -433,7 +433,7 @@ static int SQLITE_TCLAPI xF5tApi(
|
||||
int iVal;
|
||||
int bClear;
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[2], &bClear) ) return TCL_ERROR;
|
||||
iVal = ((char*)p->pApi->xGetAuxdata(p->pFts, bClear) - (char*)0);
|
||||
iVal = (int)((char*)p->pApi->xGetAuxdata(p->pFts, bClear) - (char*)0);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ int test_mdb_scan(TestDb *, void *, int, void *, int, void *, int,
|
||||
*/
|
||||
int test_lsm_open(const char*, const char *zFile, int bClear, TestDb **ppDb);
|
||||
int test_lsm_lomem_open(const char*, const char*, int bClear, TestDb **ppDb);
|
||||
int test_lsm_lomem2_open(const char*, const char*, int bClear, TestDb **ppDb);
|
||||
int test_lsm_zip_open(const char*, const char*, int bClear, TestDb **ppDb);
|
||||
int test_lsm_small_open(const char*, const char*, int bClear, TestDb **ppDb);
|
||||
int test_lsm_mt2(const char*, const char *zFile, int bClear, TestDb **ppDb);
|
||||
|
||||
@@ -721,6 +721,7 @@ static struct Lib {
|
||||
{ "sqlite3", "testdb.sqlite", sql_open },
|
||||
{ "lsm_small", "testdb.lsm_small", test_lsm_small_open },
|
||||
{ "lsm_lomem", "testdb.lsm_lomem", test_lsm_lomem_open },
|
||||
{ "lsm_lomem2", "testdb.lsm_lomem2", test_lsm_lomem2_open },
|
||||
#ifdef HAVE_ZLIB
|
||||
{ "lsm_zip", "testdb.lsm_zip", test_lsm_zip_open },
|
||||
#endif
|
||||
|
||||
@@ -1033,6 +1033,19 @@ int test_lsm_lomem_open(
|
||||
return testLsmOpen(zCfg, zFilename, bClear, ppDb);
|
||||
}
|
||||
|
||||
int test_lsm_lomem2_open(
|
||||
const char *zSpec,
|
||||
const char *zFilename,
|
||||
int bClear,
|
||||
TestDb **ppDb
|
||||
){
|
||||
/* "max_freelist=4 autocheckpoint=32" */
|
||||
const char *zCfg =
|
||||
"page_size=512 block_size=64 autoflush=0 mmap=0 "
|
||||
;
|
||||
return testLsmOpen(zCfg, zFilename, bClear, ppDb);
|
||||
}
|
||||
|
||||
int test_lsm_zip_open(
|
||||
const char *zSpec,
|
||||
const char *zFilename,
|
||||
|
||||
+1
-1
@@ -683,7 +683,7 @@ static int doWriteOp(
|
||||
int nDiff;
|
||||
|
||||
if( nQuant>pDb->nTreeLimit ){
|
||||
nQuant = pDb->nTreeLimit;
|
||||
nQuant = LSM_MAX(pDb->nTreeLimit, pgsz);
|
||||
}
|
||||
|
||||
nBefore = lsmTreeSize(pDb);
|
||||
|
||||
@@ -5252,16 +5252,15 @@ static int doLsmSingleWork(
|
||||
/* If the in-memory part of the free-list is too large, write a new
|
||||
** top-level containing just the in-memory free-list entries to disk. */
|
||||
if( rc==LSM_OK && pDb->pWorker->freelist.nEntry > pDb->nMaxFreelist ){
|
||||
int nPg = 0;
|
||||
while( rc==LSM_OK && lsmDatabaseFull(pDb) ){
|
||||
int nPg = 0;
|
||||
rc = sortedWork(pDb, 16, nMerge, 1, &nPg);
|
||||
nRem -= nPg;
|
||||
}
|
||||
if( rc==LSM_OK ){
|
||||
rc = sortedNewFreelistOnly(pDb);
|
||||
}
|
||||
nRem -= nPg;
|
||||
if( nPg ) bDirty = 1;
|
||||
bDirty = 1;
|
||||
}
|
||||
|
||||
if( rc==LSM_OK ){
|
||||
|
||||
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
** 2017-10-20
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file implements a VFS shim that allows an SQLite database to be
|
||||
** appended onto the end of some other file, such as an executable.
|
||||
**
|
||||
** A special record must appear at the end of the file that identifies the
|
||||
** file as an appended database and provides an offset to page 1. For
|
||||
** best performance page 1 should be located at a disk page boundary, though
|
||||
** that is not required.
|
||||
**
|
||||
** When opening a database using this VFS, the connection might treat
|
||||
** the file as an ordinary SQLite database, or it might treat is as a
|
||||
** database appended onto some other file. Here are the rules:
|
||||
**
|
||||
** (1) When opening a new empty file, that file is treated as an ordinary
|
||||
** database.
|
||||
**
|
||||
** (2) When opening a file that begins with the standard SQLite prefix
|
||||
** string "SQLite format 3", that file is treated as an ordinary
|
||||
** database.
|
||||
**
|
||||
** (3) When opening a file that ends with the appendvfs trailer string
|
||||
** "Start-Of-SQLite3-NNNNNNNN" that file is treated as an appended
|
||||
** database.
|
||||
**
|
||||
** (4) If none of the above apply and the SQLITE_OPEN_CREATE flag is
|
||||
** set, then a new database is appended to the already existing file.
|
||||
**
|
||||
** (5) Otherwise, SQLITE_CANTOPEN is returned.
|
||||
**
|
||||
** To avoid unnecessary complications with the PENDING_BYTE, the size of
|
||||
** the file containing the database is limited to 1GB. This VFS will refuse
|
||||
** to read or write past the 1GB mark. This restriction might be lifted in
|
||||
** future versions. For now, if you need a large database, then keep the
|
||||
** database in a separate file.
|
||||
**
|
||||
** If the file being opened is not an appended database, then this shim is
|
||||
** a pass-through into the default underlying VFS.
|
||||
**/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* The append mark at the end of the database is:
|
||||
**
|
||||
** Start-Of-SQLite3-NNNNNNNN
|
||||
** 123456789 123456789 12345
|
||||
**
|
||||
** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is
|
||||
** the offset to page 1.
|
||||
*/
|
||||
#define APND_MARK_PREFIX "Start-Of-SQLite3-"
|
||||
#define APND_MARK_PREFIX_SZ 17
|
||||
#define APND_MARK_SIZE 25
|
||||
|
||||
/*
|
||||
** Maximum size of the combined prefix + database + append-mark. This
|
||||
** must be less than 0x40000000 to avoid locking issues on Windows.
|
||||
*/
|
||||
#define APND_MAX_SIZE (65536*15259)
|
||||
|
||||
/*
|
||||
** Forward declaration of objects used by this utility
|
||||
*/
|
||||
typedef struct sqlite3_vfs ApndVfs;
|
||||
typedef struct ApndFile ApndFile;
|
||||
|
||||
/* Access to a lower-level VFS that (might) implement dynamic loading,
|
||||
** access to randomness, etc.
|
||||
*/
|
||||
#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
|
||||
#define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))
|
||||
|
||||
/* An open file */
|
||||
struct ApndFile {
|
||||
sqlite3_file base; /* IO methods */
|
||||
sqlite3_int64 iPgOne; /* File offset to page 1 */
|
||||
sqlite3_int64 iMark; /* Start of the append-mark */
|
||||
};
|
||||
|
||||
/*
|
||||
** Methods for ApndFile
|
||||
*/
|
||||
static int apndClose(sqlite3_file*);
|
||||
static int apndRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int apndWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
|
||||
static int apndTruncate(sqlite3_file*, sqlite3_int64 size);
|
||||
static int apndSync(sqlite3_file*, int flags);
|
||||
static int apndFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
||||
static int apndLock(sqlite3_file*, int);
|
||||
static int apndUnlock(sqlite3_file*, int);
|
||||
static int apndCheckReservedLock(sqlite3_file*, int *pResOut);
|
||||
static int apndFileControl(sqlite3_file*, int op, void *pArg);
|
||||
static int apndSectorSize(sqlite3_file*);
|
||||
static int apndDeviceCharacteristics(sqlite3_file*);
|
||||
static int apndShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
|
||||
static int apndShmLock(sqlite3_file*, int offset, int n, int flags);
|
||||
static void apndShmBarrier(sqlite3_file*);
|
||||
static int apndShmUnmap(sqlite3_file*, int deleteFlag);
|
||||
static int apndFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
|
||||
static int apndUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
|
||||
|
||||
/*
|
||||
** Methods for ApndVfs
|
||||
*/
|
||||
static int apndOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
||||
static int apndDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
||||
static int apndAccess(sqlite3_vfs*, const char *zName, int flags, int *);
|
||||
static int apndFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
|
||||
static void *apndDlOpen(sqlite3_vfs*, const char *zFilename);
|
||||
static void apndDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
|
||||
static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
|
||||
static void apndDlClose(sqlite3_vfs*, void*);
|
||||
static int apndRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
||||
static int apndSleep(sqlite3_vfs*, int microseconds);
|
||||
static int apndCurrentTime(sqlite3_vfs*, double*);
|
||||
static int apndGetLastError(sqlite3_vfs*, int, char *);
|
||||
static int apndCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
||||
static int apndSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
|
||||
static sqlite3_syscall_ptr apndGetSystemCall(sqlite3_vfs*, const char *z);
|
||||
static const char *apndNextSystemCall(sqlite3_vfs*, const char *zName);
|
||||
|
||||
static sqlite3_vfs apnd_vfs = {
|
||||
3, /* iVersion (set when registered) */
|
||||
0, /* szOsFile (set when registered) */
|
||||
1024, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"apndvfs", /* zName */
|
||||
0, /* pAppData (set when registered) */
|
||||
apndOpen, /* xOpen */
|
||||
apndDelete, /* xDelete */
|
||||
apndAccess, /* xAccess */
|
||||
apndFullPathname, /* xFullPathname */
|
||||
apndDlOpen, /* xDlOpen */
|
||||
apndDlError, /* xDlError */
|
||||
apndDlSym, /* xDlSym */
|
||||
apndDlClose, /* xDlClose */
|
||||
apndRandomness, /* xRandomness */
|
||||
apndSleep, /* xSleep */
|
||||
apndCurrentTime, /* xCurrentTime */
|
||||
apndGetLastError, /* xGetLastError */
|
||||
apndCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
apndSetSystemCall, /* xSetSystemCall */
|
||||
apndGetSystemCall, /* xGetSystemCall */
|
||||
apndNextSystemCall /* xNextSystemCall */
|
||||
};
|
||||
|
||||
static const sqlite3_io_methods apnd_io_methods = {
|
||||
3, /* iVersion */
|
||||
apndClose, /* xClose */
|
||||
apndRead, /* xRead */
|
||||
apndWrite, /* xWrite */
|
||||
apndTruncate, /* xTruncate */
|
||||
apndSync, /* xSync */
|
||||
apndFileSize, /* xFileSize */
|
||||
apndLock, /* xLock */
|
||||
apndUnlock, /* xUnlock */
|
||||
apndCheckReservedLock, /* xCheckReservedLock */
|
||||
apndFileControl, /* xFileControl */
|
||||
apndSectorSize, /* xSectorSize */
|
||||
apndDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
apndShmMap, /* xShmMap */
|
||||
apndShmLock, /* xShmLock */
|
||||
apndShmBarrier, /* xShmBarrier */
|
||||
apndShmUnmap, /* xShmUnmap */
|
||||
apndFetch, /* xFetch */
|
||||
apndUnfetch /* xUnfetch */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Close an apnd-file.
|
||||
*/
|
||||
static int apndClose(sqlite3_file *pFile){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xClose(pFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from an apnd-file.
|
||||
*/
|
||||
static int apndRead(
|
||||
sqlite3_file *pFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst+p->iPgOne);
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the append-mark onto the end of the file.
|
||||
*/
|
||||
static int apndWriteMark(ApndFile *p, sqlite3_file *pFile){
|
||||
int i;
|
||||
unsigned char a[APND_MARK_SIZE];
|
||||
memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ);
|
||||
for(i=0; i<8; i++){
|
||||
a[APND_MARK_PREFIX_SZ+i] = (p->iPgOne >> (56 - i*8)) & 0xff;
|
||||
}
|
||||
return pFile->pMethods->xWrite(pFile, a, APND_MARK_SIZE, p->iMark);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to an apnd-file.
|
||||
*/
|
||||
static int apndWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
int rc;
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
if( iOfst+iAmt>=APND_MAX_SIZE ) return SQLITE_FULL;
|
||||
rc = pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst+p->iPgOne);
|
||||
if( rc==SQLITE_OK && iOfst + iAmt + p->iPgOne > p->iMark ){
|
||||
sqlite3_int64 sz = 0;
|
||||
rc = pFile->pMethods->xFileSize(pFile, &sz);
|
||||
if( rc==SQLITE_OK ){
|
||||
p->iMark = sz - APND_MARK_SIZE;
|
||||
if( iOfst + iAmt + p->iPgOne > p->iMark ){
|
||||
p->iMark = p->iPgOne + iOfst + iAmt;
|
||||
rc = apndWriteMark(p, pFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate an apnd-file.
|
||||
*/
|
||||
static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
int rc;
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
rc = pFile->pMethods->xTruncate(pFile, size+p->iPgOne+APND_MARK_SIZE);
|
||||
if( rc==SQLITE_OK ){
|
||||
p->iMark = p->iPgOne+size;
|
||||
rc = apndWriteMark(p, pFile);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync an apnd-file.
|
||||
*/
|
||||
static int apndSync(sqlite3_file *pFile, int flags){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xSync(pFile, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current file-size of an apnd-file.
|
||||
*/
|
||||
static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
int rc;
|
||||
pFile = ORIGFILE(p);
|
||||
rc = pFile->pMethods->xFileSize(pFile, pSize);
|
||||
if( rc==SQLITE_OK && p->iPgOne ){
|
||||
*pSize -= p->iPgOne + APND_MARK_SIZE;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock an apnd-file.
|
||||
*/
|
||||
static int apndLock(sqlite3_file *pFile, int eLock){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xLock(pFile, eLock);
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock an apnd-file.
|
||||
*/
|
||||
static int apndUnlock(sqlite3_file *pFile, int eLock){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xUnlock(pFile, eLock);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if another file-handle holds a RESERVED lock on an apnd-file.
|
||||
*/
|
||||
static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** File control method. For custom operations on an apnd-file.
|
||||
*/
|
||||
static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
int rc;
|
||||
pFile = ORIGFILE(pFile);
|
||||
rc = pFile->pMethods->xFileControl(pFile, op, pArg);
|
||||
if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
|
||||
*(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", p->iPgOne, *(char**)pArg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector-size in bytes for an apnd-file.
|
||||
*/
|
||||
static int apndSectorSize(sqlite3_file *pFile){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xSectorSize(pFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the device characteristic flags supported by an apnd-file.
|
||||
*/
|
||||
static int apndDeviceCharacteristics(sqlite3_file *pFile){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xDeviceCharacteristics(pFile);
|
||||
}
|
||||
|
||||
/* Create a shared memory file mapping */
|
||||
static int apndShmMap(
|
||||
sqlite3_file *pFile,
|
||||
int iPg,
|
||||
int pgsz,
|
||||
int bExtend,
|
||||
void volatile **pp
|
||||
){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
|
||||
}
|
||||
|
||||
/* Perform locking on a shared-memory segment */
|
||||
static int apndShmLock(sqlite3_file *pFile, int offset, int n, int flags){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xShmLock(pFile,offset,n,flags);
|
||||
}
|
||||
|
||||
/* Memory barrier operation on shared memory */
|
||||
static void apndShmBarrier(sqlite3_file *pFile){
|
||||
pFile = ORIGFILE(pFile);
|
||||
pFile->pMethods->xShmBarrier(pFile);
|
||||
}
|
||||
|
||||
/* Unmap a shared memory segment */
|
||||
static int apndShmUnmap(sqlite3_file *pFile, int deleteFlag){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
|
||||
}
|
||||
|
||||
/* Fetch a page of a memory-mapped file */
|
||||
static int apndFetch(
|
||||
sqlite3_file *pFile,
|
||||
sqlite3_int64 iOfst,
|
||||
int iAmt,
|
||||
void **pp
|
||||
){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp);
|
||||
}
|
||||
|
||||
/* Release a memory-mapped page */
|
||||
static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the file is an ordinary SQLite database file.
|
||||
*/
|
||||
static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){
|
||||
int rc;
|
||||
char zHdr[16];
|
||||
static const char aSqliteHdr[] = "SQLite format 3";
|
||||
if( sz<512 ) return 0;
|
||||
rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0);
|
||||
if( rc ) return 0;
|
||||
return memcmp(zHdr, aSqliteHdr, sizeof(zHdr))==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to read the append-mark off the end of a file. Return the
|
||||
** start of the appended database if the append-mark is present. If
|
||||
** there is no append-mark, return -1;
|
||||
*/
|
||||
static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){
|
||||
int rc, i;
|
||||
sqlite3_int64 iMark;
|
||||
unsigned char a[APND_MARK_SIZE];
|
||||
|
||||
if( sz<=APND_MARK_SIZE ) return -1;
|
||||
rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE);
|
||||
if( rc ) return -1;
|
||||
if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1;
|
||||
iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ]&0x7f))<<56;
|
||||
for(i=1; i<8; i++){
|
||||
iMark += (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<(56-8*i);
|
||||
}
|
||||
return iMark;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open an apnd file handle.
|
||||
*/
|
||||
static int apndOpen(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_file *pFile,
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
ApndFile *p;
|
||||
sqlite3_file *pSubFile;
|
||||
sqlite3_vfs *pSubVfs;
|
||||
int rc;
|
||||
sqlite3_int64 sz;
|
||||
pSubVfs = ORIGVFS(pVfs);
|
||||
if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
|
||||
return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
|
||||
}
|
||||
p = (ApndFile*)pFile;
|
||||
memset(p, 0, sizeof(*p));
|
||||
pSubFile = ORIGFILE(pFile);
|
||||
p->base.pMethods = &apnd_io_methods;
|
||||
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
|
||||
if( rc ) goto apnd_open_done;
|
||||
rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
|
||||
if( rc ){
|
||||
pSubFile->pMethods->xClose(pSubFile);
|
||||
goto apnd_open_done;
|
||||
}
|
||||
if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){
|
||||
memmove(pFile, pSubFile, pSubVfs->szOsFile);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
p->iMark = 0;
|
||||
p->iPgOne = apndReadMark(sz, pFile);
|
||||
if( p->iPgOne>0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( (flags & SQLITE_OPEN_CREATE)==0 ){
|
||||
pSubFile->pMethods->xClose(pSubFile);
|
||||
rc = SQLITE_CANTOPEN;
|
||||
}
|
||||
p->iPgOne = (sz+0xfff) & ~(sqlite3_int64)0xfff;
|
||||
apnd_open_done:
|
||||
if( rc ) pFile->pMethods = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** All other VFS methods are pass-thrus.
|
||||
*/
|
||||
static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
|
||||
}
|
||||
static int apndAccess(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int flags,
|
||||
int *pResOut
|
||||
){
|
||||
return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
|
||||
}
|
||||
static int apndFullPathname(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int nOut,
|
||||
char *zOut
|
||||
){
|
||||
return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
|
||||
}
|
||||
static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
||||
return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
|
||||
}
|
||||
static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
||||
ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
|
||||
}
|
||||
static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
|
||||
return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
|
||||
}
|
||||
static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
|
||||
}
|
||||
static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
|
||||
}
|
||||
static int apndSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
|
||||
}
|
||||
static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
|
||||
}
|
||||
static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){
|
||||
return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
|
||||
}
|
||||
static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
|
||||
return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
|
||||
}
|
||||
static int apndSetSystemCall(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_syscall_ptr pCall
|
||||
){
|
||||
return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
|
||||
}
|
||||
static sqlite3_syscall_ptr apndGetSystemCall(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName
|
||||
){
|
||||
return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
|
||||
}
|
||||
static const char *apndNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
|
||||
return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
/*
|
||||
** This routine is called when the extension is loaded.
|
||||
** Register the new VFS.
|
||||
*/
|
||||
int sqlite3_appendvfs_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_vfs *pOrig;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
pOrig = sqlite3_vfs_find(0);
|
||||
apnd_vfs.iVersion = pOrig->iVersion;
|
||||
apnd_vfs.pAppData = pOrig;
|
||||
apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile);
|
||||
rc = sqlite3_vfs_register(&apnd_vfs, 0);
|
||||
#ifdef APPENDVFS_TEST
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister);
|
||||
}
|
||||
#endif
|
||||
if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
|
||||
return rc;
|
||||
}
|
||||
@@ -27,6 +27,21 @@ SQLITE_EXTENSION_INIT1
|
||||
** seven bits per integer stored in the lower seven bits of each byte.
|
||||
** More significant bits occur first. The most significant bit (0x80)
|
||||
** is a flag to indicate the end of the integer.
|
||||
**
|
||||
** This function, SQLAR, and ZIP all use the same "deflate" compression
|
||||
** algorithm, but each is subtly different:
|
||||
**
|
||||
** * ZIP uses raw deflate.
|
||||
**
|
||||
** * SQLAR uses the "zlib format" which is raw deflate with a two-byte
|
||||
** algorithm-identification header and a four-byte checksum at the end.
|
||||
**
|
||||
** * This utility uses the "zlib format" like SQLAR, but adds the variable-
|
||||
** length integer uncompressed size value at the beginning.
|
||||
**
|
||||
** This function might be extended in the future to support compression
|
||||
** formats other than deflate, by providing a different algorithm-id
|
||||
** mark following the variable-length integer size parameter.
|
||||
*/
|
||||
static void compressFunc(
|
||||
sqlite3_context *context,
|
||||
|
||||
+707
-35
@@ -11,11 +11,120 @@
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements SQL functions readfile() and
|
||||
** writefile().
|
||||
** writefile(), and eponymous virtual type "fsdir".
|
||||
**
|
||||
** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
|
||||
**
|
||||
** If neither of the optional arguments is present, then this UDF
|
||||
** function writes blob DATA to file FILE. If successful, the number
|
||||
** of bytes written is returned. If an error occurs, NULL is returned.
|
||||
**
|
||||
** If the first option argument - MODE - is present, then it must
|
||||
** be passed an integer value that corresponds to a POSIX mode
|
||||
** value (file type + permissions, as returned in the stat.st_mode
|
||||
** field by the stat() system call). Three types of files may
|
||||
** be written/created:
|
||||
**
|
||||
** regular files: (mode & 0170000)==0100000
|
||||
** symbolic links: (mode & 0170000)==0120000
|
||||
** directories: (mode & 0170000)==0040000
|
||||
**
|
||||
** For a directory, the DATA is ignored. For a symbolic link, it is
|
||||
** interpreted as text and used as the target of the link. For a
|
||||
** regular file, it is interpreted as a blob and written into the
|
||||
** named file. Regardless of the type of file, its permissions are
|
||||
** set to (mode & 0777) before returning.
|
||||
**
|
||||
** If the optional MTIME argument is present, then it is interpreted
|
||||
** as an integer - the number of seconds since the unix epoch. The
|
||||
** modification-time of the target file is set to this value before
|
||||
** returning.
|
||||
**
|
||||
** If three or more arguments are passed to this function and an
|
||||
** error is encountered, an exception is raised.
|
||||
**
|
||||
** READFILE(FILE):
|
||||
**
|
||||
** Read and return the contents of file FILE (type blob) from disk.
|
||||
**
|
||||
** FSDIR:
|
||||
**
|
||||
** Used as follows:
|
||||
**
|
||||
** SELECT * FROM fsdir($path [, $dir]);
|
||||
**
|
||||
** Parameter $path is an absolute or relative pathname. If the file that it
|
||||
** refers to does not exist, it is an error. If the path refers to a regular
|
||||
** file or symbolic link, it returns a single row. Or, if the path refers
|
||||
** to a directory, it returns one row for the directory, and one row for each
|
||||
** file within the hierarchy rooted at $path.
|
||||
**
|
||||
** Each row has the following columns:
|
||||
**
|
||||
** name: Path to file or directory (text value).
|
||||
** mode: Value of stat.st_mode for directory entry (an integer).
|
||||
** mtime: Value of stat.st_mtime for directory entry (an integer).
|
||||
** data: For a regular file, a blob containing the file data. For a
|
||||
** symlink, a text value containing the text of the link. For a
|
||||
** directory, NULL.
|
||||
**
|
||||
** If a non-NULL value is specified for the optional $dir parameter and
|
||||
** $path is a relative path, then $path is interpreted relative to $dir.
|
||||
** And the paths returned in the "name" column of the table are also
|
||||
** relative to directory $dir.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <utime.h>
|
||||
#else
|
||||
# include "windows.h"
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
# include "test_windirent.h"
|
||||
# define dirent DIRENT
|
||||
# define timespec TIMESPEC
|
||||
# define stat _stat
|
||||
# define mkdir(path,mode) _mkdir(path)
|
||||
# define lstat(path,buf) _stat(path,buf)
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
|
||||
|
||||
/*
|
||||
** Set the result stored by context ctx to a blob containing the
|
||||
** contents of file zName.
|
||||
*/
|
||||
static void readFileContents(sqlite3_context *ctx, const char *zName){
|
||||
FILE *in;
|
||||
long nIn;
|
||||
void *pBuf;
|
||||
|
||||
in = fopen(zName, "rb");
|
||||
if( in==0 ) return;
|
||||
fseek(in, 0, SEEK_END);
|
||||
nIn = ftell(in);
|
||||
rewind(in);
|
||||
pBuf = sqlite3_malloc( nIn );
|
||||
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
|
||||
sqlite3_result_blob(ctx, pBuf, nIn, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_free(pBuf);
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "readfile(X)" SQL function. The entire content
|
||||
@@ -28,58 +137,618 @@ static void readfileFunc(
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zName;
|
||||
FILE *in;
|
||||
long nIn;
|
||||
void *pBuf;
|
||||
|
||||
(void)(argc); /* Unused parameter */
|
||||
zName = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zName==0 ) return;
|
||||
in = fopen(zName, "rb");
|
||||
if( in==0 ) return;
|
||||
fseek(in, 0, SEEK_END);
|
||||
nIn = ftell(in);
|
||||
rewind(in);
|
||||
pBuf = sqlite3_malloc( nIn );
|
||||
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
|
||||
sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_free(pBuf);
|
||||
}
|
||||
fclose(in);
|
||||
readFileContents(context, zName);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "writefile(X,Y)" SQL function. The argument Y
|
||||
** is written into file X. The number of bytes written is returned. Or
|
||||
** NULL is returned if something goes wrong, such as being unable to open
|
||||
** file X for writing.
|
||||
** Set the error message contained in context ctx to the results of
|
||||
** vprintf(zFmt, ...).
|
||||
*/
|
||||
static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
|
||||
char *zMsg = 0;
|
||||
va_list ap;
|
||||
va_start(ap, zFmt);
|
||||
zMsg = sqlite3_vmprintf(zFmt, ap);
|
||||
sqlite3_result_error(ctx, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument zFile is the name of a file that will be created and/or written
|
||||
** by SQL function writefile(). This function ensures that the directory
|
||||
** zFile will be written to exists, creating it if required. The permissions
|
||||
** for any path components created by this function are set to (mode&0777).
|
||||
**
|
||||
** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
|
||||
** SQLITE_OK is returned if the directory is successfully created, or
|
||||
** SQLITE_ERROR otherwise.
|
||||
*/
|
||||
static int makeDirectory(
|
||||
const char *zFile,
|
||||
mode_t mode
|
||||
){
|
||||
char *zCopy = sqlite3_mprintf("%s", zFile);
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( zCopy==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
int nCopy = (int)strlen(zCopy);
|
||||
int i = 1;
|
||||
|
||||
while( rc==SQLITE_OK ){
|
||||
struct stat sStat;
|
||||
int rc2;
|
||||
|
||||
for(; zCopy[i]!='/' && i<nCopy; i++);
|
||||
if( i==nCopy ) break;
|
||||
zCopy[i] = '\0';
|
||||
|
||||
rc2 = stat(zCopy, &sStat);
|
||||
if( rc2!=0 ){
|
||||
if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR;
|
||||
}else{
|
||||
if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
|
||||
}
|
||||
zCopy[i] = '/';
|
||||
i++;
|
||||
}
|
||||
|
||||
sqlite3_free(zCopy);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function does the work for the writefile() UDF. Refer to
|
||||
** header comments at the top of this file for details.
|
||||
*/
|
||||
static int writeFile(
|
||||
sqlite3_context *pCtx, /* Context to return bytes written in */
|
||||
const char *zFile, /* File to write */
|
||||
sqlite3_value *pData, /* Data to write */
|
||||
mode_t mode, /* MODE parameter passed to writefile() */
|
||||
sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */
|
||||
){
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
if( S_ISLNK(mode) ){
|
||||
const char *zTo = (const char*)sqlite3_value_text(pData);
|
||||
if( symlink(zTo, zFile)<0 ) return 1;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
if( S_ISDIR(mode) ){
|
||||
if( mkdir(zFile, mode) ){
|
||||
/* The mkdir() call to create the directory failed. This might not
|
||||
** be an error though - if there is already a directory at the same
|
||||
** path and either the permissions already match or can be changed
|
||||
** to do so using chmod(), it is not an error. */
|
||||
struct stat sStat;
|
||||
if( errno!=EEXIST
|
||||
|| 0!=stat(zFile, &sStat)
|
||||
|| !S_ISDIR(sStat.st_mode)
|
||||
|| ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3_int64 nWrite = 0;
|
||||
const char *z;
|
||||
int rc = 0;
|
||||
FILE *out = fopen(zFile, "wb");
|
||||
if( out==0 ) return 1;
|
||||
z = (const char*)sqlite3_value_blob(pData);
|
||||
if( z ){
|
||||
sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
|
||||
nWrite = sqlite3_value_bytes(pData);
|
||||
if( nWrite!=n ){
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
if( rc==0 && mode && chmod(zFile, mode & 0777) ){
|
||||
rc = 1;
|
||||
}
|
||||
if( rc ) return 2;
|
||||
sqlite3_result_int64(pCtx, nWrite);
|
||||
}
|
||||
}
|
||||
|
||||
if( mtime>=0 ){
|
||||
#if defined(_WIN32)
|
||||
/* Windows */
|
||||
FILETIME lastAccess;
|
||||
FILETIME lastWrite;
|
||||
SYSTEMTIME currentTime;
|
||||
LONGLONG intervals;
|
||||
HANDLE hFile;
|
||||
GetSystemTime(¤tTime);
|
||||
SystemTimeToFileTime(¤tTime, &lastAccess);
|
||||
intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
|
||||
lastWrite.dwLowDateTime = (DWORD)intervals;
|
||||
lastWrite.dwHighDateTime = intervals >> 32;
|
||||
hFile = CreateFile(
|
||||
zFile, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS, NULL
|
||||
);
|
||||
if( hFile!=INVALID_HANDLE_VALUE ){
|
||||
BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
|
||||
CloseHandle(hFile);
|
||||
return !bResult;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
#elif defined(AT_FDCWD)
|
||||
/* Recent unix */
|
||||
struct timespec times[2];
|
||||
times[0].tv_nsec = times[1].tv_nsec = 0;
|
||||
times[0].tv_sec = time(0);
|
||||
times[1].tv_sec = mtime;
|
||||
if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
/* Legacy unix */
|
||||
struct timeval times[2];
|
||||
times[0].tv_usec = times[1].tv_usec = 0;
|
||||
times[0].tv_sec = time(0);
|
||||
times[1].tv_sec = mtime;
|
||||
if( utimes(zFile, times) ){
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
|
||||
** Refer to header comments at the top of this file for details.
|
||||
*/
|
||||
static void writefileFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
FILE *out;
|
||||
const char *z;
|
||||
sqlite3_int64 rc;
|
||||
const char *zFile;
|
||||
mode_t mode = 0;
|
||||
int res;
|
||||
sqlite3_int64 mtime = -1;
|
||||
|
||||
if( argc<2 || argc>4 ){
|
||||
sqlite3_result_error(context,
|
||||
"wrong number of arguments to function writefile()", -1
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
(void)(argc); /* Unused parameter */
|
||||
zFile = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zFile==0 ) return;
|
||||
out = fopen(zFile, "wb");
|
||||
if( out==0 ) return;
|
||||
z = (const char*)sqlite3_value_blob(argv[1]);
|
||||
if( z==0 ){
|
||||
rc = 0;
|
||||
}else{
|
||||
rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
|
||||
if( argc>=3 ){
|
||||
mode = (mode_t)sqlite3_value_int(argv[2]);
|
||||
}
|
||||
if( argc==4 ){
|
||||
mtime = sqlite3_value_int64(argv[3]);
|
||||
}
|
||||
|
||||
res = writeFile(context, zFile, argv[1], mode, mtime);
|
||||
if( res==1 && errno==ENOENT ){
|
||||
if( makeDirectory(zFile, mode)==SQLITE_OK ){
|
||||
res = writeFile(context, zFile, argv[1], mode, mtime);
|
||||
}
|
||||
}
|
||||
|
||||
if( argc>2 && res!=0 ){
|
||||
if( S_ISLNK(mode) ){
|
||||
ctxErrorMsg(context, "failed to create symlink: %s", zFile);
|
||||
}else if( S_ISDIR(mode) ){
|
||||
ctxErrorMsg(context, "failed to create directory: %s", zFile);
|
||||
}else{
|
||||
ctxErrorMsg(context, "failed to write file: %s", zFile);
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
sqlite3_result_int64(context, rc);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Cursor type for recursively iterating through a directory structure.
|
||||
*/
|
||||
typedef struct fsdir_cursor fsdir_cursor;
|
||||
typedef struct FsdirLevel FsdirLevel;
|
||||
|
||||
struct FsdirLevel {
|
||||
DIR *pDir; /* From opendir() */
|
||||
char *zDir; /* Name of directory (nul-terminated) */
|
||||
};
|
||||
|
||||
struct fsdir_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
|
||||
int nLvl; /* Number of entries in aLvl[] array */
|
||||
int iLvl; /* Index of current entry */
|
||||
FsdirLevel *aLvl; /* Hierarchy of directories being traversed */
|
||||
|
||||
const char *zBase;
|
||||
int nBase;
|
||||
|
||||
struct stat sStat; /* Current lstat() results */
|
||||
char *zPath; /* Path to current entry */
|
||||
sqlite3_int64 iRowid; /* Current rowid */
|
||||
};
|
||||
|
||||
typedef struct fsdir_tab fsdir_tab;
|
||||
struct fsdir_tab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
};
|
||||
|
||||
/*
|
||||
** Construct a new fsdir virtual table object.
|
||||
*/
|
||||
static int fsdirConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
fsdir_tab *pNew = 0;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for fsdir vtab objects.
|
||||
*/
|
||||
static int fsdirDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new fsdir_cursor object.
|
||||
*/
|
||||
static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
fsdir_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->iLvl = -1;
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset a cursor back to the state it was in when first returned
|
||||
** by fsdirOpen().
|
||||
*/
|
||||
static void fsdirResetCursor(fsdir_cursor *pCur){
|
||||
int i;
|
||||
for(i=0; i<=pCur->iLvl; i++){
|
||||
FsdirLevel *pLvl = &pCur->aLvl[i];
|
||||
if( pLvl->pDir ) closedir(pLvl->pDir);
|
||||
sqlite3_free(pLvl->zDir);
|
||||
}
|
||||
sqlite3_free(pCur->zPath);
|
||||
pCur->aLvl = 0;
|
||||
pCur->zPath = 0;
|
||||
pCur->zBase = 0;
|
||||
pCur->nBase = 0;
|
||||
pCur->iLvl = -1;
|
||||
pCur->iRowid = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for an fsdir_cursor.
|
||||
*/
|
||||
static int fsdirClose(sqlite3_vtab_cursor *cur){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
|
||||
fsdirResetCursor(pCur);
|
||||
sqlite3_free(pCur->aLvl);
|
||||
sqlite3_free(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the error message for the virtual table associated with cursor
|
||||
** pCur to the results of vprintf(zFmt, ...).
|
||||
*/
|
||||
static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
|
||||
va_list ap;
|
||||
va_start(ap, zFmt);
|
||||
pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance an fsdir_cursor to its next row of output.
|
||||
*/
|
||||
static int fsdirNext(sqlite3_vtab_cursor *cur){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
mode_t m = pCur->sStat.st_mode;
|
||||
|
||||
pCur->iRowid++;
|
||||
if( S_ISDIR(m) ){
|
||||
/* Descend into this directory */
|
||||
int iNew = pCur->iLvl + 1;
|
||||
FsdirLevel *pLvl;
|
||||
if( iNew>=pCur->nLvl ){
|
||||
int nNew = iNew+1;
|
||||
int nByte = nNew*sizeof(FsdirLevel);
|
||||
FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
|
||||
pCur->aLvl = aNew;
|
||||
pCur->nLvl = nNew;
|
||||
}
|
||||
pCur->iLvl = iNew;
|
||||
pLvl = &pCur->aLvl[iNew];
|
||||
|
||||
pLvl->zDir = pCur->zPath;
|
||||
pCur->zPath = 0;
|
||||
pLvl->pDir = opendir(pLvl->zDir);
|
||||
if( pLvl->pDir==0 ){
|
||||
fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
while( pCur->iLvl>=0 ){
|
||||
FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
|
||||
struct dirent *pEntry = readdir(pLvl->pDir);
|
||||
if( pEntry ){
|
||||
if( pEntry->d_name[0]=='.' ){
|
||||
if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
|
||||
if( pEntry->d_name[1]=='\0' ) continue;
|
||||
}
|
||||
sqlite3_free(pCur->zPath);
|
||||
pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
|
||||
if( pCur->zPath==0 ) return SQLITE_NOMEM;
|
||||
if( lstat(pCur->zPath, &pCur->sStat) ){
|
||||
fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
closedir(pLvl->pDir);
|
||||
sqlite3_free(pLvl->zDir);
|
||||
pLvl->pDir = 0;
|
||||
pLvl->zDir = 0;
|
||||
pCur->iLvl--;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
sqlite3_free(pCur->zPath);
|
||||
pCur->zPath = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the series_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int fsdirColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
switch( i ){
|
||||
case 0: { /* name */
|
||||
sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: /* mode */
|
||||
sqlite3_result_int64(ctx, pCur->sStat.st_mode);
|
||||
break;
|
||||
|
||||
case 2: /* mtime */
|
||||
sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
|
||||
break;
|
||||
|
||||
case 3: { /* data */
|
||||
mode_t m = pCur->sStat.st_mode;
|
||||
if( S_ISDIR(m) ){
|
||||
sqlite3_result_null(ctx);
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
}else if( S_ISLNK(m) ){
|
||||
char aStatic[64];
|
||||
char *aBuf = aStatic;
|
||||
int nBuf = 64;
|
||||
int n;
|
||||
|
||||
while( 1 ){
|
||||
n = readlink(pCur->zPath, aBuf, nBuf);
|
||||
if( n<nBuf ) break;
|
||||
if( aBuf!=aStatic ) sqlite3_free(aBuf);
|
||||
nBuf = nBuf*2;
|
||||
aBuf = sqlite3_malloc(nBuf);
|
||||
if( aBuf==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
|
||||
if( aBuf!=aStatic ) sqlite3_free(aBuf);
|
||||
#endif
|
||||
}else{
|
||||
readFileContents(ctx, pCur->zPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** first row returned is assigned rowid value 1, and each subsequent
|
||||
** row a value 1 more than that of the previous.
|
||||
*/
|
||||
static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int fsdirEof(sqlite3_vtab_cursor *cur){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
return (pCur->zPath==0);
|
||||
}
|
||||
|
||||
/*
|
||||
** xFilter callback.
|
||||
*/
|
||||
static int fsdirFilter(
|
||||
sqlite3_vtab_cursor *cur,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
const char *zDir = 0;
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
|
||||
fsdirResetCursor(pCur);
|
||||
|
||||
if( idxNum==0 ){
|
||||
fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
assert( argc==idxNum && (argc==1 || argc==2) );
|
||||
zDir = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zDir==0 ){
|
||||
fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if( argc==2 ){
|
||||
pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
|
||||
}
|
||||
if( pCur->zBase ){
|
||||
pCur->nBase = (int)strlen(pCur->zBase)+1;
|
||||
pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
|
||||
}else{
|
||||
pCur->zPath = sqlite3_mprintf("%s", zDir);
|
||||
}
|
||||
|
||||
if( pCur->zPath==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( lstat(pCur->zPath, &pCur->sStat) ){
|
||||
fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the generate_series virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
**
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** The query plan is represented by bits in idxNum:
|
||||
**
|
||||
** (1) start = $value -- constraint exists
|
||||
** (2) stop = $value -- constraint exists
|
||||
** (4) step = $value -- constraint exists
|
||||
** (8) output in descending order
|
||||
*/
|
||||
static int fsdirBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i; /* Loop over constraints */
|
||||
int idx4 = -1;
|
||||
int idx5 = -1;
|
||||
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
if( pConstraint->iColumn==4 ) idx4 = i;
|
||||
if( pConstraint->iColumn==5 ) idx5 = i;
|
||||
}
|
||||
|
||||
if( idx4<0 ){
|
||||
pIdxInfo->idxNum = 0;
|
||||
pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
|
||||
}else{
|
||||
pIdxInfo->aConstraintUsage[idx4].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idx4].argvIndex = 1;
|
||||
if( idx5>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idx5].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idx5].argvIndex = 2;
|
||||
pIdxInfo->idxNum = 2;
|
||||
pIdxInfo->estimatedCost = 10.0;
|
||||
}else{
|
||||
pIdxInfo->idxNum = 1;
|
||||
pIdxInfo->estimatedCost = 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register the "fsdir" virtual table.
|
||||
*/
|
||||
static int fsdirRegister(sqlite3 *db){
|
||||
static sqlite3_module fsdirModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
fsdirConnect, /* xConnect */
|
||||
fsdirBestIndex, /* xBestIndex */
|
||||
fsdirDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
fsdirOpen, /* xOpen - open a cursor */
|
||||
fsdirClose, /* xClose - close a cursor */
|
||||
fsdirFilter, /* xFilter - configure scan constraints */
|
||||
fsdirNext, /* xNext - advance a cursor */
|
||||
fsdirEof, /* xEof - check for end of scan */
|
||||
fsdirColumn, /* xColumn - read data */
|
||||
fsdirRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
|
||||
int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
|
||||
return rc;
|
||||
}
|
||||
#else /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
# define fsdirRegister(x) SQLITE_OK
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
@@ -95,8 +764,11 @@ int sqlite3_fileio_init(
|
||||
rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
|
||||
readfileFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
|
||||
writefileFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fsdirRegister(db);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+122
-39
@@ -10,23 +10,33 @@
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This is an in-memory read-only VFS implementation. The application
|
||||
** supplies a block of memory which is the database file, and this VFS
|
||||
** uses that block of memory.
|
||||
** This is an in-memory VFS implementation. The application supplies
|
||||
** a chunk of memory to hold the database file.
|
||||
**
|
||||
** Because there is no place to store journals and no good way to lock
|
||||
** the "file", this VFS is read-only.
|
||||
** Because there is place to store a rollback or wal journal, the database
|
||||
** must use one of journal_mode=MEMORY or journal_mode=NONE.
|
||||
**
|
||||
** USAGE:
|
||||
**
|
||||
** sqlite3_open_v2("file:/whatever?ptr=0xf05538&sz=14336", &db,
|
||||
** SQLITE_OPEN_READONLY | SQLITE_OPEN_URI,
|
||||
** sqlite3_open_v2("file:/whatever?ptr=0xf05538&sz=14336&max=65536", &db,
|
||||
** SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI,
|
||||
** "memvfs");
|
||||
**
|
||||
** The ptr= and sz= query parameters are required or the open will fail.
|
||||
** The ptr= parameter gives the memory address of the buffer holding the
|
||||
** read-only database and sz= gives the size of the database. The parameter
|
||||
** values may be in hexadecimal or decimal. The filename is ignored.
|
||||
** These are the query parameters:
|
||||
**
|
||||
** ptr= The address of the memory buffer that holds the database.
|
||||
**
|
||||
** sz= The current size the database file
|
||||
**
|
||||
** maxsz= The maximum size of the database. In other words, the
|
||||
** amount of space allocated for the ptr= buffer.
|
||||
**
|
||||
** freeonclose= If true, then sqlite3_free() is called on the ptr=
|
||||
** value when the connection closes.
|
||||
**
|
||||
** The ptr= and sz= query parameters are required. If maxsz= is omitted,
|
||||
** then it defaults to the sz= value. Parameter values can be in either
|
||||
** decimal or hexadecimal. The filename in the URI is ignored.
|
||||
*/
|
||||
#include <sqlite3ext.h>
|
||||
SQLITE_EXTENSION_INIT1
|
||||
@@ -49,7 +59,9 @@ typedef struct MemFile MemFile;
|
||||
struct MemFile {
|
||||
sqlite3_file base; /* IO methods */
|
||||
sqlite3_int64 sz; /* Size of the file */
|
||||
sqlite3_int64 szMax; /* Space allocated to aData */
|
||||
unsigned char *aData; /* content of the file */
|
||||
int bFreeOnClose; /* Invoke sqlite3_free() on aData at close */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -144,6 +156,8 @@ static const sqlite3_io_methods mem_io_methods = {
|
||||
** to free.
|
||||
*/
|
||||
static int memClose(sqlite3_file *pFile){
|
||||
MemFile *p = (MemFile *)pFile;
|
||||
if( p->bFreeOnClose ) sqlite3_free(p->aData);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -170,21 +184,34 @@ static int memWrite(
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
return SQLITE_READONLY;
|
||||
MemFile *p = (MemFile *)pFile;
|
||||
if( iOfst+iAmt>p->sz ){
|
||||
if( iOfst+iAmt>p->szMax ) return SQLITE_FULL;
|
||||
if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
|
||||
p->sz = iOfst+iAmt;
|
||||
}
|
||||
memcpy(p->aData+iOfst, z, iAmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate an mem-file.
|
||||
*/
|
||||
static int memTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
return SQLITE_READONLY;
|
||||
MemFile *p = (MemFile *)pFile;
|
||||
if( size>p->sz ){
|
||||
if( size>p->szMax ) return SQLITE_FULL;
|
||||
memset(p->aData+p->sz, 0, size-p->sz);
|
||||
}
|
||||
p->sz = size;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync an mem-file.
|
||||
*/
|
||||
static int memSync(sqlite3_file *pFile, int flags){
|
||||
return SQLITE_READONLY;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -200,7 +227,7 @@ static int memFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
** Lock an mem-file.
|
||||
*/
|
||||
static int memLock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_READONLY;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -242,7 +269,10 @@ static int memSectorSize(sqlite3_file *pFile){
|
||||
** Return the device characteristic flags supported by an mem-file.
|
||||
*/
|
||||
static int memDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return SQLITE_IOCAP_IMMUTABLE;
|
||||
return SQLITE_IOCAP_ATOMIC |
|
||||
SQLITE_IOCAP_POWERSAFE_OVERWRITE |
|
||||
SQLITE_IOCAP_SAFE_APPEND |
|
||||
SQLITE_IOCAP_SEQUENTIAL;
|
||||
}
|
||||
|
||||
/* Create a shared memory file mapping */
|
||||
@@ -253,12 +283,12 @@ static int memShmMap(
|
||||
int bExtend,
|
||||
void volatile **pp
|
||||
){
|
||||
return SQLITE_READONLY;
|
||||
return SQLITE_IOERR_SHMMAP;
|
||||
}
|
||||
|
||||
/* Perform locking on a shared-memory segment */
|
||||
static int memShmLock(sqlite3_file *pFile, int offset, int n, int flags){
|
||||
return SQLITE_READONLY;
|
||||
return SQLITE_IOERR_SHMLOCK;
|
||||
}
|
||||
|
||||
/* Memory barrier operation on shared memory */
|
||||
@@ -305,6 +335,9 @@ static int memOpen(
|
||||
if( p->aData==0 ) return SQLITE_CANTOPEN;
|
||||
p->sz = sqlite3_uri_int64(zName,"sz",0);
|
||||
if( p->sz<0 ) return SQLITE_CANTOPEN;
|
||||
p->szMax = sqlite3_uri_int64(zName,"max",p->sz);
|
||||
if( p->szMax<p->sz ) return SQLITE_CANTOPEN;
|
||||
p->bFreeOnClose = sqlite3_uri_boolean(zName,"freeonclose",0);
|
||||
pFile->pMethods = &mem_io_methods;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -315,7 +348,7 @@ static int memOpen(
|
||||
** returning.
|
||||
*/
|
||||
static int memDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
return SQLITE_READONLY;
|
||||
return SQLITE_IOERR_DELETE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -328,14 +361,7 @@ static int memAccess(
|
||||
int flags,
|
||||
int *pResOut
|
||||
){
|
||||
/* The spec says there are three possible values for flags. But only
|
||||
** two of them are actually used */
|
||||
assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE );
|
||||
if( flags==SQLITE_ACCESS_READWRITE ){
|
||||
*pResOut = 0;
|
||||
}else{
|
||||
*pResOut = 1;
|
||||
}
|
||||
*pResOut = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -416,31 +442,43 @@ static int memCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
|
||||
|
||||
#ifdef MEMVFS_TEST
|
||||
/*
|
||||
** memload(FILENAME)
|
||||
** memvfs_from_file(FILENAME, MAXSIZE)
|
||||
**
|
||||
** This an SQL function used to help in testing the memvfs VFS. The
|
||||
** function reads the content of a file into memory and then returns
|
||||
** a string that gives the locate and size of the in-memory buffer.
|
||||
** a URI that can be handed to ATTACH to attach the memory buffer as
|
||||
** a database. Example:
|
||||
**
|
||||
** ATTACH memvfs_from_file('test.db',1048576) AS inmem;
|
||||
**
|
||||
** The optional MAXSIZE argument gives the size of the memory allocation
|
||||
** used to hold the database. If omitted, it defaults to the size of the
|
||||
** file on disk.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
static void memvfsMemloadFunc(
|
||||
static void memvfsFromFileFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char *p;
|
||||
sqlite3_int64 sz;
|
||||
sqlite3_int64 szMax;
|
||||
FILE *in;
|
||||
const char *zFilename = (const char*)sqlite3_value_text(argv[0]);
|
||||
char zReturn[100];
|
||||
char *zUri;
|
||||
|
||||
if( zFilename==0 ) return;
|
||||
in = fopen(zFilename, "rb");
|
||||
if( in==0 ) return;
|
||||
fseek(in, 0, SEEK_END);
|
||||
sz = ftell(in);
|
||||
szMax = sz = ftell(in);
|
||||
rewind(in);
|
||||
p = sqlite3_malloc( sz );
|
||||
if( argc>=2 ){
|
||||
szMax = sqlite3_value_int64(argv[1]);
|
||||
if( szMax<sz ) szMax = sz;
|
||||
}
|
||||
p = sqlite3_malloc64( szMax );
|
||||
if( p==0 ){
|
||||
fclose(in);
|
||||
sqlite3_result_error_nomem(context);
|
||||
@@ -448,18 +486,60 @@ static void memvfsMemloadFunc(
|
||||
}
|
||||
fread(p, sz, 1, in);
|
||||
fclose(in);
|
||||
sqlite3_snprintf(sizeof(zReturn),zReturn,"ptr=%lld&sz=%lld",
|
||||
(sqlite3_int64)p, sz);
|
||||
sqlite3_result_text(context, zReturn, -1, SQLITE_TRANSIENT);
|
||||
zUri = sqlite3_mprintf(
|
||||
"file:/mem?vfs=memvfs&ptr=%lld&sz=%lld&max=%lld&freeonclose=1",
|
||||
(sqlite3_int64)p, sz, szMax);
|
||||
sqlite3_result_text(context, zUri, -1, sqlite3_free);
|
||||
}
|
||||
#endif /* MEMVFS_TEST */
|
||||
|
||||
#ifdef MEMVFS_TEST
|
||||
/*
|
||||
** memvfs_to_file(SCHEMA, FILENAME)
|
||||
**
|
||||
** The schema identified by SCHEMA must be a memvfs database. Write
|
||||
** the content of this database into FILENAME.
|
||||
*/
|
||||
static void memvfsToFileFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
MemFile *p = 0;
|
||||
FILE *out;
|
||||
int rc;
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
sqlite3_vfs *pVfs = 0;
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
const char *zFilename = (const char*)sqlite3_value_text(argv[1]);
|
||||
|
||||
if( zFilename==0 ) return;
|
||||
out = fopen(zFilename, "wb");
|
||||
if( out==0 ) return;
|
||||
rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_VFS_POINTER, &pVfs);
|
||||
if( rc || pVfs==0 ) return;
|
||||
if( strcmp(pVfs->zName,"memvfs")!=0 ) return;
|
||||
rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
|
||||
if( rc ) return;
|
||||
fwrite(p->aData, 1, (size_t)p->sz, out);
|
||||
fclose(out);
|
||||
}
|
||||
#endif /* MEMVFS_TEST */
|
||||
|
||||
#ifdef MEMVFS_TEST
|
||||
/* Called for each new database connection */
|
||||
static int memvfsRegister(
|
||||
sqlite3 *db,
|
||||
const char **pzErrMsg,
|
||||
char **pzErrMsg,
|
||||
const struct sqlite3_api_routines *pThunk
|
||||
){
|
||||
return sqlite3_create_function(db, "memload", 1, SQLITE_UTF8, 0,
|
||||
memvfsMemloadFunc, 0, 0);
|
||||
sqlite3_create_function(db, "memvfs_from_file", 1, SQLITE_UTF8, 0,
|
||||
memvfsFromFileFunc, 0, 0);
|
||||
sqlite3_create_function(db, "memvfs_from_file", 2, SQLITE_UTF8, 0,
|
||||
memvfsFromFileFunc, 0, 0);
|
||||
sqlite3_create_function(db, "memvfs_to_file", 2, SQLITE_UTF8, 0,
|
||||
memvfsToFileFunc, 0, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* MEMVFS_TEST */
|
||||
|
||||
@@ -485,6 +565,9 @@ int sqlite3_memvfs_init(
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_auto_extension((void(*)(void))memvfsRegister);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = memvfsRegister(db, pzErrMsg, pApi);
|
||||
}
|
||||
#endif
|
||||
if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
|
||||
return rc;
|
||||
|
||||
@@ -0,0 +1,707 @@
|
||||
/*
|
||||
** 2018-01-08
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains code to implement the sqlite3_normalize() function.
|
||||
**
|
||||
** char *sqlite3_normalize(const char *zSql);
|
||||
**
|
||||
** This function takes an SQL string as input and returns a "normalized"
|
||||
** version of that string in memory obtained from sqlite3_malloc64(). The
|
||||
** caller is responsible for ensuring that the returned memory is freed.
|
||||
**
|
||||
** If a memory allocation error occurs, this routine returns NULL.
|
||||
**
|
||||
** The normalization consists of the following transformations:
|
||||
**
|
||||
** (1) Convert every literal (string, blob literal, numeric constant,
|
||||
** or "NULL" constant) into a ?
|
||||
**
|
||||
** (2) Remove all superfluous whitespace, including comments. Change
|
||||
** all required whitespace to a single space character.
|
||||
**
|
||||
** (3) Lowercase all ASCII characters.
|
||||
**
|
||||
** (4) If an IN or NOT IN operator is followed by a list of 1 or more
|
||||
** values, convert that list into "(?,?,?)".
|
||||
**
|
||||
** The purpose of normalization is two-fold:
|
||||
**
|
||||
** (1) Sanitize queries by removing potentially private or sensitive
|
||||
** information contained in literals.
|
||||
**
|
||||
** (2) Identify structurally identical queries by comparing their
|
||||
** normalized forms.
|
||||
**
|
||||
** Command-Line Utility
|
||||
** --------------------
|
||||
**
|
||||
** This file also contains code for a command-line utility that converts
|
||||
** SQL queries in text files into their normalized forms. To build the
|
||||
** command-line program, compile this file with -DSQLITE_NORMALIZE_CLI
|
||||
** and link it against the SQLite library.
|
||||
*/
|
||||
#include <sqlite3.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Implementation note:
|
||||
**
|
||||
** Much of the tokenizer logic is copied out of the tokenize.c source file
|
||||
** of SQLite. That logic could be simplified for this particular application,
|
||||
** but that would impose a risk of introducing subtle errors. It is best to
|
||||
** keep the code as close to the original as possible.
|
||||
**
|
||||
** The tokenize code is in sync with the SQLite core as of 2018-01-08.
|
||||
** Any future changes to the core tokenizer might require corresponding
|
||||
** adjustments to the tokenizer logic in this module.
|
||||
*/
|
||||
|
||||
|
||||
/* Character classes for tokenizing
|
||||
**
|
||||
** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented
|
||||
** using a lookup table, whereas a switch() directly on c uses a binary search.
|
||||
** The lookup table is much faster. To maximize speed, and to ensure that
|
||||
** a lookup table is used, all of the classes need to be small integers and
|
||||
** all of them need to be used within the switch.
|
||||
*/
|
||||
#define CC_X 0 /* The letter 'x', or start of BLOB literal */
|
||||
#define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */
|
||||
#define CC_ID 2 /* unicode characters usable in IDs */
|
||||
#define CC_DIGIT 3 /* Digits */
|
||||
#define CC_DOLLAR 4 /* '$' */
|
||||
#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */
|
||||
#define CC_VARNUM 6 /* '?'. Numeric SQL variables */
|
||||
#define CC_SPACE 7 /* Space characters */
|
||||
#define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */
|
||||
#define CC_QUOTE2 9 /* '['. [...] style quoted ids */
|
||||
#define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */
|
||||
#define CC_MINUS 11 /* '-'. Minus or SQL-style comment */
|
||||
#define CC_LT 12 /* '<'. Part of < or <= or <> */
|
||||
#define CC_GT 13 /* '>'. Part of > or >= */
|
||||
#define CC_EQ 14 /* '='. Part of = or == */
|
||||
#define CC_BANG 15 /* '!'. Part of != */
|
||||
#define CC_SLASH 16 /* '/'. / or c-style comment */
|
||||
#define CC_LP 17 /* '(' */
|
||||
#define CC_RP 18 /* ')' */
|
||||
#define CC_SEMI 19 /* ';' */
|
||||
#define CC_PLUS 20 /* '+' */
|
||||
#define CC_STAR 21 /* '*' */
|
||||
#define CC_PERCENT 22 /* '%' */
|
||||
#define CC_COMMA 23 /* ',' */
|
||||
#define CC_AND 24 /* '&' */
|
||||
#define CC_TILDA 25 /* '~' */
|
||||
#define CC_DOT 26 /* '.' */
|
||||
#define CC_ILLEGAL 27 /* Illegal character */
|
||||
|
||||
static const unsigned char aiClass[] = {
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
|
||||
/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
|
||||
/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16,
|
||||
/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6,
|
||||
/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1,
|
||||
/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27,
|
||||
/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
|
||||
};
|
||||
|
||||
/* An array to map all upper-case characters into their corresponding
|
||||
** lower-case character.
|
||||
**
|
||||
** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
|
||||
** handle case conversions for the UTF character set since the tables
|
||||
** involved are nearly as big or bigger than SQLite itself.
|
||||
*/
|
||||
static const unsigned char sqlite3UpperToLower[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
|
||||
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
|
||||
122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
|
||||
108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
|
||||
126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
|
||||
162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
|
||||
180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
|
||||
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
|
||||
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
|
||||
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
|
||||
252,253,254,255
|
||||
};
|
||||
|
||||
/*
|
||||
** The following 256 byte lookup table is used to support SQLites built-in
|
||||
** equivalents to the following standard library functions:
|
||||
**
|
||||
** isspace() 0x01
|
||||
** isalpha() 0x02
|
||||
** isdigit() 0x04
|
||||
** isalnum() 0x06
|
||||
** isxdigit() 0x08
|
||||
** toupper() 0x20
|
||||
** SQLite identifier character 0x40
|
||||
** Quote character 0x80
|
||||
**
|
||||
** Bit 0x20 is set if the mapped character requires translation to upper
|
||||
** case. i.e. if the character is a lower-case ASCII character.
|
||||
** If x is a lower-case ASCII character, then its upper-case equivalent
|
||||
** is (x - 0x20). Therefore toupper() can be implemented as:
|
||||
**
|
||||
** (x & ~(map[x]&0x20))
|
||||
**
|
||||
** The equivalent of tolower() is implemented using the sqlite3UpperToLower[]
|
||||
** array. tolower() is used more often than toupper() by SQLite.
|
||||
**
|
||||
** Bit 0x40 is set if the character is non-alphanumeric and can be used in an
|
||||
** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any
|
||||
** non-ASCII UTF character. Hence the test for whether or not a character is
|
||||
** part of an identifier is 0x46.
|
||||
*/
|
||||
static const unsigned char sqlite3CtypeMap[256] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
|
||||
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
|
||||
0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
|
||||
0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
|
||||
|
||||
0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
|
||||
0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
|
||||
0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
|
||||
0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
|
||||
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */
|
||||
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
|
||||
};
|
||||
#define sqlite3Toupper(x) ((x)&~(sqlite3CtypeMap[(unsigned char)(x)]&0x20))
|
||||
#define sqlite3Isspace(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x01)
|
||||
#define sqlite3Isalnum(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x06)
|
||||
#define sqlite3Isalpha(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x02)
|
||||
#define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04)
|
||||
#define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
|
||||
#define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
|
||||
#define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
|
||||
|
||||
|
||||
/*
|
||||
** If X is a character that can be used in an identifier then
|
||||
** IdChar(X) will be true. Otherwise it is false.
|
||||
**
|
||||
** For ASCII, any character with the high-order bit set is
|
||||
** allowed in an identifier. For 7-bit characters,
|
||||
** sqlite3IsIdChar[X] must be 1.
|
||||
**
|
||||
** For EBCDIC, the rules are more complex but have the same
|
||||
** end result.
|
||||
**
|
||||
** Ticket #1066. the SQL standard does not allow '$' in the
|
||||
** middle of identifiers. But many SQL implementations do.
|
||||
** SQLite will allow '$' in identifiers for compatibility.
|
||||
** But the feature is undocumented.
|
||||
*/
|
||||
#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0)
|
||||
|
||||
/*
|
||||
** Ignore testcase() macros
|
||||
*/
|
||||
#define testcase(X)
|
||||
|
||||
/*
|
||||
** Token values
|
||||
*/
|
||||
#define TK_SPACE 0
|
||||
#define TK_NAME 1
|
||||
#define TK_LITERAL 2
|
||||
#define TK_PUNCT 3
|
||||
#define TK_ERROR 4
|
||||
|
||||
#define TK_MINUS TK_PUNCT
|
||||
#define TK_LP TK_PUNCT
|
||||
#define TK_RP TK_PUNCT
|
||||
#define TK_SEMI TK_PUNCT
|
||||
#define TK_PLUS TK_PUNCT
|
||||
#define TK_STAR TK_PUNCT
|
||||
#define TK_SLASH TK_PUNCT
|
||||
#define TK_REM TK_PUNCT
|
||||
#define TK_EQ TK_PUNCT
|
||||
#define TK_LE TK_PUNCT
|
||||
#define TK_NE TK_PUNCT
|
||||
#define TK_LSHIFT TK_PUNCT
|
||||
#define TK_LT TK_PUNCT
|
||||
#define TK_GE TK_PUNCT
|
||||
#define TK_RSHIFT TK_PUNCT
|
||||
#define TK_GT TK_PUNCT
|
||||
#define TK_GE TK_PUNCT
|
||||
#define TK_BITOR TK_PUNCT
|
||||
#define TK_CONCAT TK_PUNCT
|
||||
#define TK_COMMA TK_PUNCT
|
||||
#define TK_BITAND TK_PUNCT
|
||||
#define TK_BITNOT TK_PUNCT
|
||||
#define TK_STRING TK_LITERAL
|
||||
#define TK_ID TK_NAME
|
||||
#define TK_ILLEGAL TK_ERROR
|
||||
#define TK_DOT TK_PUNCT
|
||||
#define TK_INTEGER TK_LITERAL
|
||||
#define TK_FLOAT TK_LITERAL
|
||||
#define TK_VARIABLE TK_LITERAL
|
||||
#define TK_BLOB TK_LITERAL
|
||||
|
||||
/*
|
||||
** Return the length (in bytes) of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
*/
|
||||
static int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
int i, c;
|
||||
switch( aiClass[*z] ){ /* Switch on the character-class of the first byte
|
||||
** of the token. See the comment on the CC_ defines
|
||||
** above. */
|
||||
case CC_SPACE: {
|
||||
for(i=1; sqlite3Isspace(z[i]); i++){}
|
||||
*tokenType = TK_SPACE;
|
||||
return i;
|
||||
}
|
||||
case CC_MINUS: {
|
||||
if( z[1]=='-' ){
|
||||
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
|
||||
*tokenType = TK_SPACE;
|
||||
return i;
|
||||
}
|
||||
*tokenType = TK_MINUS;
|
||||
return 1;
|
||||
}
|
||||
case CC_LP: {
|
||||
*tokenType = TK_LP;
|
||||
return 1;
|
||||
}
|
||||
case CC_RP: {
|
||||
*tokenType = TK_RP;
|
||||
return 1;
|
||||
}
|
||||
case CC_SEMI: {
|
||||
*tokenType = TK_SEMI;
|
||||
return 1;
|
||||
}
|
||||
case CC_PLUS: {
|
||||
*tokenType = TK_PLUS;
|
||||
return 1;
|
||||
}
|
||||
case CC_STAR: {
|
||||
*tokenType = TK_STAR;
|
||||
return 1;
|
||||
}
|
||||
case CC_SLASH: {
|
||||
if( z[1]!='*' || z[2]==0 ){
|
||||
*tokenType = TK_SLASH;
|
||||
return 1;
|
||||
}
|
||||
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
|
||||
if( c ) i++;
|
||||
*tokenType = TK_SPACE;
|
||||
return i;
|
||||
}
|
||||
case CC_PERCENT: {
|
||||
*tokenType = TK_REM;
|
||||
return 1;
|
||||
}
|
||||
case CC_EQ: {
|
||||
*tokenType = TK_EQ;
|
||||
return 1 + (z[1]=='=');
|
||||
}
|
||||
case CC_LT: {
|
||||
if( (c=z[1])=='=' ){
|
||||
*tokenType = TK_LE;
|
||||
return 2;
|
||||
}else if( c=='>' ){
|
||||
*tokenType = TK_NE;
|
||||
return 2;
|
||||
}else if( c=='<' ){
|
||||
*tokenType = TK_LSHIFT;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_LT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case CC_GT: {
|
||||
if( (c=z[1])=='=' ){
|
||||
*tokenType = TK_GE;
|
||||
return 2;
|
||||
}else if( c=='>' ){
|
||||
*tokenType = TK_RSHIFT;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_GT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case CC_BANG: {
|
||||
if( z[1]!='=' ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return 1;
|
||||
}else{
|
||||
*tokenType = TK_NE;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case CC_PIPE: {
|
||||
if( z[1]!='|' ){
|
||||
*tokenType = TK_BITOR;
|
||||
return 1;
|
||||
}else{
|
||||
*tokenType = TK_CONCAT;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case CC_COMMA: {
|
||||
*tokenType = TK_COMMA;
|
||||
return 1;
|
||||
}
|
||||
case CC_AND: {
|
||||
*tokenType = TK_BITAND;
|
||||
return 1;
|
||||
}
|
||||
case CC_TILDA: {
|
||||
*tokenType = TK_BITNOT;
|
||||
return 1;
|
||||
}
|
||||
case CC_QUOTE: {
|
||||
int delim = z[0];
|
||||
testcase( delim=='`' );
|
||||
testcase( delim=='\'' );
|
||||
testcase( delim=='"' );
|
||||
for(i=1; (c=z[i])!=0; i++){
|
||||
if( c==delim ){
|
||||
if( z[i+1]==delim ){
|
||||
i++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( c=='\'' ){
|
||||
*tokenType = TK_STRING;
|
||||
return i+1;
|
||||
}else if( c!=0 ){
|
||||
*tokenType = TK_ID;
|
||||
return i+1;
|
||||
}else{
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
case CC_DOT: {
|
||||
if( !sqlite3Isdigit(z[1]) ){
|
||||
*tokenType = TK_DOT;
|
||||
return 1;
|
||||
}
|
||||
/* If the next character is a digit, this is a floating point
|
||||
** number that begins with ".". Fall thru into the next case */
|
||||
}
|
||||
case CC_DIGIT: {
|
||||
*tokenType = TK_INTEGER;
|
||||
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
|
||||
for(i=3; sqlite3Isxdigit(z[i]); i++){}
|
||||
return i;
|
||||
}
|
||||
for(i=0; sqlite3Isdigit(z[i]); i++){}
|
||||
if( z[i]=='.' ){
|
||||
i++;
|
||||
while( sqlite3Isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
if( (z[i]=='e' || z[i]=='E') &&
|
||||
( sqlite3Isdigit(z[i+1])
|
||||
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
|
||||
)
|
||||
){
|
||||
i += 2;
|
||||
while( sqlite3Isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
while( IdChar(z[i]) ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
case CC_QUOTE2: {
|
||||
for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
|
||||
*tokenType = c==']' ? TK_ID : TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
case CC_VARNUM: {
|
||||
*tokenType = TK_VARIABLE;
|
||||
for(i=1; sqlite3Isdigit(z[i]); i++){}
|
||||
return i;
|
||||
}
|
||||
case CC_DOLLAR:
|
||||
case CC_VARALPHA: {
|
||||
int n = 0;
|
||||
testcase( z[0]=='$' ); testcase( z[0]=='@' );
|
||||
testcase( z[0]==':' ); testcase( z[0]=='#' );
|
||||
*tokenType = TK_VARIABLE;
|
||||
for(i=1; (c=z[i])!=0; i++){
|
||||
if( IdChar(c) ){
|
||||
n++;
|
||||
}else if( c=='(' && n>0 ){
|
||||
do{
|
||||
i++;
|
||||
}while( (c=z[i])!=0 && !sqlite3Isspace(c) && c!=')' );
|
||||
if( c==')' ){
|
||||
i++;
|
||||
}else{
|
||||
*tokenType = TK_ILLEGAL;
|
||||
}
|
||||
break;
|
||||
}else if( c==':' && z[i+1]==':' ){
|
||||
i++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( n==0 ) *tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
case CC_KYWD: {
|
||||
for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
|
||||
if( IdChar(z[i]) ){
|
||||
/* This token started out using characters that can appear in keywords,
|
||||
** but z[i] is a character not allowed within keywords, so this must
|
||||
** be an identifier instead */
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
*tokenType = TK_ID;
|
||||
return i;
|
||||
}
|
||||
case CC_X: {
|
||||
testcase( z[0]=='x' ); testcase( z[0]=='X' );
|
||||
if( z[1]=='\'' ){
|
||||
*tokenType = TK_BLOB;
|
||||
for(i=2; sqlite3Isxdigit(z[i]); i++){}
|
||||
if( z[i]!='\'' || i%2 ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
while( z[i] && z[i]!='\'' ){ i++; }
|
||||
}
|
||||
if( z[i] ) i++;
|
||||
return i;
|
||||
}
|
||||
/* If it is not a BLOB literal, then it must be an ID, since no
|
||||
** SQL keywords start with the letter 'x'. Fall through */
|
||||
}
|
||||
case CC_ID: {
|
||||
i = 1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
while( IdChar(z[i]) ){ i++; }
|
||||
*tokenType = TK_ID;
|
||||
return i;
|
||||
}
|
||||
|
||||
char *sqlite3_normalize(const char *zSql){
|
||||
char *z; /* The output string */
|
||||
sqlite3_int64 nZ; /* Size of the output string in bytes */
|
||||
sqlite3_int64 nSql; /* Size of the input string in bytes */
|
||||
int i; /* Next character to read from zSql[] */
|
||||
int j; /* Next slot to fill in on z[] */
|
||||
int tokenType; /* Type of the next token */
|
||||
int n; /* Size of the next token */
|
||||
int k; /* Loop counter */
|
||||
|
||||
nSql = strlen(zSql);
|
||||
nZ = nSql;
|
||||
z = sqlite3_malloc64( nZ+2 );
|
||||
if( z==0 ) return 0;
|
||||
for(i=j=0; zSql[i]; i += n){
|
||||
n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType);
|
||||
switch( tokenType ){
|
||||
case TK_SPACE: {
|
||||
break;
|
||||
}
|
||||
case TK_ERROR: {
|
||||
sqlite3_free(z);
|
||||
return 0;
|
||||
}
|
||||
case TK_LITERAL: {
|
||||
z[j++] = '?';
|
||||
break;
|
||||
}
|
||||
case TK_PUNCT:
|
||||
case TK_NAME: {
|
||||
if( n==4 && sqlite3_strnicmp(zSql+i,"NULL",4)==0 ){
|
||||
if( (j>=3 && strncmp(z+j-2,"is",2)==0 && !IdChar(z[j-3]))
|
||||
|| (j>=4 && strncmp(z+j-3,"not",3)==0 && !IdChar(z[j-4]))
|
||||
){
|
||||
/* NULL is a keyword in this case, not a literal value */
|
||||
}else{
|
||||
/* Here the NULL is a literal value */
|
||||
z[j++] = '?';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>0 && IdChar(z[j-1]) && IdChar(zSql[i]) ) z[j++] = ' ';
|
||||
for(k=0; k<n; k++){
|
||||
z[j++] = sqlite3Tolower(zSql[i+k]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while( j>0 && z[j-1]==' ' ){ j--; }
|
||||
if( i>0 && z[j-1]!=';' ){ z[j++] = ';'; }
|
||||
z[j] = 0;
|
||||
|
||||
/* Make a second pass converting "in(...)" where the "..." is not a
|
||||
** SELECT statement into "in(?,?,?)" */
|
||||
for(i=0; i<j; i=n){
|
||||
char *zIn = strstr(z+i, "in(");
|
||||
int nParen;
|
||||
if( zIn==0 ) break;
|
||||
n = (int)(zIn-z)+3; /* Index of first char past "in(" */
|
||||
if( n && IdChar(zIn[-1]) ) continue;
|
||||
if( strncmp(zIn, "in(select",9)==0 && !IdChar(zIn[9]) ) continue;
|
||||
if( strncmp(zIn, "in(with",7)==0 && !IdChar(zIn[7]) ) continue;
|
||||
for(nParen=1, k=0; z[n+k]; k++){
|
||||
if( z[n+k]=='(' ) nParen++;
|
||||
if( z[n+k]==')' ){
|
||||
nParen--;
|
||||
if( nParen==0 ) break;
|
||||
}
|
||||
}
|
||||
/* k is the number of bytes in the "..." within "in(...)" */
|
||||
if( k<5 ){
|
||||
z = sqlite3_realloc64(z, j+(5-k)+1);
|
||||
if( z==0 ) return 0;
|
||||
memmove(z+n+5, z+n+k, j-(n+k));
|
||||
}else if( k>5 ){
|
||||
memmove(z+n+5, z+n+k, j-(n+k));
|
||||
}
|
||||
j = j-k+5;
|
||||
z[j] = 0;
|
||||
memcpy(z+n, "?,?,?", 5);
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
** For testing purposes, or to build a stand-alone SQL normalizer program,
|
||||
** compile this one source file with the -DSQLITE_NORMALIZE_CLI and link
|
||||
** it against any SQLite library. The resulting command-line program will
|
||||
** run sqlite3_normalize() over the text of all files named on the command-
|
||||
** line and show the result on standard output.
|
||||
*/
|
||||
#ifdef SQLITE_NORMALIZE_CLI
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** Break zIn up into separate SQL statements and run sqlite3_normalize()
|
||||
** on each one. Print the result of each run.
|
||||
*/
|
||||
static void normalizeFile(char *zIn){
|
||||
int i;
|
||||
if( zIn==0 ) return;
|
||||
for(i=0; zIn[i]; i++){
|
||||
char cSaved;
|
||||
if( zIn[i]!=';' ) continue;
|
||||
cSaved = zIn[i+1];
|
||||
zIn[i+1] = 0;
|
||||
if( sqlite3_complete(zIn) ){
|
||||
char *zOut = sqlite3_normalize(zIn);
|
||||
if( zOut ){
|
||||
printf("%s\n", zOut);
|
||||
sqlite3_free(zOut);
|
||||
}else{
|
||||
fprintf(stderr, "ERROR: %s\n", zIn);
|
||||
}
|
||||
zIn[i+1] = cSaved;
|
||||
zIn += i+1;
|
||||
i = -1;
|
||||
}else{
|
||||
zIn[i+1] = cSaved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The main routine for "sql_normalize". Read files named on the
|
||||
** command-line and run the text of each through sqlite3_normalize().
|
||||
*/
|
||||
int main(int argc, char **argv){
|
||||
int i;
|
||||
FILE *in;
|
||||
char *zBuf = 0;
|
||||
sqlite3_int64 sz, got;
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
in = fopen(argv[i], "rb");
|
||||
if( in==0 ){
|
||||
fprintf(stderr, "cannot open \"%s\"\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
fseek(in, 0, SEEK_END);
|
||||
sz = ftell(in);
|
||||
rewind(in);
|
||||
zBuf = sqlite3_realloc64(zBuf, sz+1);
|
||||
if( zBuf==0 ){
|
||||
fprintf(stderr, "failed to malloc for %lld bytes\n", sz);
|
||||
exit(1);
|
||||
}
|
||||
got = fread(zBuf, 1, sz, in);
|
||||
fclose(in);
|
||||
if( got!=sz ){
|
||||
fprintf(stderr, "only able to read %lld of %lld bytes from \"%s\"\n",
|
||||
got, sz, argv[i]);
|
||||
}else{
|
||||
zBuf[got] = 0;
|
||||
normalizeFile(zBuf);
|
||||
}
|
||||
}
|
||||
sqlite3_free(zBuf);
|
||||
}
|
||||
#endif /* SQLITE_NORMALIZE_CLI */
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
** 2017-12-17
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** Utility functions sqlar_compress() and sqlar_uncompress(). Useful
|
||||
** for working with sqlar archives and used by the shell tool's built-in
|
||||
** sqlar support.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <zlib.h>
|
||||
|
||||
/*
|
||||
** Implementation of the "sqlar_compress(X)" SQL function.
|
||||
**
|
||||
** If the type of X is SQLITE_BLOB, and compressing that blob using
|
||||
** zlib utility function compress() yields a smaller blob, return the
|
||||
** compressed blob. Otherwise, return a copy of X.
|
||||
**
|
||||
** SQLar uses the "zlib format" for compressed content. The zlib format
|
||||
** contains a two-byte identification header and a four-byte checksum at
|
||||
** the end. This is different from ZIP which uses the raw deflate format.
|
||||
**
|
||||
** Future enhancements to SQLar might add support for new compression formats.
|
||||
** If so, those new formats will be identified by alternative headers in the
|
||||
** compressed data.
|
||||
*/
|
||||
static void sqlarCompressFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==1 );
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
|
||||
const Bytef *pData = sqlite3_value_blob(argv[0]);
|
||||
uLong nData = sqlite3_value_bytes(argv[0]);
|
||||
uLongf nOut = compressBound(nData);
|
||||
Bytef *pOut;
|
||||
|
||||
pOut = (Bytef*)sqlite3_malloc(nOut);
|
||||
if( pOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
}else{
|
||||
if( Z_OK!=compress(pOut, &nOut, pData, nData) ){
|
||||
sqlite3_result_error(context, "error in compress()", -1);
|
||||
}else if( nOut<nData ){
|
||||
sqlite3_result_blob(context, pOut, nOut, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
sqlite3_result_value(context, argv[0]);
|
||||
}
|
||||
sqlite3_free(pOut);
|
||||
}
|
||||
}else{
|
||||
sqlite3_result_value(context, argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
|
||||
**
|
||||
** Parameter SZ is interpreted as an integer. If it is less than or
|
||||
** equal to zero, then this function returns a copy of X. Or, if
|
||||
** SZ is equal to the size of X when interpreted as a blob, also
|
||||
** return a copy of X. Otherwise, decompress blob X using zlib
|
||||
** utility function uncompress() and return the results (another
|
||||
** blob).
|
||||
*/
|
||||
static void sqlarUncompressFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
uLong nData;
|
||||
uLongf sz;
|
||||
|
||||
assert( argc==2 );
|
||||
sz = sqlite3_value_int(argv[1]);
|
||||
|
||||
if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
|
||||
sqlite3_result_value(context, argv[0]);
|
||||
}else{
|
||||
const Bytef *pData= sqlite3_value_blob(argv[0]);
|
||||
Bytef *pOut = sqlite3_malloc(sz);
|
||||
if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
|
||||
sqlite3_result_error(context, "error in uncompress()", -1);
|
||||
}else{
|
||||
sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
|
||||
}
|
||||
sqlite3_free(pOut);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_sqlar_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,
|
||||
sqlarCompressFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,
|
||||
sqlarUncompressFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -799,7 +799,7 @@ static void unionConfigureVtab(
|
||||
zVal = zOpt;
|
||||
if( *zVal==':' ) zVal++;
|
||||
while( union_isidchar(*zVal) ) zVal++;
|
||||
nOpt = zVal-zOpt;
|
||||
nOpt = (int)(zVal-zOpt);
|
||||
|
||||
while( union_isspace(*zVal) ) zVal++;
|
||||
if( *zVal=='=' ){
|
||||
|
||||
+1418
File diff suppressed because it is too large
Load Diff
@@ -361,6 +361,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/ieee754.c \
|
||||
$(TOP)/ext/misc/mmapwarm.c \
|
||||
$(TOP)/ext/misc/nextchar.c \
|
||||
$(TOP)/ext/misc/normalize.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
@@ -370,6 +371,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/unionvtab.c \
|
||||
$(TOP)/ext/misc/wholenumber.c \
|
||||
$(TOP)/ext/misc/vfslog.c \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
$(TOP)/ext/fts5/fts5_tcl.c \
|
||||
$(TOP)/ext/fts5/fts5_test_mi.c \
|
||||
$(TOP)/ext/fts5/fts5_test_tok.c
|
||||
@@ -486,7 +488,8 @@ TESTPROGS = \
|
||||
sqlite3_analyzer$(EXE) \
|
||||
sqlite3_checker$(EXE) \
|
||||
sqldiff$(EXE) \
|
||||
dbhash$(EXE)
|
||||
dbhash$(EXE) \
|
||||
sqltclsh$(EXE)
|
||||
|
||||
# Databases containing fuzzer test cases
|
||||
#
|
||||
@@ -510,6 +513,7 @@ SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
@@ -691,11 +695,15 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
|
||||
# Source files that go into making shell.c
|
||||
SHELL_SRC = \
|
||||
$(TOP)/src/shell.c.in \
|
||||
$(TOP)/ext/misc/appendvfs.c \
|
||||
$(TOP)/ext/misc/shathree.c \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/completion.c \
|
||||
$(TOP)/ext/misc/sqlar.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
$(TOP)/src/test_windirent.c
|
||||
|
||||
shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
|
||||
tclsh $(TOP)/tool/mkshellc.tcl >shell.c
|
||||
@@ -814,6 +822,12 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
|
||||
sqlite3_analyzer$(EXE): sqlite3_analyzer.c
|
||||
$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB)
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl
|
||||
tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh$(EXE): sqltclsh.c
|
||||
$(TCCX) $(TCL_FLAGS) sqltclsh.c -o $@ $(LIBTCL) $(THREADLIB)
|
||||
|
||||
sqlite3_expert$(EXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
|
||||
$(TCCX) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert$(EXE) $(THREADLIB)
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
C Stricter\stest\scases.
|
||||
D 2017-12-29T16:37:33.070
|
||||
F Makefile.in 804c347948b0ad5a962aea3e59413e897227e0173d0e76910f11f473e6c7ae9b
|
||||
C Test\scases\sfor\ssqlite3_normalize().
|
||||
D 2018-01-08T20:04:57.992
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 822052988bbf6204ca2c3e2665618b5a48acec24105d5afa8c4ebb59cb941d3e
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 57dcce0595d4a0c4b94b6f6ba732b8e33540358adf5fb8e1aa8389d34a9677e8
|
||||
F Makefile.msc 0f2875c7d4cb93ae4dab661f58f9d68699d323cfb87ebd7d8dccbb9949979b83
|
||||
F README.md eeae1e552f93ef72ef7c5b8f6647b368a001c28820ad1df179d3dae602bef681
|
||||
F VERSION 0c10cdfed866fdd2d80434f64f042c3330f1daaed12e54287beb104f04b3faaf
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -11,7 +13,7 @@ F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 66c0befa511f0d95ba229e180067cf0357a9ebf8b3201b06d683c5ba6220fb39
|
||||
F autoconf/Makefile.msc b88a70dee8453cc353e5d6df172d60a11a0af905710a24b1e6be80f8fea6e96b
|
||||
F autoconf/Makefile.msc 2c50a59319af7da4eaca8c13e3240881b1bc245fd175845a055faab7d03d6e67
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 8dd08ca564279fff091c9bfdd2599d8f992c9f1f70c5396de2126ad2bd1b3bed
|
||||
@@ -114,7 +116,7 @@ F ext/fts5/fts5_hash.c 32be400cf761868c9db33efe81a06eb19a17c5402ad477ee9efb51301
|
||||
F ext/fts5/fts5_index.c 5fe14375a29e8a7aa8f3e863babe180a19269206c254c8f47b216821d4ac1e15
|
||||
F ext/fts5/fts5_main.c 24868f88ab2a865defbba7a92eebeb726cc991eb092b71b5f5508f180c72605b
|
||||
F ext/fts5/fts5_storage.c fb5ef3c27073f67ade2e1bea08405f9e43f68f5f3676ed0ab7013bce5ba10be6
|
||||
F ext/fts5/fts5_tcl.c a7df39442ae674dde877cf06fe02ebb7658e69c179a4d223241c90df4f14b54e
|
||||
F ext/fts5/fts5_tcl.c b470467be4c5cab2d8b026992c05d86cd2293e7d8c4a10ba56d5f4f707981097
|
||||
F ext/fts5/fts5_test_mi.c 65864ba1e5c34a61d409c4c587e0bbe0466eb4f8f478d85dc42a92caad1338e6
|
||||
F ext/fts5/fts5_test_tok.c ffd657dd67e7fcdb31bf63fb60b6d867299a581d0f46e97086abacd66c2a9b26
|
||||
F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
|
||||
@@ -221,7 +223,7 @@ F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/lsm1/Makefile 98b0a24b45e248283d6bea4b6cb3e58d7b394edd8e96a0ac28c5fa5104813bad
|
||||
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
|
||||
F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86
|
||||
F ext/lsm1/lsm-test/lsmtest.h 5847594d4b43ec3412e1fd97104f7eb5fd770be55e691e6cb2e80929f86bebe3
|
||||
F ext/lsm1/lsm-test/lsmtest.h cf58528ffe0cfe535e91b44584e2ec5fb1caacdabecef0d8dcf83bf83168bf28
|
||||
F ext/lsm1/lsm-test/lsmtest1.c 33158978327f800e82b6a47c09b86ace809f56a9ff10b0162273ec1186cc3153
|
||||
F ext/lsm1/lsm-test/lsmtest2.c 188b09aec776516aeedcfd13b9c6faf85ba16b3671a0897a2c740ee00a5dc4f8
|
||||
F ext/lsm1/lsm-test/lsmtest3.c 9ab87528a36dbf4a61d7c8ad954f5ee368c0878c127b84b942b2e2abe522de26
|
||||
@@ -237,10 +239,10 @@ F ext/lsm1/lsm-test/lsmtest_func.c 159aa401bc8032bfa3d8cf2977bd687abebab88025589
|
||||
F ext/lsm1/lsm-test/lsmtest_io.c cf11b27b129c6bd5818fa1d440176502dc27229f0db892b4479118d61993ea20
|
||||
F ext/lsm1/lsm-test/lsmtest_main.c a9bc647738c0dcaebf205d6d194b3ce4a6ef3925801cd2d919f0a4ea33a15aeb
|
||||
F ext/lsm1/lsm-test/lsmtest_mem.c 4e63c764345ab1df59d4f13a77980c6f3643798210b10d6cdbd785b4b888fda5
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb.c 555fb101d2fe638abdd133e9294536c857fb38e0f227e049c00a67f51eaece06
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb.c 618a8619183fda4f5540fcde15f9068293c5e3180e1a246e34409b0c148758b3
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb.h 8733eee249b12956a9df8322994b43d19bd8c02ad2e8b0bb5164db4d6ccc1735
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb2.cc 99ea7f2dd9c7536c8fb9bdd329e4cfeb76899f3ddf6f48bdd3926e016922b715
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb3.c e44bf94e8bd724cd6ac161fd2cd44ffe43193932ad3a6bee1b07d80bb74012bb
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb3.c b4e46b1d2fec553fe4efb44e341b43abd20556fde610db0cfffdc2300b72defe
|
||||
F ext/lsm1/lsm-test/lsmtest_tdb4.c 47e8bb5eba266472d690fb8264f1855ebdba0ae5a0e541e35fcda61ebf1d277f
|
||||
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
|
||||
F ext/lsm1/lsm-test/lsmtest_win32.c 0e0a224674c4d3170631c41b026b56c7e1672b151f5261e1b4cc19068641da2d
|
||||
@@ -249,11 +251,11 @@ F ext/lsm1/lsmInt.h 5983690e05e83653cc01ba9d8fbf8455e534ddf8349ed9adedbf46a75497
|
||||
F ext/lsm1/lsm_ckpt.c 0eabfaf812ddb4ea43add38f05e430694cd054eb622c3e35af4c43118a2d5321
|
||||
F ext/lsm1/lsm_file.c 3c51841d5b3e7da162693cbac9a9f47eeedf6bcbbe2969a4d25e30c428c9fe36
|
||||
F ext/lsm1/lsm_log.c a8bf334532109bba05b09a504ee45fc393828b0d034ca61ab45e3940709d9a7c
|
||||
F ext/lsm1/lsm_main.c 801295038b548ae2e5fae93f08c3f945154f40848a03ff26b16eab5d04ba573a
|
||||
F ext/lsm1/lsm_main.c b5703f8042e71d3a2d65e671f6832e077e79e89e9975818f67f969922618db63
|
||||
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
|
||||
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
|
||||
F ext/lsm1/lsm_shared.c 76adfc1ed9ffebaf92746dde4b370ccc48143ca8b05b563816eadd2aadf1c525
|
||||
F ext/lsm1/lsm_sorted.c d07ff7c28758542b8b4da4b5a1fb67b22a4d33e50e7f684cffe1f6c45cf5182c
|
||||
F ext/lsm1/lsm_sorted.c df7b393d9e4b85e6ad07181c6434d58a69a9145ee925d89c3ee1d2a210adaf9a
|
||||
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
|
||||
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
|
||||
F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
|
||||
@@ -266,21 +268,23 @@ F ext/lsm1/tool/mklsm1c.tcl f31561bbee5349f0a554d1ad7236ac1991fc09176626f529f607
|
||||
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
|
||||
F ext/misc/amatch.c 6db4607cb17c54b853a2d7c7c36046d004853f65b9b733e6f019d543d5dfae87
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/appendvfs.c 4c65f0b79686ae5a483134233d7fd912f0f2d4fd76023404f96f2290fff13b19
|
||||
F ext/misc/btreeinfo.c d7fd9a2fe2fa33ba28488e2fce703ebecc759219ea9e0bb3b254784866c0a676
|
||||
F ext/misc/carray.c ed96c218ea940b85c9a274c4d9c59fe9491c299147a38a8bba537687bd6c6005
|
||||
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
|
||||
F ext/misc/completion.c 52c3f01523e3e387eb321b4739a89d1fe47cbe6025aa1f2d8d3685e9e365df0f
|
||||
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
|
||||
F ext/misc/compress.c dd4f8a6d0baccff3c694757db5b430f3bbd821d8686d1fc24df55cf9f035b189
|
||||
F ext/misc/csv.c 1a009b93650732e22334edc92459c4630b9fa703397cbb3c8ca279921a36ca11
|
||||
F ext/misc/dbdump.c 3509fa6b8932d04e932d6b6b827b6a82ca362781b8e8f3c77336f416793e215e
|
||||
F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c b1aa06c0f1dac277695d4529e5e976c65ab5678dcbb53a0304deaa8adc44b332
|
||||
F ext/misc/fileio.c 672e89e125846848e07e025cbe601dc370a93433d571d9422541a9cefbd12b76
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
|
||||
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
|
||||
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
|
||||
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/normalize.c 19262ef3ef29d4de2f281b423326865c8916c63d0cb09f1dc98d24d5c1e8ba64
|
||||
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
|
||||
F ext/misc/regexp.c a68d25c659bd2d893cd1215667bbf75ecb9dc7d4
|
||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||
@@ -291,14 +295,16 @@ F ext/misc/sha1.c 0b9e9b855354910d3ca467bf39099d570e73db56
|
||||
F ext/misc/shathree.c 9e960ba50483214c6a7a4b1517f8d8cef799e9db381195178c3fd3ad207e10c0
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 41cf26c6b89fcaa8798ae10ae64d39c1f1d9d6995152e545bd491c13058b8fac
|
||||
F ext/misc/sqlar.c 57d5bc45cd5492208e451f697404be88f8612527d64c9d42f96b325b64983d74
|
||||
F ext/misc/stmt.c 6f16443abb3551e3f5813bb13ba19a30e7032830015b0f92fe0c0453045c0a11
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/unionvtab.c de36c2c45583d68f99e45b392311967066b02e2651d05697da783698b245b387
|
||||
F ext/misc/unionvtab.c 2aa94902ea646e1aaf6c05eac944a14276cddd67735b2ad856030ffffbb6626c
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178
|
||||
F ext/misc/vtablog.c 31d0d8f4406795679dcd3a67917c213d3a2a5fb3ea5de35f6e773491ed7e13c9
|
||||
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/misc/zipfile.c 8075df9296beeebc344567927d114c6d3201110a29110013388d233fa7d4fb2c
|
||||
F ext/rbu/rbu.c ea7d1b7eb44c123a2a619332e19fe5313500705c4a58aaa1887905c0d83ffc2e
|
||||
F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842
|
||||
F ext/rbu/rbu10.test 1846519a438697f45e9dcb246908af81b551c29e1078d0304fae83f1fed7e9ee
|
||||
@@ -401,7 +407,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk b5f569262e4f8111bb8cf6110784b8210fe14ea45f6c7ea50fb4230ebe7a4880
|
||||
F main.mk c6b8ee2fa871e01ad6a460d750cd074010292464a60a37a2207930ae0df629dc
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -434,13 +440,13 @@ F src/delete.c 74667ad914ac143731a444a1bacf29ceb18f6eded8a0dd17aafae80baa07f8bb
|
||||
F src/expr.c ad6e7a9c34a4bab9d10cc857d647ae7ce370a633b5c0bfa71f1c29b81ae364b8
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
|
||||
F src/func.c 697a3ee3b8c8481db497226e9e71935727d6a9fb3d3cc049e82a1c717a0a8342
|
||||
F src/func.c bd528d5ed68ce5cbf78a762e3b735fa75009f7197ff07fab07fd771f35ebaa1b
|
||||
F src/global.c ac3094f1dc59fbeb919aef7cc0cc827a8459d1fb1adb7972ef75bd9e0c10b75b
|
||||
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c cb67cc56ef2ddd13e6944b2c0dd08a920bcd9503230adef8b9928d338097c722
|
||||
F src/insert.c 14686083cedc198540b15a79586cdd4be2acf6d5fa97627e355f817ab07e9fee
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 55bcc3c741059a1056859e8adaf133aa179e22be12215c0936b2f354ef71209b
|
||||
F src/main.c 690c4134f944cbd5b71d59dd6e61ce4131f6a50ab774f38108e57d07d79cf876
|
||||
@@ -465,7 +471,7 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c 7fc2735390a7809d5d893ed735d994ff12521224b89738226fff6f1a0aa1c932
|
||||
F src/os_win.c 0a4afa35cc8e812000df3ea2f64b476131b39e29e75d8007d0504726e4761de4
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
|
||||
F src/pager.c 9b9cb4e06c03d43d62480a7a685a012d645fcf3a39e7767ccb505fb41ee083ec
|
||||
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
|
||||
F src/parse.y 44cbbc3e132ea128258eff7be7f6d5c5dfa25522f89ec8b5501276966511bd50
|
||||
F src/pcache.c 7ae91a4557a43d77d449accbfdc68846e6516f8e2eda46e8bbe4536fb669b201
|
||||
@@ -479,8 +485,8 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 8b22abe193e4d8243befa2038e4ae2405802fed1c446e5e502d11f652e09ba74
|
||||
F src/shell.c.in f3ec8f90dd698ea98781a90642c91eacbc24f4e55bb551c7b2762000d3ef55dc
|
||||
F src/sqlite.h.in b4dc75265ed04b98e2184011a7dd0054ce2137ff84867a6be8b4f3bdfbc03d30
|
||||
F src/shell.c.in 0e20ac49a6c4458620084bf7715ad39cd9557d9116e447548d2282000e8ca361
|
||||
F src/sqlite.h.in 1f1a2da222ec57465794e8984d77f32d0bd0da80cdc136beadda461a0be9d80c
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
|
||||
F src/sqliteInt.h fd8702c65994d7de3e2d8f7d85d958731da1ed29476571fdfa2290fd8ec0bf80
|
||||
@@ -488,7 +494,7 @@ F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6
|
||||
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 1833388c01e3b77f4c712185ee7250b9423ee0981ce6ae7e401e47db0319a696
|
||||
F src/test1.c 8ef15f7a357f85dfc41c6c748ce9c947b4f676e01bb5ae6a45bee4923dff8b51
|
||||
F src/test1.c 1ab7cbbb6693e08364c1a9241e2aee17f8c4925e4cc52396be77ae6845a05828
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
@@ -536,8 +542,8 @@ F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb26
|
||||
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
|
||||
F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
|
||||
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_windirent.c 17f91f5f2aa1bb7328abb49414c363b5d2a9d3ff
|
||||
F src/test_windirent.h 5d67483a55442e31e1bde0f4a230e6e932ad5906
|
||||
F src/test_windirent.c a895e2c068a06644eef91a7f0a32182445a893b9a0f33d0cdb4283dca2486ac1
|
||||
F src/test_windirent.h 8782864172ba5ae52c5c313c70faeadb324ff74de9c3dcc6b56a557dccaa1de6
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
|
||||
@@ -547,7 +553,7 @@ F src/update.c 961bd1265d4d1e5cd65c9a54fa5122fb7aefcb003fcf2de0c092fceb7e58972c
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c 7315e97a8dc2c8e19ca64196c652cf0a65d13fd0a211b2cec082062372dc6261
|
||||
F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
|
||||
F src/vdbe.c cb3b5035f337c9fed4a0170ca20325dc4500b832c57d00561310cbb78149a73c
|
||||
F src/vdbe.c c70267613df80345ed9bbd9c249c365b53bb9cbbe9d3e78e6d5c049d00ef5501
|
||||
F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
|
||||
F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9
|
||||
F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1
|
||||
@@ -917,7 +923,7 @@ F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test d202a7606d23f90988a664e88e268aed1087c11c
|
||||
F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
|
||||
F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4
|
||||
F test/func6.test 1a2bc511fedb779e2bd3154361385216c6d35080f36bfe896b8cdd1b1954294a
|
||||
F test/func6.test a4281c8fcd42b56f7a60f28e8e4d444e8b2256f9e82658b7ab87699f8318f564
|
||||
F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa
|
||||
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
|
||||
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
@@ -969,7 +975,7 @@ F test/index7.test 7feababe16f2091b229c22aff2bcc1d4d6b9d2bb
|
||||
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
|
||||
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
|
||||
F test/indexedby.test faa585e315e868f09bce0eb39c41d6134649b13d2801638294d3ae616edf1609
|
||||
F test/indexexpr1.test 84100e880154a4b645db9f4fc7642756d9a2b6011b68f73c8efda4d244816de9
|
||||
F test/indexexpr1.test ace1ad489adc25325ad298434f13b1a515b36bf5dca9fe2a4b66cdf17aea3fa0
|
||||
F test/indexexpr2.test 13247bac49143196556eb3f65e97ef301bd3e993f4511558b5db322ddc370ea6
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
@@ -1087,6 +1093,7 @@ F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
|
||||
F test/nockpt.test 9a436a7213ba5ef7a32304998d386d3ea3f76c9d
|
||||
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
|
||||
F test/normalize.test 501630ab49b0b26b65c74124bf03e3374c1b57fa97aae750f84803609141d167
|
||||
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
|
||||
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
|
||||
@@ -1127,7 +1134,7 @@ F test/pragma.test 7c8cfc328a1717a95663cf8edb06c52ddfeaf97bb0aee69ae7457132e8d39
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
F test/pragma4.test 3046501bee2f652dc2a4f9c87781e2741361d6864439c8381aba6c3b774b335c
|
||||
F test/pragma5.test fd517f42ee847e126afbbbd9fd0fb9e5a4a61a962496a350adb8a22583fbdc37
|
||||
F test/pragma5.test 824ce6ced5d6b7ec71abe37fc6005ff836fe39d638273dc5192b39864b9ee983
|
||||
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
|
||||
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
|
||||
F test/printf2.test 9e6db85f81c63f2367c34a9d7db384088bd374ad
|
||||
@@ -1147,7 +1154,7 @@ F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
|
||||
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.tcl 0b0b3d926e36822ff63b405d683544ce1014303b029f2678bbcf40c162b5f246 x
|
||||
F test/releasetest.tcl 6aaa853f7a7bbdc458d4cb42c0425228729b0f3e5769e9b41088c08eee999a49 x
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/rollback.test f580934279800d480a19176c6b44909df31ce7ad45267ea475a541daa522f3d3
|
||||
F test/rollback2.test 8435d6ff0f13f51d2a4181c232e706005fa90fc5
|
||||
@@ -1213,13 +1220,14 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
|
||||
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test f78ea0e2637ae9f497cb41206f6346f983052ffc7a359e664aaf6847fc704ea7
|
||||
F test/shell1.test 6d69e08039aea13f2c42749f162fe05eab7b5c93729f31d49d7d27cf36226e5a
|
||||
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1
|
||||
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
|
||||
F test/shell5.test 23939a4c51f0421330ea61dbd3c74f9c215f5f8d3d1a94846da6ffc777a35458
|
||||
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
|
||||
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
|
||||
F test/shell8.test 7585847402452d594f0e5f93430d34ed63b2f34ca7e956f63db157f9327c6896
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
|
||||
@@ -1592,6 +1600,7 @@ F test/wordcount.c cb589cec469a1d90add05b1f8cee75c7210338d87a5afd65260ed5c0f4bbf
|
||||
F test/writecrash.test f1da7f7adfe8d7f09ea79b42e5ca6dcc41102f27f8e334ad71539501ddd910cc
|
||||
F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
|
||||
F test/zerodamage.test e59a56443d6298ecf7435f618f0b27654f0c849e
|
||||
F test/zipfile.test a1dd0429294cb9487900fc2b29aa9921329f20a7314aa0921b668246172ac090
|
||||
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
|
||||
F tool/GetTclKit.bat 8995df40c4209808b31f24de0b58f90930239a234f7591e3675d45bfbb990c5d
|
||||
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
|
||||
@@ -1624,7 +1633,7 @@ F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 4ee2a30ccbd900dc4d5cdb61bdab87cd2166cd2affcc78c9cc0b8d22a65b2eee
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd
|
||||
F tool/mkshellc.tcl 574307265b49d813301fba91ccd74e6a26d33f65f74b6891c320a0ffbee07895
|
||||
F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5
|
||||
F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
||||
@@ -1657,6 +1666,8 @@ F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
|
||||
F tool/split-sqlite3c.tcl 3efcd4240b738f6bb2b5af0aea7e1e0ef9bc1c61654f645076cec883030b710c
|
||||
F tool/sqldiff.c 30879bbc8de686df4624e86adce2d8981f500904c1cfb55b5d1eea2ffd9341eb
|
||||
F tool/sqlite3_analyzer.c.in 7eeaae8b0d7577662acaabbb11107af0659d1b41bc1dfdd4d91422de27127968
|
||||
F tool/sqltclsh.c.in 8b2529b6c3cdd8ad6aaff21e80eb58370c428cb207b4607d0da4def064dcec56
|
||||
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
|
||||
F tool/srcck1.c 371de5363b70154012955544f86fdee8f6e5326f
|
||||
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
|
||||
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
|
||||
@@ -1688,7 +1699,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 89e5720a8d8d46d4e2f16f15678e91336117e64abc977174e2b345a30308d0d2
|
||||
R 9cb794037b97521b258cb5fdbbf60d53
|
||||
P db5d138e97f22ad4d4d11dbef96df93696ba0e557809066bc263ca3c3898f349
|
||||
R 5585a6831c91176202d5e0f81c59c944
|
||||
U drh
|
||||
Z 8d1ee588df9bbfd069e3afd64819112f
|
||||
Z ca698384a23dd84f9bb875fa9da10ba1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
9406c0a685fd5ff3516a66402b0514a1440652822a5eecf0b7af85929f3079e8
|
||||
658f42257d56a3562dfa8e55023c6e497f55c565cd751d942de3a9e0cb2fa708
|
||||
+1
-2
@@ -1800,8 +1800,7 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY),
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
FUNCTION2(sqlite_unsupported_offset,
|
||||
1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
|
||||
FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
|
||||
SQLITE_FUNC_TYPEOF),
|
||||
#endif
|
||||
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
|
||||
|
||||
@@ -1571,6 +1571,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
|
||||
/* Check to see if the new index entry will be unique */
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
|
||||
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
||||
|
||||
@@ -1659,6 +1660,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
||||
}
|
||||
if( ipkTop ){
|
||||
|
||||
+1
-1
@@ -5579,7 +5579,7 @@ static int getPageMMap(
|
||||
}
|
||||
if( pPg==0 ){
|
||||
rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
|
||||
}else{
|
||||
}else{
|
||||
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
|
||||
}
|
||||
if( pPg ){
|
||||
|
||||
+1054
-96
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -6971,9 +6971,9 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
||||
** the xFileControl method. ^The return value of the xFileControl
|
||||
** method becomes the return value of this routine.
|
||||
**
|
||||
** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
|
||||
** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
|
||||
** a pointer to the underlying [sqlite3_file] object to be written into
|
||||
** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER
|
||||
** the space pointed to by the 4th parameter. ^The [SQLITE_FCNTL_FILE_POINTER]
|
||||
** case is a short-circuit path which does not actually invoke the
|
||||
** underlying sqlite3_io_methods.xFileControl method.
|
||||
**
|
||||
@@ -6985,7 +6985,7 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
||||
** an incorrect zDbName and an SQLITE_ERROR return from the underlying
|
||||
** xFileControl method.
|
||||
**
|
||||
** See also: [SQLITE_FCNTL_LOCKSTATE]
|
||||
** See also: [file control opcodes]
|
||||
*/
|
||||
int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
|
||||
|
||||
@@ -8301,7 +8301,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
|
||||
**
|
||||
** This function may only be called from within a call to the [xBestIndex]
|
||||
** method of a [virtual table implementation].
|
||||
** method of a [virtual table].
|
||||
**
|
||||
** The first argument must be the sqlite3_index_info object that is the
|
||||
** first parameter to the xBestIndex() method. The second argument must be
|
||||
|
||||
+36
@@ -4559,6 +4559,35 @@ static int SQLITE_TCLAPI test_complete16(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_normalize SQL
|
||||
**
|
||||
** Return the normalized value for an SQL statement.
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_normalize(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
char *zSql;
|
||||
char *zNorm;
|
||||
extern char *sqlite3_normalize(const char*);
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SQL");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
zSql = (char*)Tcl_GetString(objv[1]);
|
||||
zNorm = sqlite3_normalize(zSql);
|
||||
if( zNorm ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(zNorm, -1));
|
||||
sqlite3_free(zNorm);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_step STMT
|
||||
**
|
||||
@@ -6960,6 +6989,9 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
#ifdef SQLITE_HAVE_ZLIB
|
||||
extern int sqlite3_zipfile_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
#endif
|
||||
static const struct {
|
||||
const char *zExtName;
|
||||
int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
@@ -6981,6 +7013,9 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
{ "totype", sqlite3_totype_init },
|
||||
{ "unionvtab", sqlite3_unionvtab_init },
|
||||
{ "wholenumber", sqlite3_wholenumber_init },
|
||||
#ifdef SQLITE_HAVE_ZLIB
|
||||
{ "zipfile", sqlite3_zipfile_init },
|
||||
#endif
|
||||
};
|
||||
sqlite3 *db;
|
||||
const char *zName;
|
||||
@@ -7541,6 +7576,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_open16", test_open16 ,0 },
|
||||
{ "sqlite3_open_v2", test_open_v2 ,0 },
|
||||
{ "sqlite3_complete16", test_complete16 ,0 },
|
||||
{ "sqlite3_normalize", test_normalize ,0 },
|
||||
|
||||
{ "sqlite3_prepare", test_prepare ,0 },
|
||||
{ "sqlite3_prepare16", test_prepare16 ,0 },
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
|
||||
#include "test_windirent.h"
|
||||
|
||||
/*
|
||||
|
||||
+37
-4
@@ -13,7 +13,8 @@
|
||||
** POSIX functions on Win32 using the MSVCRT.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
|
||||
#define SQLITE_WINDIRENT_H
|
||||
|
||||
/*
|
||||
** We need several data types from the Windows SDK header.
|
||||
@@ -37,6 +38,33 @@
|
||||
#include <errno.h>
|
||||
#include <io.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*
|
||||
** We may need several defines that should have been in "sys/stat.h".
|
||||
*/
|
||||
|
||||
#ifndef S_ISREG
|
||||
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
#ifndef S_ISLNK
|
||||
#define S_ISLNK(mode) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** We may need to provide the "mode_t" type.
|
||||
*/
|
||||
|
||||
#ifndef MODE_T_DEFINED
|
||||
#define MODE_T_DEFINED
|
||||
typedef unsigned short mode_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** We may need to provide the "ino_t" type.
|
||||
@@ -75,22 +103,27 @@
|
||||
** We need to provide the necessary structures and related types.
|
||||
*/
|
||||
|
||||
#ifndef DIRENT_DEFINED
|
||||
#define DIRENT_DEFINED
|
||||
typedef struct DIRENT DIRENT;
|
||||
typedef struct DIR DIR;
|
||||
typedef DIRENT *LPDIRENT;
|
||||
typedef DIR *LPDIR;
|
||||
|
||||
struct DIRENT {
|
||||
ino_t d_ino; /* Sequence number, do not use. */
|
||||
unsigned d_attributes; /* Win32 file attributes. */
|
||||
char d_name[NAME_MAX + 1]; /* Name within the directory. */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef DIR_DEFINED
|
||||
#define DIR_DEFINED
|
||||
typedef struct DIR DIR;
|
||||
typedef DIR *LPDIR;
|
||||
struct DIR {
|
||||
intptr_t d_handle; /* Value returned by "_findfirst". */
|
||||
DIRENT d_first; /* DIRENT constructed based on "_findfirst". */
|
||||
DIRENT d_next; /* DIRENT constructed based on "_findnext". */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Provide a macro, for use by the implementation, to determine if a
|
||||
|
||||
+1
-1
@@ -2370,7 +2370,7 @@ case OP_Offset: { /* out3 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
pOut = &p->aMem[pOp->p3];
|
||||
if( pC==0 || pC->eCurType!=CURTYPE_BTREE ){
|
||||
if( NEVER(pC==0) || pC->eCurType!=CURTYPE_BTREE ){
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
}else{
|
||||
sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor));
|
||||
|
||||
+20
-20
@@ -9,7 +9,7 @@
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
# Test cases for the sqlite_unsupported_offset() function.
|
||||
# Test cases for the sqlite_offset() function.
|
||||
#
|
||||
# Some of the tests in this file depend on the exact placement of content
|
||||
# within b-tree pages. Such placement is at the implementations discretion,
|
||||
@@ -34,51 +34,51 @@ do_execsql_test func6-100 {
|
||||
INSERT INTO t2(x,y) SELECT a, b FROM t1;
|
||||
}
|
||||
do_execsql_test func6-110 {
|
||||
SELECT a, sqlite_unsupported_offset(d)/4096 + 1,
|
||||
sqlite_unsupported_offset(d)%4096 FROM t1
|
||||
SELECT a, sqlite_offset(d)/4096 + 1,
|
||||
sqlite_offset(d)%4096 FROM t1
|
||||
ORDER BY rowid LIMIT 2;
|
||||
} {abc001 2 4084 abc002 2 4069}
|
||||
do_execsql_test func6-120 {
|
||||
SELECT a, typeof(sqlite_unsupported_offset(+a)) FROM t1
|
||||
SELECT a, typeof(sqlite_offset(+a)) FROM t1
|
||||
ORDER BY rowid LIMIT 2;
|
||||
} {abc001 null abc002 null}
|
||||
do_execsql_test func6-130 {
|
||||
SELECT a, sqlite_unsupported_offset(a)/4096+1,
|
||||
sqlite_unsupported_offset(a)%4096
|
||||
SELECT a, sqlite_offset(a)/4096+1,
|
||||
sqlite_offset(a)%4096
|
||||
FROM t1
|
||||
ORDER BY a LIMIT 2;
|
||||
} {abc001 3 4087 abc002 3 4076}
|
||||
do_execsql_test func6-140 {
|
||||
SELECT a, sqlite_unsupported_offset(d)/4096+1,
|
||||
sqlite_unsupported_offset(d)%4096
|
||||
SELECT a, sqlite_offset(d)/4096+1,
|
||||
sqlite_offset(d)%4096
|
||||
FROM t1
|
||||
ORDER BY a LIMIT 2;
|
||||
} {abc001 2 4084 abc002 2 4069}
|
||||
do_execsql_test func6-150 {
|
||||
SELECT a,
|
||||
sqlite_unsupported_offset(a)/4096+1,
|
||||
sqlite_unsupported_offset(a)%4096,
|
||||
sqlite_unsupported_offset(d)/4096+1,
|
||||
sqlite_unsupported_offset(d)%4096
|
||||
sqlite_offset(a)/4096+1,
|
||||
sqlite_offset(a)%4096,
|
||||
sqlite_offset(d)/4096+1,
|
||||
sqlite_offset(d)%4096
|
||||
FROM t1
|
||||
ORDER BY a LIMIT 2;
|
||||
} {abc001 3 4087 2 4084 abc002 3 4076 2 4069}
|
||||
do_execsql_test func6-160 {
|
||||
SELECT b,
|
||||
sqlite_unsupported_offset(b)/4096+1,
|
||||
sqlite_unsupported_offset(b)%4096,
|
||||
sqlite_unsupported_offset(c)/4096+1,
|
||||
sqlite_unsupported_offset(c)%4096,
|
||||
sqlite_unsupported_offset(d)/4096+1,
|
||||
sqlite_unsupported_offset(d)%4096
|
||||
sqlite_offset(b)/4096+1,
|
||||
sqlite_offset(b)%4096,
|
||||
sqlite_offset(c)/4096+1,
|
||||
sqlite_offset(c)%4096,
|
||||
sqlite_offset(d)/4096+1,
|
||||
sqlite_offset(d)%4096
|
||||
FROM t1
|
||||
ORDER BY b LIMIT 2;
|
||||
} {1 4 4090 4 4090 2 4084 2 4 4081 4 4081 2 4069}
|
||||
|
||||
|
||||
do_execsql_test func6-200 {
|
||||
SELECT y, sqlite_unsupported_offset(y)/4096+1,
|
||||
sqlite_unsupported_offset(y)%4096
|
||||
SELECT y, sqlite_offset(y)/4096+1,
|
||||
sqlite_offset(y)%4096
|
||||
FROM t2
|
||||
ORDER BY x LIMIT 2;
|
||||
} {1 5 4087 2 5 4076}
|
||||
|
||||
@@ -401,5 +401,28 @@ do_execsql_test indexexpr1-1430 {
|
||||
SELECT abs(15+3) IN (SELECT 17 UNION ALL SELECT 18) FROM t1;
|
||||
} {1 1}
|
||||
|
||||
# 2018-01-02 ticket https://sqlite.org/src/info/dc3f932f5a147771
|
||||
# A REPLACE into a table that uses an index on an expression causes
|
||||
# an assertion fault. Problem discovered by OSSFuzz.
|
||||
#
|
||||
do_execsql_test indexexpr1-1500 {
|
||||
CREATE TABLE t1500(a INT PRIMARY KEY, b INT UNIQUE);
|
||||
CREATE INDEX t1500ab ON t1500(a*b);
|
||||
INSERT INTO t1500(a,b) VALUES(1,2);
|
||||
REPLACE INTO t1500(a,b) VALUES(1,3); -- formerly caused assertion fault
|
||||
SELECT * FROM t1500;
|
||||
} {1 3}
|
||||
|
||||
# 2018-01-03 OSSFuzz discovers another test case for the same problem
|
||||
# above.
|
||||
#
|
||||
do_execsql_test indexexpr-1510 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a PRIMARY KEY,b UNIQUE);
|
||||
REPLACE INTO t1 VALUES(2, 1);
|
||||
REPLACE INTO t1 SELECT 6,1;
|
||||
CREATE INDEX t1aa ON t1(a-a);
|
||||
REPLACE INTO t1 SELECT a, randomblob(a) FROM t1
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# 2018-01-08
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests for the sqlite3_normalize() extension function.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix normalize
|
||||
|
||||
foreach {tnum sql norm} {
|
||||
100
|
||||
{SELECT * FROM t1 WHERE a IN (1) AND b=51.42}
|
||||
{select*from t1 where a in(?,?,?)and b=?;}
|
||||
|
||||
110
|
||||
{SELECT a, b+15, c FROM t1 WHERE d NOT IN (SELECT x FROM t2);}
|
||||
{select a,b+?,c from t1 where d not in(select x from t2);}
|
||||
|
||||
120
|
||||
{ SELECT NULL, b FROM t1 -- comment text
|
||||
WHERE d IN (WITH t(a) AS (VALUES(5)) /* CTE */
|
||||
SELECT a FROM t)
|
||||
OR e='hello';
|
||||
}
|
||||
{select?,b from t1 where d in(with t(a)as(values(?))select a from t)or e=?;}
|
||||
|
||||
121
|
||||
{/*Initial comment*/
|
||||
-- another comment line
|
||||
SELECT NULL /* comment */ , b FROM t1 -- comment text
|
||||
WHERE d IN (WITH t(a) AS (VALUES(5)) /* CTE */
|
||||
SELECT a FROM t)
|
||||
OR e='hello';
|
||||
}
|
||||
{select?,b from t1 where d in(with t(a)as(values(?))select a from t)or e=?;}
|
||||
|
||||
130
|
||||
{/* Query containing parameters */
|
||||
SELECT x,$::abc(15),y,@abc,z,?99,w FROM t1 /* Trailing comment */}
|
||||
{select x,?,y,?,z,?,w from t1;}
|
||||
|
||||
140
|
||||
{/* Long list on the RHS of IN */
|
||||
SELECT 15 IN (1,2,3,(SELECT * FROM t1),'xyz',x'abcd',22*(x+5),null);}
|
||||
{select?in(?,?,?);}
|
||||
|
||||
150
|
||||
{SELECT x'abc'; -- illegal token}
|
||||
{}
|
||||
|
||||
160
|
||||
{SELECT a,NULL,b FROM t1 WHERE c IS NOT NULL or D is null or e=5}
|
||||
{select a,?,b from t1 where c is not null or d is null or e=?;}
|
||||
|
||||
170
|
||||
{/* IN list exactly 5 bytes long */
|
||||
SELECT * FROM t1 WHERE x IN (1,2,3);}
|
||||
{select*from t1 where x in(?,?,?);}
|
||||
} {
|
||||
do_test $tnum [list sqlite3_normalize $sql] $norm
|
||||
}
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -34,7 +34,7 @@ do_execsql_test 1.0 {
|
||||
1 builtin {} 0 {} 0
|
||||
}
|
||||
do_execsql_test 1.1 {
|
||||
SELECT * FROM pragma_function_list WHERE name='upper'
|
||||
SELECT * FROM pragma_function_list WHERE name='upper' AND builtin
|
||||
} {upper 1}
|
||||
do_execsql_test 1.2 {
|
||||
SELECT * FROM pragma_function_list WHERE name LIKE 'exter%';
|
||||
|
||||
@@ -734,6 +734,9 @@ proc makeCommand { targets makeOpts cflags opts } {
|
||||
set nmakeDir [file nativename $::SRCDIR]
|
||||
set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]]
|
||||
lappend result nmake /f $nmakeFile TOP=$nmakeDir
|
||||
set tclDir [file nativename [file normalize \
|
||||
[file dirname [file dirname [info nameofexecutable]]]]]
|
||||
lappend result "TCLDIR=$tclDir"
|
||||
if {[regexp {USE_STDCALL=1} $cflags]} {
|
||||
lappend result USE_STDCALL=1
|
||||
}
|
||||
|
||||
+4
-2
@@ -581,8 +581,10 @@ do_test shell1-3.21.4 {
|
||||
}
|
||||
catchcmd "test.db" ".schema"
|
||||
} {0 {CREATE TABLE t1(x);
|
||||
CREATE VIEW v2 AS SELECT x+1 AS y FROM t1;
|
||||
CREATE VIEW v1 AS SELECT y+1 FROM v2;}}
|
||||
CREATE VIEW v2 AS SELECT x+1 AS y FROM t1
|
||||
/* v2(y) */;
|
||||
CREATE VIEW v1 AS SELECT y+1 FROM v2
|
||||
/* v1("y+1") */;}}
|
||||
db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
# 2017 December 9
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test the shell tool ".ar" command.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix shell8
|
||||
set CLI [test_find_cli]
|
||||
|
||||
proc populate_dir {dirname spec} {
|
||||
# First delete the current tree, if one exists.
|
||||
file delete -force $dirname
|
||||
|
||||
# Recreate the root of the new tree.
|
||||
file mkdir $dirname
|
||||
|
||||
# Add each file to the new tree.
|
||||
foreach {f d} $spec {
|
||||
set path [file join $dirname $f]
|
||||
file mkdir [file dirname $path]
|
||||
set fd [open $path w]
|
||||
puts -nonewline $fd $d
|
||||
close $fd
|
||||
}
|
||||
}
|
||||
|
||||
proc dir_to_list {dirname {n -1}} {
|
||||
if {$n<0} {set n [llength [file split $dirname]]}
|
||||
|
||||
set res [list]
|
||||
foreach f [glob -nocomplain $dirname/*] {
|
||||
set mtime [file mtime $f]
|
||||
if {$::tcl_platform(platform)!="windows"} {
|
||||
set perm [file attributes $f -perm]
|
||||
} else {
|
||||
set perm 0
|
||||
}
|
||||
set relpath [file join {*}[lrange [file split $f] $n end]]
|
||||
lappend res
|
||||
if {[file isdirectory $f]} {
|
||||
lappend res [list $relpath / $mtime $perm]
|
||||
lappend res {*}[dir_to_list $f]
|
||||
} else {
|
||||
set fd [open $f]
|
||||
set data [read $fd]
|
||||
close $fd
|
||||
lappend res [list $relpath $data $mtime $perm]
|
||||
}
|
||||
}
|
||||
lsort $res
|
||||
}
|
||||
|
||||
proc dir_compare {d1 d2} {
|
||||
set l1 [dir_to_list $d1]
|
||||
set l2 [dir_to_list $d1]
|
||||
string compare $l1 $l2
|
||||
}
|
||||
|
||||
foreach {tn tcl} {
|
||||
1 {
|
||||
set c1 ".ar c ar1"
|
||||
set x1 ".ar x"
|
||||
|
||||
set c2 ".ar cC ar1 ."
|
||||
set x2 ".ar Cx ar3"
|
||||
|
||||
set c3 ".ar cCf ar1 test_xyz.db ."
|
||||
set x3 ".ar Cfx ar3 test_xyz.db"
|
||||
}
|
||||
|
||||
2 {
|
||||
set c1 ".ar -c ar1"
|
||||
set x1 ".ar -x"
|
||||
|
||||
set c2 ".ar -cC ar1 ."
|
||||
set x2 ".ar -xC ar3"
|
||||
|
||||
set c3 ".ar -cCar1 -ftest_xyz.db ."
|
||||
set x3 ".ar -x -C ar3 -f test_xyz.db"
|
||||
}
|
||||
|
||||
3 {
|
||||
set c1 ".ar --create ar1"
|
||||
set x1 ".ar --extract"
|
||||
|
||||
set c2 ".ar --directory ar1 --create ."
|
||||
set x2 ".ar --extract --dir ar3"
|
||||
|
||||
set c3 ".ar --creat --dir ar1 --file test_xyz.db ."
|
||||
set x3 ".ar --e --d ar3 --f test_xyz.db"
|
||||
}
|
||||
|
||||
4 {
|
||||
set c1 ".ar --cr ar1"
|
||||
set x1 ".ar --e"
|
||||
|
||||
set c2 ".ar -C ar1 -c ."
|
||||
set x2 ".ar -x -C ar3"
|
||||
|
||||
set c3 ".ar -c --directory ar1 --file test_xyz.db ."
|
||||
set x3 ".ar -x --directory ar3 --file test_xyz.db"
|
||||
}
|
||||
} {
|
||||
eval $tcl
|
||||
|
||||
# Populate directory "ar1" with some files.
|
||||
#
|
||||
populate_dir ar1 {
|
||||
file1 "abcd"
|
||||
file2 "efgh"
|
||||
dir1/file3 "ijkl"
|
||||
}
|
||||
set expected [dir_to_list ar1]
|
||||
|
||||
do_test 1.$tn.1 {
|
||||
catchcmd test_ar.db $c1
|
||||
file delete -force ar1
|
||||
catchcmd test_ar.db $x1
|
||||
dir_to_list ar1
|
||||
} $expected
|
||||
|
||||
do_test 1.$tn.2 {
|
||||
file delete -force ar3
|
||||
catchcmd test_ar.db $c2
|
||||
catchcmd test_ar.db $x2
|
||||
dir_to_list ar3
|
||||
} $expected
|
||||
|
||||
do_test 1.$tn.3 {
|
||||
file delete -force ar3
|
||||
file delete -force test_xyz.db
|
||||
catchcmd ":memory:" $c3
|
||||
catchcmd ":memory:" $x3
|
||||
dir_to_list ar3
|
||||
} $expected
|
||||
|
||||
# This is a repeat of test 1.$tn.1, except that there is a 2 second
|
||||
# pause between creating the archive and extracting its contents.
|
||||
# This is to test that timestamps are set correctly.
|
||||
#
|
||||
# Because it is slow, only do this for $tn==1.
|
||||
if {$tn==1} {
|
||||
do_test 1.$tn.1 {
|
||||
catchcmd test_ar.db $c1
|
||||
file delete -force ar1
|
||||
after 2000
|
||||
catchcmd test_ar.db $x1
|
||||
dir_to_list ar1
|
||||
} $expected
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# 2017 December 9
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix zipfile
|
||||
|
||||
if {[catch {load_static_extension db zipfile} error]} {
|
||||
puts "Skipping zipfile tests, hit load error: $error"
|
||||
finish_test; return
|
||||
}
|
||||
|
||||
forcedelete test.zip
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE temp.zz USING zipfile('test.zip');
|
||||
PRAGMA table_info(zz);
|
||||
} {
|
||||
0 name {} 0 {} 0
|
||||
1 mode {} 0 {} 0
|
||||
2 mtime {} 0 {} 0
|
||||
3 sz {} 0 {} 0
|
||||
4 data {} 0 {} 0
|
||||
5 method {} 0 {} 0
|
||||
}
|
||||
|
||||
do_execsql_test 1.1.1 {
|
||||
INSERT INTO zz VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
|
||||
}
|
||||
do_execsql_test 1.1.2 {
|
||||
INSERT INTO zz VALUES('g.txt', '-rw-r--r--', 1000000002, 5, '12345', 0);
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT name, mtime, data FROM zipfile('test.zip')
|
||||
} {
|
||||
f.txt 1000000000 abcde
|
||||
g.txt 1000000002 12345
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO zz VALUES('h.txt',
|
||||
'-rw-r--r--', 1000000004, 20, 'aaaaaaaaaabbbbbbbbbb', NULL
|
||||
);
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT name, mtime, zipfile_uncompress(data, sz, method), method
|
||||
FROM zipfile('test.zip');
|
||||
} {
|
||||
f.txt 1000000000 abcde 0
|
||||
g.txt 1000000002 12345 0
|
||||
h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8
|
||||
}
|
||||
|
||||
do_execsql_test 1.5.1 {
|
||||
BEGIN;
|
||||
INSERT INTO zz VALUES('i.txt', '-rw-r--r--', 1000000006, 5, 'zxcvb', 0);
|
||||
SELECT name FROM zz;
|
||||
COMMIT;
|
||||
} {f.txt g.txt h.txt i.txt}
|
||||
do_execsql_test 1.5.2 {
|
||||
SELECT name FROM zz;
|
||||
} {f.txt g.txt h.txt i.txt}
|
||||
|
||||
do_execsql_test 1.6.0 {
|
||||
DELETE FROM zz WHERE name='g.txt';
|
||||
SELECT name FROM zz;
|
||||
} {f.txt h.txt i.txt}
|
||||
|
||||
finish_test
|
||||
|
||||
+15
-2
@@ -30,16 +30,29 @@ puts $out {/* DO NOT EDIT!
|
||||
** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
|
||||
*/}
|
||||
set in [open $topdir/src/shell.c.in rb]
|
||||
proc omit_redundant_typedefs {line} {
|
||||
global typedef_seen
|
||||
if {[regexp {^typedef .*;} $line]} {
|
||||
if {[info exists typedef_seen($line)]} {
|
||||
return "/* $line */"
|
||||
}
|
||||
set typedef_seen($line) 1
|
||||
}
|
||||
return $line
|
||||
}
|
||||
while {1} {
|
||||
set lx [gets $in]
|
||||
set lx [omit_redundant_typedefs [gets $in]]
|
||||
if {[eof $in]} break;
|
||||
if {[regexp {^INCLUDE } $lx]} {
|
||||
set cfile [lindex $lx 1]
|
||||
puts $out "/************************* Begin $cfile ******************/"
|
||||
set in2 [open $topdir/src/$cfile rb]
|
||||
while {![eof $in2]} {
|
||||
set lx [gets $in2]
|
||||
set lx [omit_redundant_typedefs [gets $in2]]
|
||||
if {[regexp {^#include "sqlite} $lx]} continue
|
||||
if {[regexp {^# *include "test_windirent.h"} $lx]} {
|
||||
set lx "/* $lx */"
|
||||
}
|
||||
set lx [string map [list __declspec(dllexport) {}] $lx]
|
||||
puts $out $lx
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
** This is the source code to a "tclsh" that has SQLite built-in.
|
||||
**
|
||||
** The startup script is located as follows:
|
||||
**
|
||||
** (1) Open the executable as an appended SQLite database and try to
|
||||
** read the startup script out of that database.
|
||||
**
|
||||
** (2) If the first argument is a readable file, try to open that file
|
||||
** as an SQLite database and read the startup script out of that
|
||||
** database.
|
||||
**
|
||||
** (3) If the first argument is a readable file with a ".tcl" extension,
|
||||
** then try to run that script directly.
|
||||
**
|
||||
** If none of the above steps work, then the program runs as an interactive
|
||||
** tclsh.
|
||||
*/
|
||||
#define TCLSH_INIT_PROC sqlite3_tclapp_init_proc
|
||||
#define SQLITE_ENABLE_DBSTAT_VTAB 1
|
||||
#undef SQLITE_THREADSAFE
|
||||
#define SQLITE_THREADSAFE 0
|
||||
#undef SQLITE_ENABLE_COLUMN_METADATA
|
||||
#define SQLITE_OMIT_DECLTYPE 1
|
||||
#define SQLITE_OMIT_DEPRECATED 1
|
||||
#define SQLITE_OMIT_PROGRESS_CALLBACK 1
|
||||
#define SQLITE_OMIT_SHARED_CACHE 1
|
||||
#define SQLITE_DEFAULT_MEMSTATUS 0
|
||||
#define SQLITE_MAX_EXPR_DEPTH 0
|
||||
INCLUDE sqlite3.c
|
||||
INCLUDE $ROOT/ext/misc/appendvfs.c
|
||||
INCLUDE $ROOT/ext/misc/zipfile.c
|
||||
INCLUDE $ROOT/ext/misc/sqlar.c
|
||||
INCLUDE $ROOT/src/tclsqlite.c
|
||||
|
||||
const char *sqlite3_tclapp_init_proc(Tcl_Interp *interp){
|
||||
(void)interp;
|
||||
sqlite3_appendvfs_init(0,0,0);
|
||||
sqlite3_auto_extension((void(*)(void))sqlite3_sqlar_init);
|
||||
sqlite3_auto_extension((void(*)(void))sqlite3_zipfile_init);
|
||||
|
||||
return
|
||||
BEGIN_STRING
|
||||
INCLUDE $ROOT/tool/sqltclsh.tcl
|
||||
END_STRING
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
# Try to open the executable as a database and read the "scripts.data"
|
||||
# field where "scripts.name" is 'main.tcl'
|
||||
#
|
||||
catch {
|
||||
if {![file exists $argv0] && [file exists $argv0.exe]} {
|
||||
append argv0 .exe
|
||||
}
|
||||
sqlite3 db $argv0 -vfs apndvfs -create 0
|
||||
set mainscript [db one {
|
||||
SELECT sqlar_uncompress(data,sz) FROM sqlar WHERE name='main.tcl'
|
||||
}]
|
||||
}
|
||||
if {[info exists mainscript]} {
|
||||
eval $mainscript
|
||||
return
|
||||
} else {
|
||||
catch {db close}
|
||||
}
|
||||
|
||||
# Try to open file named in the first argument as a database and
|
||||
# read the "scripts.data" field where "scripts.name" is 'main.tcl'
|
||||
#
|
||||
if {[llength $argv]>0 && [file readable [lindex $argv 0]]} {
|
||||
catch {
|
||||
sqlite3 db [lindex $argv 0] -vfs apndvfs -create 0
|
||||
set mainscript [db one {SELECT data FROM scripts WHERE name='main.tcl'}]
|
||||
set argv0 [lindex $argv 0]
|
||||
set argv [lrange $argv 1 end]
|
||||
}
|
||||
if {[info exists mainscript]} {
|
||||
eval $mainscript
|
||||
return
|
||||
} else {
|
||||
catch {db close}
|
||||
}
|
||||
if {[string match *.tcl [lindex $argv 0]]} {
|
||||
set fd [open [lindex $argv 0] rb]
|
||||
set mainscript [read $fd]
|
||||
close $fd
|
||||
unset fd
|
||||
set argv0 [lindex $argv 0]
|
||||
set argv [lrange $argv 1 end]
|
||||
}
|
||||
if {[info exists mainscript]} {
|
||||
eval $mainscript
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# If all else fails, do an interactive loop
|
||||
#
|
||||
set line {}
|
||||
while {![eof stdin]} {
|
||||
if {$line!=""} {
|
||||
puts -nonewline "> "
|
||||
} else {
|
||||
puts -nonewline "% "
|
||||
}
|
||||
flush stdout
|
||||
append line [gets stdin]
|
||||
if {[info complete $line]} {
|
||||
if {[catch {uplevel #0 $line} result]} {
|
||||
puts stderr "Error: $result"
|
||||
} elseif {$result!=""} {
|
||||
puts $result
|
||||
}
|
||||
set line {}
|
||||
} else {
|
||||
append line \\n"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user