Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7cfbb21451 | |||
| 64bc5263e1 | |||
| cac93a5be0 |
+16
-10
@@ -30,12 +30,14 @@ The public domain source files usually contain a header comment
|
||||
similar to the following to make it clear that the software is
|
||||
public domain.
|
||||
|
||||
> 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.
|
||||
> ~~~
|
||||
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.
|
||||
~~~
|
||||
|
||||
Almost every file you find in this source repository will be
|
||||
public domain. But there are a small number of exceptions:
|
||||
@@ -47,7 +49,9 @@ This repository contains a (relatively) small amount of non-public-domain
|
||||
code used to help implement the configuration and build logic. In other
|
||||
words, there are some non-public-domain files used to implement:
|
||||
|
||||
> ./configure && make
|
||||
> ~~~
|
||||
./configure && make
|
||||
~~~
|
||||
|
||||
In all cases, the non-public-domain files included with this
|
||||
repository have generous BSD-style licenses. So anyone is free to
|
||||
@@ -65,7 +69,7 @@ third-party build scripts in order to compile SQLite.
|
||||
Non-public-domain code included in this respository includes:
|
||||
|
||||
* The ["autosetup"](http://msteveb.github.io/autosetup/) configuration
|
||||
system that is contained (mostly) in the autosetup/ directory, but also
|
||||
system that is contained (mostly) the autosetup/ directory, but also
|
||||
includes the "./configure" script at the top-level of this archive.
|
||||
Autosetup has a separate BSD-style license. See the
|
||||
[autosetup/LICENSE](http://msteveb.github.io/autosetup/license/)
|
||||
@@ -75,11 +79,13 @@ Non-public-domain code included in this respository includes:
|
||||
software found in the legacy autoconf/ directory and its
|
||||
subdirectories.
|
||||
|
||||
The following unix shell command can be run from the top-level
|
||||
The following unix shell command is can be run from the top-level
|
||||
of this source repository in order to remove all non-public-domain
|
||||
code:
|
||||
|
||||
> rm -rf configure autosetup autoconf
|
||||
> ~~~
|
||||
rm -rf configure autosetup autoconf
|
||||
~~~
|
||||
|
||||
If you unpack this source repository and then run the command above, what
|
||||
is left will be 100% public domain.
|
||||
|
||||
+3
-11
@@ -131,15 +131,9 @@ libsqlite3.DLL.install-rules = @SQLITE_DLL_INSTALL_RULES@
|
||||
CFLAGS.fuzzcheck-asan.fsanitize = @CFLAGS_ASAN_FSANITIZE@
|
||||
|
||||
#
|
||||
# TARGET_DEBUG is intended to either be empty or be set to -g
|
||||
# -DSQLITE_DEBUG=1, plus any other flags relevant for debug-only
|
||||
# builds. These get added near the front of $(T.cc) so that they can
|
||||
# be overridden by CFLAGS passed directly to make. Historically (prior
|
||||
# to 2026-03-30) these were at/near the end of the flags but that made
|
||||
# it impossible to pass custom -O* flags to specific binaries without
|
||||
# reconfiguring.
|
||||
# Intended to either be empty or be set to -g -DSQLITE_DEBUG=1.
|
||||
#
|
||||
T.cc += @TARGET_DEBUG@
|
||||
T.cc.TARGET_DEBUG = @TARGET_DEBUG@
|
||||
|
||||
#
|
||||
# $(JIMSH) and $(CFLAGS.jimsh) are documented in main.mk. $(JIMSH)
|
||||
@@ -170,9 +164,7 @@ OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ $(OPTIONS)
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
#
|
||||
# Filename extensions for binaries and libraries. B.* are for the
|
||||
# being-built-on platform and T.* are for the build's target platform.
|
||||
# i.e. B.* is for build-time tooling and T.* is for deliverables.
|
||||
# Filename extensions for binaries and libraries
|
||||
#
|
||||
B.exe = @BUILD_EXEEXT@
|
||||
T.exe = @TARGET_EXEEXT@
|
||||
|
||||
+165
-256
@@ -11,8 +11,6 @@
|
||||
TOP = .
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# Set this non-0 to create and use the SQLite amalgamation file.
|
||||
#
|
||||
!IFNDEF USE_AMALGAMATION
|
||||
@@ -103,6 +101,13 @@ NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to use the library paths and other options necessary for
|
||||
# Windows Phone 8.1.
|
||||
#
|
||||
!IFNDEF USE_WP81_OPTS
|
||||
USE_WP81_OPTS = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to split the SQLite amalgamation file into chunks to
|
||||
# be used for debugging with Visual Studio.
|
||||
#
|
||||
@@ -111,8 +116,14 @@ SPLIT_AMALGAMATION = 0
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
# Set this non-0 to have this makefile assume the Tcl shell executable
|
||||
# (tclsh*.exe) is available in the PATH. By default, this is disabled
|
||||
# for compatibility with older build environments. This setting only
|
||||
# applies if TCLSH_CMD is not set manually.
|
||||
#
|
||||
!IFNDEF USE_TCLSH_IN_PATH
|
||||
USE_TCLSH_IN_PATH = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to use zlib, possibly compiling it from source code.
|
||||
#
|
||||
@@ -175,6 +186,14 @@ USE_NATIVE_LIBPATHS = 0
|
||||
USE_RC = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to compile binaries suitable for the WinRT environment.
|
||||
# This setting does not apply to any binaries that require Tcl to operate
|
||||
# properly (i.e. the text fixture, etc).
|
||||
#
|
||||
!IFNDEF FOR_WINRT
|
||||
FOR_WINRT = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to compile binaries suitable for the UWP environment.
|
||||
# This setting does not apply to any binaries that require Tcl to operate
|
||||
# properly (i.e. the text fixture, etc).
|
||||
@@ -190,8 +209,6 @@ FOR_WIN10 = 0
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# Set this non-0 to skip attempting to look for and/or link with the Tcl
|
||||
# runtime library.
|
||||
#
|
||||
@@ -248,8 +265,6 @@ DEBUG = 0
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# By default, use --linemacros=1 argument to the mksqlite3c.tcl tool, which
|
||||
# is used to build the amalgamation. This can be turned off to ease debug
|
||||
# of the amalgamation away from the source tree.
|
||||
@@ -345,8 +360,6 @@ SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# These are the names of the customized Tcl header files used by various parts
|
||||
# of this makefile when the stdcall calling convention is in use. It is not
|
||||
# used for any other purpose.
|
||||
@@ -392,7 +405,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_CARRAY=1
|
||||
!ENDIF
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
!ENDIF
|
||||
@@ -415,7 +427,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
|
||||
# Always enable math functions on Windows
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PERCENTILE
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
@@ -628,24 +639,16 @@ RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src $(RCOPTS) $(RCCOPTS)
|
||||
!IF "$(PLATFORM)"=="x86"
|
||||
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
|
||||
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
TEST_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl
|
||||
# <</mark>>
|
||||
|
||||
!ELSE
|
||||
!IFNDEF PLATFORM
|
||||
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
|
||||
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
TEST_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl
|
||||
# <</mark>>
|
||||
|
||||
!ELSE
|
||||
CORE_CCONV_OPTS =
|
||||
SHELL_CCONV_OPTS =
|
||||
@@ -772,6 +775,18 @@ SHELL_LINK_OPTS = $(SHELL_CORE_LIB)
|
||||
TCC = $(TCC) -FAcs
|
||||
!ENDIF
|
||||
|
||||
# When compiling the library for use in the WinRT environment,
|
||||
# the following compile-time options must be used as well to
|
||||
# disable use of Win32 APIs that are not available and to enable
|
||||
# use of Win32 APIs that are specific to Windows 8 and/or WinRT.
|
||||
#
|
||||
!IF $(FOR_WINRT)!=0
|
||||
TCC = $(TCC) -DSQLITE_OS_WINRT=1
|
||||
RCC = $(RCC) -DSQLITE_OS_WINRT=1
|
||||
TCC = $(TCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
|
||||
RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
|
||||
!ENDIF
|
||||
|
||||
# C compiler options for the Windows 10 platform (needs MSVC 2015).
|
||||
#
|
||||
!IF $(FOR_WIN10)!=0
|
||||
@@ -784,31 +799,25 @@ BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
|
||||
# USE_CRT_DLL option is set to force dynamically linking to the
|
||||
# MSVC runtime library.
|
||||
#
|
||||
!IF $(USE_CRT_DLL)!=0
|
||||
!IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
|
||||
!IF $(DEBUG)>1
|
||||
TCC = $(TCC) -MDd
|
||||
BCC = $(BCC) -MDd
|
||||
ZLIBCFLAGS = -nologo -MDd -W3 -O2 -Oy- -Zi
|
||||
!ELSE
|
||||
TCC = $(TCC) -MD
|
||||
BCC = $(BCC) -MD
|
||||
ZLIBCFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi
|
||||
!ENDIF
|
||||
!ELSE
|
||||
!IF $(DEBUG)>1
|
||||
TCC = $(TCC) -MTd
|
||||
BCC = $(BCC) -MTd
|
||||
ZLIBCFLAGS = -nologo -MTd -W3 -O2 -Oy- -Zi
|
||||
!ELSE
|
||||
TCC = $(TCC) -MT
|
||||
BCC = $(BCC) -MT
|
||||
ZLIBCFLAGS = -nologo -MT -W3 -O2 -Oy- -Zi
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# The mksqlite3c.tcl and mksqlite3h.tcl scripts will pull in
|
||||
# any extension header files by default. For non-amalgamation
|
||||
# builds, we need to make sure the compiler can find these.
|
||||
@@ -859,6 +868,16 @@ MKSQLITE3H_ARGS =
|
||||
!ENDIF
|
||||
# <</mark>>
|
||||
|
||||
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
|
||||
# Omitting the define will cause extra debugging code to be inserted and
|
||||
# includes extra comments when "EXPLAIN stmt" is used.
|
||||
#
|
||||
!IF $(DEBUG)==0
|
||||
TCC = $(TCC) -DNDEBUG
|
||||
BCC = $(BCC) -DNDEBUG
|
||||
RCC = $(RCC) -DNDEBUG
|
||||
!ENDIF
|
||||
|
||||
!IF $(DEBUG)>0 || $(API_ARMOR)!=0 || $(FOR_WIN10)!=0
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR=1
|
||||
RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
|
||||
@@ -924,8 +943,6 @@ TCC = $(TCC) /fsanitize=address
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# The locations of the Tcl header and library files. Also, the library that
|
||||
# non-stubs enabled programs using Tcl must link against. These variables
|
||||
# (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment
|
||||
@@ -1165,8 +1182,6 @@ BCC = $(BCC) -Zi
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# If zlib support is enabled, add the compiler options for it.
|
||||
#
|
||||
!IF $(USE_ZLIB)!=0
|
||||
@@ -1219,6 +1234,56 @@ LTLINKOPTS = /NOLOGO
|
||||
LTLIBOPTS = /NOLOGO
|
||||
!ENDIF
|
||||
|
||||
# When compiling for use in the WinRT environment, the following
|
||||
# linker option must be used to mark the executable as runnable
|
||||
# only in the context of an application container.
|
||||
#
|
||||
!IF $(FOR_WINRT)!=0
|
||||
LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER
|
||||
!IF "$(VISUALSTUDIOVERSION)"=="12.0" || "$(VISUALSTUDIOVERSION)"=="14.0"
|
||||
!IFNDEF STORELIBPATH
|
||||
!IF "$(PLATFORM)"=="x86"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store
|
||||
!ELSEIF "$(PLATFORM)"=="x64"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store\amd64
|
||||
!ELSEIF "$(PLATFORM)"=="ARM"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store\arm
|
||||
!ELSE
|
||||
STORELIBPATH = $(CRTLIBPATH)\store
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
STORELIBPATH = $(STORELIBPATH:\\=\)
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(STORELIBPATH)"
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# When compiling for Windows Phone 8.1, an extra library path is
|
||||
# required.
|
||||
#
|
||||
!IF $(USE_WP81_OPTS)!=0
|
||||
!IFNDEF WP81LIBPATH
|
||||
!IF "$(PLATFORM)"=="x86"
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
|
||||
!ELSEIF "$(PLATFORM)"=="ARM"
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\ARM
|
||||
!ELSE
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# When compiling for Windows Phone 8.1, some extra linker options
|
||||
# are also required.
|
||||
#
|
||||
!IF $(USE_WP81_OPTS)!=0
|
||||
!IFDEF WP81LIBPATH
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
|
||||
!ENDIF
|
||||
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
|
||||
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
|
||||
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
|
||||
!ENDIF
|
||||
|
||||
# When compiling for UWP or the Windows 10 platform, some extra linker
|
||||
# options are also required.
|
||||
#
|
||||
@@ -1242,14 +1307,12 @@ LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
|
||||
# If either debugging or symbols are enabled, enable PDBs.
|
||||
#
|
||||
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
|
||||
LDFLAGS = /NODEFAULTLIB:msvcrt /DEBUG $(LDOPTS)
|
||||
LDFLAGS = /DEBUG $(LDOPTS)
|
||||
!ELSE
|
||||
LDFLAGS = /NODEFAULTLIB:msvcrt $(LDOPTS)
|
||||
LDFLAGS = $(LDOPTS)
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# Start with the Tcl related linker options.
|
||||
#
|
||||
!IF $(NO_TCL)==0
|
||||
@@ -1276,13 +1339,11 @@ LTLIBS = $(LTLIBS) $(LIBICU)
|
||||
###############################################################################
|
||||
|
||||
# <<mark>>
|
||||
# ^^^^^^^^-- content between mark and /mark omitted from autoconf/Makefile.msc
|
||||
#
|
||||
# Object files for the SQLite library (non-amalgamation).
|
||||
#
|
||||
LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
|
||||
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
|
||||
callback.lo carray.lo complete.lo ctime.lo \
|
||||
callback.lo complete.lo ctime.lo \
|
||||
date.lo dbpage.lo dbstat.lo delete.lo \
|
||||
expr.lo fault.lo fkey.lo \
|
||||
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
|
||||
@@ -1344,7 +1405,6 @@ SRC00 = \
|
||||
$(TOP)\src\btree.c \
|
||||
$(TOP)\src\build.c \
|
||||
$(TOP)\src\callback.c \
|
||||
$(TOP)\src\carray.c \
|
||||
$(TOP)\src\complete.c \
|
||||
ctime.c \
|
||||
$(TOP)\src\date.c \
|
||||
@@ -1396,7 +1456,7 @@ SRC01 = \
|
||||
$(TOP)\src\status.c \
|
||||
$(TOP)\src\table.c \
|
||||
$(TOP)\src\threads.c \
|
||||
tclsqlite-ex.c \
|
||||
$(TOP)\src\tclsqlite.c \
|
||||
$(TOP)\src\tokenize.c \
|
||||
$(TOP)\src\treeview.c \
|
||||
$(TOP)\src\trigger.c \
|
||||
@@ -1578,6 +1638,7 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\amatch.c \
|
||||
$(TOP)\ext\misc\appendvfs.c \
|
||||
$(TOP)\ext\misc\basexx.c \
|
||||
$(TOP)\ext\misc\carray.c \
|
||||
$(TOP)\ext\misc\cksumvfs.c \
|
||||
$(TOP)\ext\misc\closure.c \
|
||||
$(TOP)\ext\misc\csv.c \
|
||||
@@ -1593,6 +1654,7 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\mmapwarm.c \
|
||||
$(TOP)\ext\misc\nextchar.c \
|
||||
$(TOP)\ext\misc\normalize.c \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\prefixes.c \
|
||||
$(TOP)\ext\misc\qpvtab.c \
|
||||
$(TOP)\ext\misc\randomjson.c \
|
||||
@@ -1704,10 +1766,8 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_PERCENTILE=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
|
||||
!ENDIF
|
||||
|
||||
@@ -1719,9 +1779,7 @@ FUZZERSHELL_COMPILE_OPTS =
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -I$(TOP)\test -I$(TOP)\ext\recover
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_MEMSYS5
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_DECIMAL_MAX_DIGIT=1000
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_CARRAY
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
@@ -1735,7 +1793,6 @@ FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_MEMSYS5
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_NORMALIZE
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_PERCENTILE
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_PREUPDATE_HOOK
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_SESSION
|
||||
@@ -1766,17 +1823,8 @@ FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\fuzzinvariants.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\vt02.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\dbdata.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\sqlite3recover.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\base64.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\base85.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\completion.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\decimal.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\ieee754.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\percentile.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\randomjson.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\regexp.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\series.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\shathree.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\sha1.c
|
||||
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\stmtrand.c
|
||||
|
||||
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
||||
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
@@ -1877,8 +1925,8 @@ $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLIT
|
||||
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
|
||||
|
||||
# <<mark>>
|
||||
sqldiff.exe: $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS) $(TOP)\tool\winmain.c
|
||||
$(LTLINK) $(NO_WARN) -I$(TOP)\ext\misc $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.c $(TOP)\tool\winmain.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
|
||||
sqldiff.exe: $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -I$(TOP)\ext\misc $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
|
||||
|
||||
dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
@@ -1968,18 +2016,8 @@ sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-v
|
||||
|
||||
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(JIM_TCLSH)
|
||||
$(JIM_TCLSH) $(TOP)\tool\split-sqlite3c.tcl
|
||||
|
||||
TCLSQLITEEX = \
|
||||
$(TOP)\ext\qrf\qrf.h \
|
||||
$(TOP)\ext\qrf\qrf.c \
|
||||
$(TOP)\src\tclsqlite.c
|
||||
|
||||
tclsqlite-ex.c: $(TCLSQLITEEX) $(TOP)\tool\mkcombo.tcl $(JIM_TCLSH)
|
||||
$(JIM_TCLSH) $(TOP)\tool\mkcombo.tcl $(TCLSQLITEEX) -o $@
|
||||
# <</mark>>
|
||||
|
||||
tclsqlite-ex.c:
|
||||
|
||||
# Rule to build the amalgamation
|
||||
#
|
||||
sqlite3.lo: $(SQLITE3C)
|
||||
@@ -2063,9 +2101,6 @@ build.lo: $(TOP)\src\build.c $(HDR)
|
||||
callback.lo: $(TOP)\src\callback.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\callback.c
|
||||
|
||||
carray.lo: $(TOP)\src\carray.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\carray.c
|
||||
|
||||
complete.lo: $(TOP)\src\complete.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\complete.c
|
||||
|
||||
@@ -2279,11 +2314,11 @@ whereexpr.lo: $(TOP)\src\whereexpr.c $(HDR)
|
||||
window.lo: $(TOP)\src\window.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\window.c
|
||||
|
||||
tclsqlite.lo: tclsqlite-ex.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c tclsqlite-ex.c /OUT:tclsqlite.lo
|
||||
tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
|
||||
tclsqlite-shell.lo: tclsqlite-ex.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c tclsqlite-ex.c
|
||||
tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
|
||||
tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
@@ -2336,8 +2371,6 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
|
||||
# Source and header files that shell.c depends on
|
||||
SHELL_DEP = \
|
||||
$(TOP)\src\shell.c.in \
|
||||
$(TOP)\ext\qrf\qrf.c \
|
||||
$(TOP)\ext\qrf\qrf.h \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.h \
|
||||
$(TOP)\ext\intck\sqlite3intck.c \
|
||||
@@ -2351,6 +2384,7 @@ SHELL_DEP = \
|
||||
$(TOP)\ext\misc\ieee754.c \
|
||||
$(TOP)\ext\misc\memtrace.c \
|
||||
$(TOP)\ext\misc\pcachetrace.c \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
$(TOP)\ext\misc\series.c \
|
||||
$(TOP)\ext\misc\sha1.c \
|
||||
@@ -2377,7 +2411,7 @@ shell.c: $(SHELL_DEP) $(TOP)\tool\mkshellc.tcl $(JIM_TCLSH)
|
||||
$(JIM_TCLSH) $(TOP)\tool\mkshellc.tcl shell.c
|
||||
|
||||
zlib:
|
||||
pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) CFLAGS="$(ZLIBCFLAGS)" && popd
|
||||
pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd
|
||||
|
||||
# Rules to build the extension objects.
|
||||
#
|
||||
@@ -2491,8 +2525,6 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_CARRAY=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_PERCENTILE=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CKSUMVFS_STATIC=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STATIC_RANDOMJSON
|
||||
@@ -2501,9 +2533,9 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STRICT_SUBTYPE=1
|
||||
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
|
||||
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
|
||||
!IF $(USE_AMALGAMATION)==0
|
||||
TESTFIXTURE_SRC = $(TESTSRC) tclsqlite-ex.c $(TESTFIXTURE_SRC0)
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0)
|
||||
!ELSE
|
||||
TESTFIXTURE_SRC = $(TESTSRC) tclsqlite-ex.c $(TESTFIXTURE_SRC1)
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC1)
|
||||
!ENDIF
|
||||
|
||||
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
|
||||
@@ -2551,19 +2583,43 @@ coretestprogs: testfixture.exe sqlite3.exe
|
||||
|
||||
testprogs: $(TESTPROGS) srcck1.exe fuzzcheck.exe sessionfuzz.exe
|
||||
|
||||
fulltest: alltest fuzztest
|
||||
|
||||
alltest: $(TESTPROGS)
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\all.test $(TESTOPTS)
|
||||
|
||||
soaktest: $(TESTPROGS)
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\all.test -soak=1 $(TESTOPTS)
|
||||
|
||||
fulltestonly: $(TESTPROGS) fuzztest
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\full.test
|
||||
|
||||
queryplantest: testfixture.exe shell
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS)
|
||||
|
||||
fuzztest: fuzzcheck.exe
|
||||
.\fuzzcheck.exe $(FUZZDATA)
|
||||
|
||||
# Legacy testing target for third-party integrators. The SQLite
|
||||
# developers seldom use this target themselves. Instead
|
||||
# they use "nmake /f Makefile.msc devtest" which runs tests on
|
||||
# a standard set of options
|
||||
#
|
||||
# Legacy testing targets, no longer used by the developers and
|
||||
# now aliased to one of the commonly used testing targets.
|
||||
test: $(TESTPROGS) sourcetest fuzztest tcltest
|
||||
|
||||
# Minimal testing that runs in less than 3 minutes (on a fast machine)
|
||||
#
|
||||
quicktest: testfixture.exe sourcetest
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS)
|
||||
|
||||
# This is the common case. Run many tests that do not take too long,
|
||||
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
|
||||
#
|
||||
quicktest: devtest
|
||||
test: devtest
|
||||
fulltest: releasetest
|
||||
alltest: releasetest
|
||||
soaktest: releasetest
|
||||
fulltestonly: releasetest
|
||||
|
||||
# The veryquick.test TCL tests.
|
||||
#
|
||||
@@ -2588,22 +2644,6 @@ devtest: srctree-check sourcetest
|
||||
mdevtest:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest
|
||||
|
||||
# Rerun test cases that failed on the previous testrunner invocation
|
||||
#
|
||||
retest:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl retest
|
||||
|
||||
# Show all errors from the most reason testrunner invocation
|
||||
#
|
||||
errors:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl errors
|
||||
|
||||
# Show the status of the current testrunner invocation,
|
||||
# updated every couple of seconds
|
||||
#
|
||||
status:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl status -d 2
|
||||
|
||||
# Validate that various generated files in the source tree
|
||||
# are up-to-date.
|
||||
#
|
||||
@@ -2627,23 +2667,17 @@ smoketest: $(TESTPROGS)
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
|
||||
|
||||
# Measure the performance of floating-point conversions.
|
||||
#
|
||||
fp-speed-test: fp-speed-1.exe fp-speed-2.exe
|
||||
fp-speed-1 1000000
|
||||
fp-speed-2 1000000
|
||||
shelltest: $(TESTPROGS)
|
||||
.\testfixture.exe $(TOP)\test\permutations.test shell
|
||||
|
||||
shelltest:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl release shell
|
||||
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) tclsqlite-ex.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE_TCL_DEP)
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE_TCL_DEP)
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl -DINCLUDE_SQLITE3_C $(TOP)\tool\sqlite3_analyzer.c.in > $@
|
||||
|
||||
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
sqltclsh.c: sqlite3.c tclsqlite-ex.c $(TOP)\tool\sqltclsh.tcl $(TOP)\ext\misc\appendvfs.c $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in
|
||||
sqltclsh.c: sqlite3.c $(TOP)\src\tclsqlite.c $(TOP)\tool\sqltclsh.tcl $(TOP)\ext\misc\appendvfs.c $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh.exe: sqltclsh.c $(SHELL_CORE_DEP) $(LIBRESOBJS)
|
||||
@@ -2653,6 +2687,23 @@ sqltclsh.exe: sqltclsh.c $(SHELL_CORE_DEP) $(LIBRESOBJS)
|
||||
sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(SQLITE3C) $(TLIBS)
|
||||
|
||||
CHECKER_DEPS =\
|
||||
$(TOP)\tool\mkccode.tcl \
|
||||
sqlite3.c \
|
||||
$(TOP)\src\tclsqlite.c \
|
||||
$(TOP)\ext\repair\sqlite3_checker.tcl \
|
||||
$(TOP)\ext\repair\checkindex.c \
|
||||
$(TOP)\ext\repair\checkfreelist.c \
|
||||
$(TOP)\ext\misc\btreeinfo.c \
|
||||
$(TOP)\ext\repair\sqlite3_checker.c.in
|
||||
|
||||
sqlite3_checker.c: $(CHECKER_DEPS)
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\ext\repair\sqlite3_checker.c.in > $@
|
||||
|
||||
sqlite3_checker.exe: sqlite3_checker.c $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_checker.c \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
dbdump.exe: $(TOP)\ext\misc\dbdump.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -DDBDUMP_STANDALONE $(TOP)\ext\misc\dbdump.c $(SQLITE3C) \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS)
|
||||
@@ -2685,9 +2736,6 @@ showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) $(SQLITE3H)
|
||||
showshm.exe: $(TOP)\tool\showshm.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\showshm.c /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
showtmlog.exe: $(TOP)\tool\showtmlog.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\showtmlog.c /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
index_usage.exe: $(TOP)\tool\index_usage.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\tool\index_usage.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
@@ -2725,14 +2773,6 @@ speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\speedtest1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fp-speed-1.exe: $(TOP)\test\fp-speed-1.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\fp-speed-1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fp-speed-2.exe: $(TOP)\test\fp-speed-2.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\fp-speed-2.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
kvtest.exe: $(TOP)\test\kvtest.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(KV_COMPILE_OPTS) \
|
||||
$(TOP)\test\kvtest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
@@ -2764,135 +2804,6 @@ tcl-env:
|
||||
@echo JIM_TCLSH = $(JIM_TCLSH)
|
||||
@echo VISUALSTUDIOVERSION = $(VISUALSTUDIOVERSION)
|
||||
|
||||
env:
|
||||
@echo ALL_TCL_TARGETS = $(ALL_TCL_TARGETS)
|
||||
@echo API_ARMOR = $(API_ARMOR)
|
||||
@echo ASAN = $(ASAN)
|
||||
@echo BCC = $(BCC)
|
||||
@echo BUILD_ZLIB = $(BUILD_ZLIB)
|
||||
@echo CC = $(CC)
|
||||
@echo CCOPTS = $(CCOPTS)
|
||||
@echo CHECKER_DEPS = $(CHECKER_DEPS)
|
||||
@echo CORE_CCONV_OPTS = $(CORE_CCONV_OPTS)
|
||||
@echo CORE_COMPILE_OPTS = $(CORE_COMPILE_OPTS)
|
||||
@echo CORE_LINK_DEP = $(CORE_LINK_DEP)
|
||||
@echo CORE_LINK_OPTS = $(CORE_LINK_OPTS)
|
||||
@echo CRTLIBPATH = $(CRTLIBPATH)
|
||||
@echo CSC = $(CSC)
|
||||
@echo DBFUZZ_COMPILE_OPTS = $(DBFUZZ_COMPILE_OPTS)
|
||||
@echo DEBUG = $(DEBUG)
|
||||
@echo DYNAMIC_SHELL = $(DYNAMIC_SHELL)
|
||||
@echo EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS)
|
||||
@echo EXTHDR = $(EXTHDR)
|
||||
@echo EXTRA_SRC = $(EXTRA_SRC)
|
||||
@echo FOR_UWP = $(FOR_UWP)
|
||||
@echo FUZZCHECK_OPTS = $(FUZZCHECK_OPTS)
|
||||
@echo FUZZCHECK_SRC = $(FUZZCHECK_SRC)
|
||||
@echo FUZZDATA = $(FUZZDATA)
|
||||
@echo FUZZERSHELL_COMPILE_OPTS = $(FUZZERSHELL_COMPILE_OPTS)
|
||||
@echo HDR = $(HDR)
|
||||
@echo ICUDIR = $(ICUDIR)
|
||||
@echo ICUINCDIR = $(ICUINCDIR)
|
||||
@echo ICULIBDIR = $(ICULIBDIR)
|
||||
@echo JIM_TCLSH = $(JIM_TCLSH)
|
||||
@echo KV_COMPILE_OPTS = $(KV_COMPILE_OPTS)
|
||||
@echo LDFLAGS = $(LDFLAGS)
|
||||
@echo LD = $(LD)
|
||||
@echo LIBICU = $(LIBICU)
|
||||
@echo LIBOBJ = $(LIBOBJ)
|
||||
@echo LIBREADLINE = $(LIBREADLINE)
|
||||
@echo LIBRESOBJS = $(LIBRESOBJS)
|
||||
@echo LIBTCLPATH = $(LIBTCLPATH)
|
||||
@echo LIBTCLSTUB = $(LIBTCLSTUB)
|
||||
@echo LIBTCL = $(LIBTCL)
|
||||
@echo LTCOMPILE = $(LTCOMPILE)
|
||||
@echo LTLIB = $(LTLIB)
|
||||
@echo LTLIBOPTS = $(LTLIBOPTS)
|
||||
@echo LTLIBPATHS = $(LTLIBPATHS)
|
||||
@echo LTLIBS = $(LTLIBS)
|
||||
@echo LTLINK = $(LTLINK)
|
||||
@echo LTLINKOPTS = $(LTLINKOPTS)
|
||||
@echo LTRCOMPILE = $(LTRCOMPILE)
|
||||
@echo MEMDEBUG = $(MEMDEBUG)
|
||||
@echo MINIMAL_AMALGAMATION = $(MINIMAL_AMALGAMATION)
|
||||
@echo MPTESTER_COMPILE_OPTS = $(MPTESTER_COMPILE_OPTS)
|
||||
@echo NCC = $(NCC)
|
||||
@echo NCRTLIBPATH = $(NCRTLIBPATH)
|
||||
@echo NLTLIBPATHS = $(NLTLIBPATHS)
|
||||
@echo NO_LINEMACROS = $(NO_LINEMACROS)
|
||||
@echo NO_TCL = $(NO_TCL)
|
||||
@echo NO_WARN = $(NO_WARN)
|
||||
@echo NSDKLIBPATH = $(NSDKLIBPATH)
|
||||
@echo NUCRTLIBPATH = $(NUCRTLIBPATH)
|
||||
@echo OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS)
|
||||
@echo OPTIMIZATIONS = $(OPTIMIZATIONS)
|
||||
@echo OSSSHELL_SRC = $(OSSSHELL_SRC)
|
||||
@echo OSTRACE = $(OSTRACE)
|
||||
@echo RBU = $(RBU)
|
||||
@echo RCC = $(RCC)
|
||||
@echo RC = $(RC)
|
||||
@echo READLINE_FLAGS = $(READLINE_FLAGS)
|
||||
@echo REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS)
|
||||
@echo RSYNC_OPT = $(RSYNC_OPT)
|
||||
@echo RSYNC_SRC = $(RSYNC_SRC)
|
||||
@echo SESSION = $(SESSION)
|
||||
@echo SETLK_TIMEOUT = $(SETLK_TIMEOUT)
|
||||
@echo SHELL_CCONV_OPTS = $(SHELL_CCONV_OPTS)
|
||||
@echo SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS)
|
||||
@echo SHELL_CORE_DEP = $(SHELL_CORE_DEP)
|
||||
@echo SHELL_CORE_LIB = $(SHELL_CORE_LIB)
|
||||
@echo SHELL_CORE_SRC = $(SHELL_CORE_SRC)
|
||||
@echo SHELL_DEP = $(SHELL_DEP)
|
||||
@echo SHELL_LINK_OPTS = $(SHELL_LINK_OPTS)
|
||||
@echo SPLIT_AMALGAMATION = $(SPLIT_AMALGAMATION)
|
||||
@echo SQLITETCLDECLSH = $(SQLITETCLDECLSH)
|
||||
@echo SQLITE_TCL_DEP = $(SQLITE_TCL_DEP)
|
||||
@echo SQLITETCLH = $(SQLITETCLH)
|
||||
@echo SRC = $(SRC)
|
||||
@echo STATICALLY_LINK_TCL = $(STATICALLY_LINK_TCL)
|
||||
@echo ST_COMPILE_OPTS = $(ST_COMPILE_OPTS)
|
||||
@echo STORELIBPATH = $(STORELIBPATH)
|
||||
@echo SYMBOLS = $(SYMBOLS)
|
||||
@echo TCC = $(TCC)
|
||||
@echo TCLDIR = $(TCLDIR)
|
||||
@echo TCLINCDIR = $(TCLINCDIR)
|
||||
@echo TCLLIBDIR = $(TCLLIBDIR)
|
||||
@echo TCLLIBPATHS = $(TCLLIBPATHS)
|
||||
@echo TCLLIBS = $(TCLLIBS)
|
||||
@echo TCLSH_CMD = $(TCLSH_CMD)
|
||||
@echo TCLSQLITEEX = $(TCLSQLITEEX)
|
||||
@echo TCLSUFFIX = $(TCLSUFFIX)
|
||||
@echo TCLVERSION = $(TCLVERSION)
|
||||
@echo TEST_CCONV_OPTS = $(TEST_CCONV_OPTS)
|
||||
@echo TESTEXT = $(TESTEXT)
|
||||
@echo TESTFIXTURE_DEP = $(TESTFIXTURE_DEP)
|
||||
@echo TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS)
|
||||
@echo TESTFIXTURE_SRC = $(TESTFIXTURE_SRC)
|
||||
@echo TESTOPTS = $(TESTOPTS)
|
||||
@echo TESTPROGS = $(TESTPROGS)
|
||||
@echo TESTSRC = $(TESTSRC)
|
||||
@echo TLIBS = $(TLIBS)
|
||||
@echo TOP = $(TOP)
|
||||
@echo UCRTLIBPATH = $(UCRTLIBPATH)
|
||||
@echo USE_AMALGAMATION = $(USE_AMALGAMATION)
|
||||
@echo USE_CRT_DLL = $(USE_CRT_DLL)
|
||||
@echo USE_FATAL_WARN = $(USE_FATAL_WARN)
|
||||
@echo USE_FULLWARN = $(USE_FULLWARN)
|
||||
@echo USE_ICU = $(USE_ICU)
|
||||
@echo USE_LISTINGS = $(USE_LISTINGS)
|
||||
@echo USE_NATIVE_LIBPATHS = $(USE_NATIVE_LIBPATHS)
|
||||
@echo USE_RC = $(USE_RC)
|
||||
@echo USE_RUNTIME_CHECKS = $(USE_RUNTIME_CHECKS)
|
||||
@echo USE_SEH = $(USE_SEH)
|
||||
@echo USE_STDCALL = $(USE_STDCALL)
|
||||
@echo USE_ZLIB = $(USE_ZLIB)
|
||||
@echo XCOMPILE = $(XCOMPILE)
|
||||
@echo ZLIBCFLAGS = $(ZLIBCFLAGS)
|
||||
@echo ZLIBDIR = $(ZLIBDIR)
|
||||
@echo ZLIBINCDIR = $(ZLIBINCDIR)
|
||||
@echo ZLIBLIBDIR = $(ZLIBLIBDIR)
|
||||
@echo ZLIBLIB = $(ZLIBLIB)
|
||||
|
||||
moreclean: clean
|
||||
del /Q $(SQLITE3C) $(SQLITE3H) 2>NUL
|
||||
# <</mark>>
|
||||
@@ -2922,7 +2833,6 @@ clean:
|
||||
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL
|
||||
del /Q changeset.exe 2>NUL
|
||||
del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
|
||||
del /Q fp-speed-1.exe fp-speed-2.exe 2>NUL
|
||||
del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
|
||||
del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL
|
||||
del /Q sqlite3rc.h 2>NUL
|
||||
@@ -2937,5 +2847,4 @@ clean:
|
||||
del /Q fts5.* fts5parse.* 2>NUL
|
||||
del /q src-verify.exe 2>NUL
|
||||
del /q jimsh.exe jimsh0.exe 2>NUL
|
||||
-$(TCLSH_CMD) test/testrunner.tcl clean
|
||||
# <</mark>>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<h1 align="center">SQLite Source Repository</h1>
|
||||
|
||||
This repository contains the complete source code for the
|
||||
[SQLite database engine](https://sqlite.org/) going back
|
||||
to 2000-05-29. The tree includes many tests and some
|
||||
documentation, though additional tests and most documentation
|
||||
are managed separately.
|
||||
[SQLite database engine](https://sqlite.org/), including
|
||||
many test scripts. However, other test scripts
|
||||
and most of the documentation are managed separately.
|
||||
|
||||
See the [on-line documentation](https://sqlite.org/) for more information
|
||||
about what SQLite is and how it works from a user's perspective. This
|
||||
@@ -54,34 +53,41 @@ then no longer be fully in the public domain.
|
||||
|
||||
## Obtaining The SQLite Source Code
|
||||
|
||||
Source code tarballs or ZIP archives are available at:
|
||||
If you do not want to use Fossil, you can download tarballs or ZIP
|
||||
archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
|
||||
|
||||
* [Latest trunk check-in](https://sqlite.org/src/rchvdwnld/trunk).
|
||||
* Latest trunk check-in as
|
||||
[Tarball](https://sqlite.org/src/tarball/sqlite.tar.gz),
|
||||
[ZIP-archive](https://sqlite.org/src/zip/sqlite.zip), or
|
||||
[SQLite-archive](https://sqlite.org/src/sqlar/sqlite.sqlar).
|
||||
|
||||
* [Latest release](https://sqlite.org/src/rchvdwnld/release)
|
||||
* Latest release as
|
||||
[Tarball](https://sqlite.org/src/tarball/sqlite.tar.gz?r=release),
|
||||
[ZIP-archive](https://sqlite.org/src/zip/sqlite.zip?r=release), or
|
||||
[SQLite-archive](https://sqlite.org/src/sqlar/sqlite.sqlar?r=release).
|
||||
|
||||
* For other check-ins, browse the
|
||||
[project timeline](https://sqlite.org/src/timeline?y=ci) and
|
||||
click on the check-in hash of the check-in you want to download.
|
||||
On the resulting "info" page, click one of the options to the
|
||||
right of the "**Downloads:**" label in the "**Overview**" section
|
||||
near the top.
|
||||
* For other check-ins, substitute an appropriate branch name or
|
||||
tag or hash prefix in place of "release" in the URLs of the previous
|
||||
bullet. Or browse the [timeline](https://sqlite.org/src/timeline)
|
||||
to locate the check-in desired, click on its information page link,
|
||||
then click on the "Tarball" or "ZIP Archive" links on the information
|
||||
page.
|
||||
|
||||
To access sources directly using [Fossil](https://fossil-scm.org/home),
|
||||
first install Fossil version 2.0 or later.
|
||||
Source tarballs and precompiled binaries for Fossil are available at
|
||||
Source tarballs and precompiled binaries available at
|
||||
<https://fossil-scm.org/home/uv/download.html>. Fossil is
|
||||
a stand-alone program. To install, simply download or build the single
|
||||
executable file and put that file someplace on your $PATH or %PATH%.
|
||||
executable file and put that file someplace on your $PATH.
|
||||
Then run commands like this:
|
||||
|
||||
mkdir -p ~/sqlite
|
||||
cd ~/sqlite
|
||||
fossil open https://sqlite.org/src
|
||||
|
||||
The initial "fossil open" command will take two or three minutes. Afterwards,
|
||||
you can do fast, bandwidth-efficient updates to whatever versions of SQLite you
|
||||
like. Some examples:
|
||||
The "fossil open" command will take two or three minutes. Afterwards,
|
||||
you can do fast, bandwidth-efficient updates to the whatever versions
|
||||
of SQLite you like. Some examples:
|
||||
|
||||
fossil update trunk ;# latest trunk check-in
|
||||
fossil update release ;# latest official release
|
||||
@@ -97,21 +103,19 @@ the build products. It is recommended, but not required, that the
|
||||
build directory be separate from the source directory. Cd into the
|
||||
build directory and then from the build directory run the configure
|
||||
script found at the root of the source tree. Then run "make".
|
||||
See the [compile-for-unix.md](doc/compile-for-unix.md) document for
|
||||
more detail.
|
||||
|
||||
For example:
|
||||
|
||||
apt install gcc make tcl-dev ;# Install the necessary build tools
|
||||
apt install gcc make tcl-dev ;# Make sure you have all the necessary build tools
|
||||
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
|
||||
mkdir bld ;# Build happens in a sibling directory
|
||||
mkdir bld ;# Build will occur in a sibling directory
|
||||
cd bld ;# Change to the build directory
|
||||
../sqlite/configure ;# Run the configure script
|
||||
make sqlite3 ;# The "sqlite3" command-line tool
|
||||
make sqlite3.c ;# The "amalgamation" source file
|
||||
make sqldiff ;# The "sqldiff" command-line tool
|
||||
#### Targets below require tcl-dev ####
|
||||
make tclextension-install ;# Install the SQLite TCL extension
|
||||
make sqlite3 ;# Builds the "sqlite3" command-line tool
|
||||
make sqlite3.c ;# Build the "amalgamation" source file
|
||||
make sqldiff ;# Builds the "sqldiff" command-line tool
|
||||
# Makefile targets below this point require tcl-dev
|
||||
make tclextension-install ;# Build and install the SQLite TCL extension
|
||||
make devtest ;# Run development tests
|
||||
make releasetest ;# Run full release tests
|
||||
make sqlite3_analyzer ;# Builds the "sqlite3_analyzer" tool
|
||||
@@ -119,15 +123,14 @@ For example:
|
||||
See the makefile for additional targets. For debugging builds, the
|
||||
core developers typically run "configure" with options like this:
|
||||
|
||||
../sqlite/configure --all --debug CFLAGS='-O0 -g'
|
||||
../sqlite/configure --enable-all --enable-debug CFLAGS='-O0 -g'
|
||||
|
||||
For release builds, the core developers usually do:
|
||||
|
||||
../sqlite/configure --all
|
||||
../sqlite/configure --enable-all
|
||||
|
||||
Core deliverables (sqlite3.c, sqlite3) can be built without a TCL, but
|
||||
many makefile targets require a "tclsh" TCL interpreter version 8.6
|
||||
or later. The "tclextension-install" target and the test targets that follow
|
||||
Almost all makefile targets require a "tclsh" TCL interpreter version 8.6 or
|
||||
later. The "tclextension-install" target and the test targets that follow
|
||||
all require TCL development libraries too. ("apt install tcl-dev"). It is
|
||||
helpful, but is not required, to install the SQLite TCL extension (the
|
||||
"tclextension-install" target) prior to running tests. The "releasetest"
|
||||
@@ -137,20 +140,19 @@ On "make" command-lines, one can add "OPTIONS=..." to specify additional
|
||||
compile-time options over and above those set by ./configure. For example,
|
||||
to compile with the SQLITE_OMIT_DEPRECATED compile-time option, one could say:
|
||||
|
||||
./configure --all
|
||||
./configure --enable-all
|
||||
make OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3
|
||||
|
||||
The configure script uses [autosetup](https://msteveb.github.io/autosetup/).
|
||||
If the configure script does not work out for you, there is a generic
|
||||
makefile named "Makefile.linux-gcc" in the top directory of the source tree
|
||||
that you can copy and edit to suit your needs. Comments on the generic
|
||||
makefile show what changes are needed.
|
||||
The configure script uses autoconf 2.61 and libtool. If the configure
|
||||
script does not work out for you, there is a generic makefile named
|
||||
"Makefile.linux-gcc" in the top directory of the source tree that you
|
||||
can copy and edit to suit your needs. Comments on the generic makefile
|
||||
show what changes are needed.
|
||||
|
||||
## Compiling for Windows Using MSVC
|
||||
|
||||
On Windows, everything can be compiled with MSVC.
|
||||
You will also need a working installation of TCL if you want to run tests,
|
||||
though TCL is not required if you just want to build SQLite itself.
|
||||
You will also need a working installation of TCL.
|
||||
See the [compile-for-windows.md](doc/compile-for-windows.md) document for
|
||||
additional information about how to install MSVC and TCL and configure your
|
||||
build environment.
|
||||
@@ -160,25 +162,24 @@ TCL library, using a command like this:
|
||||
|
||||
set TCLDIR=c:\Tcl
|
||||
|
||||
SQLite itself does not contain any TCL code, but it does use TCL to run
|
||||
tests. You may need to install TCL development libraries in order to
|
||||
successfully complete some makefile targets. It is helpful, but is not
|
||||
required, to install the SQLite TCL extension (the "tclextension-install"
|
||||
target) prior to running tests.
|
||||
SQLite uses "tclsh.exe" as part of the build process, and so that
|
||||
program will need to be somewhere on your %PATH%. SQLite itself
|
||||
does not contain any TCL code, but it does use TCL to help with the
|
||||
build process and to run tests. You may need to install TCL development
|
||||
libraries in order to successfully complete some makefile targets.
|
||||
It is helpful, but is not required, to install the SQLite TCL extension
|
||||
(the "tclextension-install" target) prior to running tests.
|
||||
|
||||
The source tree contains a "make.bat" file that allows the same "make"
|
||||
commands of Unix to work on Windows. In the following, you can substitute
|
||||
"nmake /f Makefile.msc" in place of "make", if you prefer to avoid this BAT
|
||||
file:
|
||||
Build using Makefile.msc. Example:
|
||||
|
||||
make sqlite3.exe
|
||||
make sqlite3.c
|
||||
make sqldiff.exe
|
||||
#### Targets below require TCL development libraries ####
|
||||
make tclextension-install
|
||||
make devtest
|
||||
make releasetest
|
||||
make sqlite3_analyzer.exe
|
||||
nmake /f Makefile.msc sqlite3.exe
|
||||
nmake /f Makefile.msc sqlite3.c
|
||||
nmake /f Makefile.msc sqldiff.exe
|
||||
# Makefile targets below this point require TCL development libraries
|
||||
nmake /f Makefile.msc tclextension-install
|
||||
nmake /f Makefile.msc devtest
|
||||
nmake /f Makefile.msc releasetest
|
||||
nmake /f Makefile.msc sqlite3_analyzer.exe
|
||||
|
||||
There are many other makefile targets. See comments in Makefile.msc for
|
||||
details.
|
||||
@@ -186,7 +187,7 @@ details.
|
||||
As with the unix Makefile, the OPTIONS=... argument can be passed on the nmake
|
||||
command-line to enable new compile-time options. For example:
|
||||
|
||||
make OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3.exe
|
||||
nmake /f Makefile.msc OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3.exe
|
||||
|
||||
## Source Tree Map
|
||||
|
||||
@@ -199,7 +200,8 @@ command-line to enable new compile-time options. For example:
|
||||
* **test/** - This directory and its subdirectories contains code used
|
||||
for testing. Files that end in "`.test`" are TCL scripts that run
|
||||
tests using an augmented TCL interpreter named "testfixture". Use
|
||||
a command like "`make testfixture`" to build that
|
||||
a command like "`make testfixture`" (unix) or
|
||||
"`nmake /f Makefile.msc testfixture.exe`" (windows) to build that
|
||||
augmented TCL interpreter, then run individual tests using commands like
|
||||
"`testfixture test/main.test`". This test/ subdirectory also contains
|
||||
additional C code modules and scripts for other kinds of testing.
|
||||
@@ -381,11 +383,10 @@ implementation. It will not be the easiest library in the world to hack.
|
||||
(and some other test programs too) is built and run when you type
|
||||
"make test".
|
||||
|
||||
* **VERSION**, **manifest**, **manifest.tags**, and **manifest.uuid** -
|
||||
These files define the current SQLite version number. The "VERSION" file
|
||||
is human generated, but the "manifest", "manifest.tags", and
|
||||
"manifest.uuid" files are automatically generated by the
|
||||
[Fossil version control system](https://fossil-scm.org/).
|
||||
* **VERSION**, **manifest**, and **manifest.uuid** - These files define
|
||||
the current SQLite version number. The "VERSION" file is human generated,
|
||||
but the "manifest" and "manifest.uuid" files are automatically generated
|
||||
by the [Fossil version control system](https://fossil-scm.org/).
|
||||
|
||||
There are many other source files. Each has a succinct header comment that
|
||||
describes its purpose and role within the larger system.
|
||||
@@ -411,6 +412,10 @@ makefile:
|
||||
|
||||
> make verify-source
|
||||
|
||||
Or on windows:
|
||||
|
||||
> nmake /f Makefile.msc verify-source
|
||||
|
||||
Using the makefile to verify source integrity is good for detecting
|
||||
accidental changes to the source tree, but malicious changes could be
|
||||
hidden by also modifying the makefiles.
|
||||
|
||||
@@ -222,12 +222,9 @@ install: install-lib
|
||||
# Flags to link the shell app either directly against sqlite3.c
|
||||
# (ENABLE_STATIC_SHELL==1) or libsqlite3.so (ENABLE_STATIC_SHELL==0).
|
||||
#
|
||||
# Maintenance reminder: placement of $(LDFLAGS) is more relevant for
|
||||
# some platforms than others:
|
||||
# https://sqlite.org/forum/forumpost/d80ecdaddd
|
||||
ENABLE_STATIC_SHELL = @ENABLE_STATIC_SHELL@
|
||||
sqlite3-shell-link-flags.1 = $(TOP)/sqlite3.c $(LDFLAGS) $(LDFLAGS.libsqlite3)
|
||||
sqlite3-shell-link-flags.0 = $(LDFLAGS) -L. -lsqlite3 $(LDFLAGS.zlib) $(LDFLAGS.math)
|
||||
sqlite3-shell-link-flags.1 = $(TOP)/sqlite3.c $(LDFLAGS.libsqlite3)
|
||||
sqlite3-shell-link-flags.0 = -L. -lsqlite3 $(LDFLAGS.zlib) $(LDFLAGS.math)
|
||||
sqlite3-shell-deps.1 = $(TOP)/sqlite3.c
|
||||
sqlite3-shell-deps.0 = $(libsqlite3.DLL)
|
||||
#
|
||||
@@ -248,7 +245,7 @@ sqlite3$(T.exe): $(TOP)/shell.c $(sqlite3-shell-deps.$(ENABLE_STATIC_SHELL))
|
||||
$(sqlite3-shell-static.flags.$(STATIC_CLI_SHELL)) \
|
||||
-I. $(OPT_FEATURE_FLAGS) $(SHELL_OPT) \
|
||||
$(CFLAGS) $(CFLAGS.readline) $(CFLAGS.icu) \
|
||||
$(LDFLAGS.readline)
|
||||
$(LDFLAGS) $(LDFLAGS.readline)
|
||||
|
||||
sqlite3$(T.exe)-1:
|
||||
sqlite3$(T.exe)-0: sqlite3$(T.exe)
|
||||
@@ -282,7 +279,7 @@ DIST_FILES := \
|
||||
README.txt VERSION \
|
||||
auto.def autosetup configure tea \
|
||||
sqlite3.h sqlite3.c shell.c sqlite3ext.h \
|
||||
Makefile.in Makefile.msc Makefile.fallback make.bat \
|
||||
Makefile.in Makefile.msc Makefile.fallback \
|
||||
sqlite3.rc sqlite3rc.h Replace.cs \
|
||||
sqlite3.pc.in sqlite3.1
|
||||
|
||||
|
||||
+90
-17
@@ -101,6 +101,13 @@ NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to use the library paths and other options necessary for
|
||||
# Windows Phone 8.1.
|
||||
#
|
||||
!IFNDEF USE_WP81_OPTS
|
||||
USE_WP81_OPTS = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to split the SQLite amalgamation file into chunks to
|
||||
# be used for debugging with Visual Studio.
|
||||
#
|
||||
@@ -149,6 +156,14 @@ USE_NATIVE_LIBPATHS = 0
|
||||
USE_RC = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to compile binaries suitable for the WinRT environment.
|
||||
# This setting does not apply to any binaries that require Tcl to operate
|
||||
# properly (i.e. the text fixture, etc).
|
||||
#
|
||||
!IFNDEF FOR_WINRT
|
||||
FOR_WINRT = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to compile binaries suitable for the UWP environment.
|
||||
# This setting does not apply to any binaries that require Tcl to operate
|
||||
# properly (i.e. the text fixture, etc).
|
||||
@@ -312,7 +327,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_CARRAY=1
|
||||
!ENDIF
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
!ENDIF
|
||||
@@ -335,7 +349,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
|
||||
# Always enable math functions on Windows
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PERCENTILE
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
@@ -548,14 +561,10 @@ RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) $(RCOPTS) $(RCCOPTS)
|
||||
!IF "$(PLATFORM)"=="x86"
|
||||
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
|
||||
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
|
||||
|
||||
|
||||
!ELSE
|
||||
!IFNDEF PLATFORM
|
||||
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
|
||||
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
|
||||
|
||||
|
||||
!ELSE
|
||||
CORE_CCONV_OPTS =
|
||||
SHELL_CCONV_OPTS =
|
||||
@@ -656,6 +665,18 @@ SHELL_LINK_OPTS = $(SHELL_CORE_LIB)
|
||||
TCC = $(TCC) -FAcs
|
||||
!ENDIF
|
||||
|
||||
# When compiling the library for use in the WinRT environment,
|
||||
# the following compile-time options must be used as well to
|
||||
# disable use of Win32 APIs that are not available and to enable
|
||||
# use of Win32 APIs that are specific to Windows 8 and/or WinRT.
|
||||
#
|
||||
!IF $(FOR_WINRT)!=0
|
||||
TCC = $(TCC) -DSQLITE_OS_WINRT=1
|
||||
RCC = $(RCC) -DSQLITE_OS_WINRT=1
|
||||
TCC = $(TCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
|
||||
RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
|
||||
!ENDIF
|
||||
|
||||
# C compiler options for the Windows 10 platform (needs MSVC 2015).
|
||||
#
|
||||
!IF $(FOR_WIN10)!=0
|
||||
@@ -668,29 +689,35 @@ BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
|
||||
# USE_CRT_DLL option is set to force dynamically linking to the
|
||||
# MSVC runtime library.
|
||||
#
|
||||
!IF $(USE_CRT_DLL)!=0
|
||||
!IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
|
||||
!IF $(DEBUG)>1
|
||||
TCC = $(TCC) -MDd
|
||||
BCC = $(BCC) -MDd
|
||||
ZLIBCFLAGS = -nologo -MDd -W3 -O2 -Oy- -Zi
|
||||
!ELSE
|
||||
TCC = $(TCC) -MD
|
||||
BCC = $(BCC) -MD
|
||||
ZLIBCFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi
|
||||
!ENDIF
|
||||
!ELSE
|
||||
!IF $(DEBUG)>1
|
||||
TCC = $(TCC) -MTd
|
||||
BCC = $(BCC) -MTd
|
||||
ZLIBCFLAGS = -nologo -MTd -W3 -O2 -Oy- -Zi
|
||||
!ELSE
|
||||
TCC = $(TCC) -MT
|
||||
BCC = $(BCC) -MT
|
||||
ZLIBCFLAGS = -nologo -MT -W3 -O2 -Oy- -Zi
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
|
||||
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
|
||||
# Omitting the define will cause extra debugging code to be inserted and
|
||||
# includes extra comments when "EXPLAIN stmt" is used.
|
||||
#
|
||||
!IF $(DEBUG)==0
|
||||
TCC = $(TCC) -DNDEBUG
|
||||
BCC = $(BCC) -DNDEBUG
|
||||
RCC = $(RCC) -DNDEBUG
|
||||
!ENDIF
|
||||
|
||||
!IF $(DEBUG)>0 || $(API_ARMOR)!=0 || $(FOR_WIN10)!=0
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR=1
|
||||
RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
|
||||
@@ -880,6 +907,56 @@ LTLINKOPTS = /NOLOGO
|
||||
LTLIBOPTS = /NOLOGO
|
||||
!ENDIF
|
||||
|
||||
# When compiling for use in the WinRT environment, the following
|
||||
# linker option must be used to mark the executable as runnable
|
||||
# only in the context of an application container.
|
||||
#
|
||||
!IF $(FOR_WINRT)!=0
|
||||
LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER
|
||||
!IF "$(VISUALSTUDIOVERSION)"=="12.0" || "$(VISUALSTUDIOVERSION)"=="14.0"
|
||||
!IFNDEF STORELIBPATH
|
||||
!IF "$(PLATFORM)"=="x86"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store
|
||||
!ELSEIF "$(PLATFORM)"=="x64"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store\amd64
|
||||
!ELSEIF "$(PLATFORM)"=="ARM"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store\arm
|
||||
!ELSE
|
||||
STORELIBPATH = $(CRTLIBPATH)\store
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
STORELIBPATH = $(STORELIBPATH:\\=\)
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(STORELIBPATH)"
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# When compiling for Windows Phone 8.1, an extra library path is
|
||||
# required.
|
||||
#
|
||||
!IF $(USE_WP81_OPTS)!=0
|
||||
!IFNDEF WP81LIBPATH
|
||||
!IF "$(PLATFORM)"=="x86"
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
|
||||
!ELSEIF "$(PLATFORM)"=="ARM"
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\ARM
|
||||
!ELSE
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# When compiling for Windows Phone 8.1, some extra linker options
|
||||
# are also required.
|
||||
#
|
||||
!IF $(USE_WP81_OPTS)!=0
|
||||
!IFDEF WP81LIBPATH
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
|
||||
!ENDIF
|
||||
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
|
||||
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
|
||||
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
|
||||
!ENDIF
|
||||
|
||||
# When compiling for UWP or the Windows 10 platform, some extra linker
|
||||
# options are also required.
|
||||
#
|
||||
@@ -903,9 +980,9 @@ LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
|
||||
# If either debugging or symbols are enabled, enable PDBs.
|
||||
#
|
||||
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
|
||||
LDFLAGS = /NODEFAULTLIB:msvcrt /DEBUG $(LDOPTS)
|
||||
LDFLAGS = /DEBUG $(LDOPTS)
|
||||
!ELSE
|
||||
LDFLAGS = /NODEFAULTLIB:msvcrt $(LDOPTS)
|
||||
LDFLAGS = $(LDOPTS)
|
||||
!ENDIF
|
||||
|
||||
|
||||
@@ -938,10 +1015,8 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_PERCENTILE=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
|
||||
!ENDIF
|
||||
|
||||
@@ -990,8 +1065,6 @@ $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLIT
|
||||
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
|
||||
|
||||
|
||||
tclsqlite-ex.c:
|
||||
|
||||
# Rule to build the amalgamation
|
||||
#
|
||||
sqlite3.lo: $(SQLITE3C)
|
||||
|
||||
@@ -119,7 +119,7 @@ TCLLIBDIR = @TCLLIBDIR@
|
||||
# typically come from the ./configure command-line invocation).
|
||||
#
|
||||
CFLAGS.configure = @SH_CFLAGS@ @TEAISH_CFLAGS@ @CFLAGS@ @CPPFLAGS@ $(TCL_INCLUDE_SPEC)
|
||||
CFLAGS.configure += -DUSE_TCL_STUBS=@TEAISH_USE_STUBS@
|
||||
#CFLAGS.configure += -DUSE_TCL_STUBS=1
|
||||
|
||||
#
|
||||
# LDFLAGS.configure = LDFLAGS as known at configure-time.
|
||||
@@ -153,7 +153,6 @@ tx.src = @TEAISH_EXT_SRC@
|
||||
# gets set up via the configure script.
|
||||
#
|
||||
tx.CFLAGS =
|
||||
tx.CPPFLAGS =
|
||||
|
||||
#
|
||||
# tx.LDFLAGS is typically set by teaish.make, whereas TEAISH_LDFLAGS
|
||||
@@ -219,7 +218,7 @@ config.log: @TEAISH_TEST_TCL_IN@
|
||||
# CC variant for compiling Tcl-using sources.
|
||||
#
|
||||
CC.tcl = \
|
||||
$(CC) -o $@ $(CFLAGS.configure) $(CFLAGS) $(tx.CFLAGS) $(tx.CPPFLAGS)
|
||||
$(CC) -o $@ $(CFLAGS.configure) $(CFLAGS) $(tx.CFLAGS)
|
||||
|
||||
#
|
||||
# CC variant for linking $(tx.src) into an extension DLL. Note that
|
||||
|
||||
+1
-11
@@ -375,11 +375,6 @@ configure process, and check it in.
|
||||
Patching Autosetup for Project-local Changes
|
||||
------------------------------------------------------------------------
|
||||
|
||||
The autosetup files require the following patches after updating
|
||||
from their upstream sources:
|
||||
|
||||
### `--debug` flag
|
||||
|
||||
Autosetup reserves the flag name **`--debug`** for its own purposes,
|
||||
and its own special handling of `--enable-...` flags makes `--debug`
|
||||
an alias for `--enable-debug`. As this project has a long history of
|
||||
@@ -393,11 +388,6 @@ If autosetup is upgraded and this patch is _not_ applied the invoking
|
||||
`./configure` will fail loudly because of the declaration of the
|
||||
`debug` flag in `auto.def` - duplicated flags are not permitted.
|
||||
|
||||
### Fail on `malloc()` error
|
||||
|
||||
See [check-in 72c8a5b94cdf5d](/info/72c8a5b94cdf5d).
|
||||
|
||||
|
||||
<a name="branch-customization"></a>
|
||||
Branch-specific Customization
|
||||
========================================================================
|
||||
@@ -461,4 +451,4 @@ all other significant processing.
|
||||
[sqlite-config.tcl]: /file/autosetup/sqlite-config.tcl
|
||||
[Makefile.in]: /file/Makefile.in
|
||||
[main.mk]: /file/main.mk
|
||||
[JimTCL]: https://msteveb.github.io/jimtcl/
|
||||
[JimTCL]: https://jim.tcl.tk
|
||||
|
||||
+7
-11
@@ -406,8 +406,8 @@ proc options-add {opts} {
|
||||
# Find the corresponding value in the user options
|
||||
# and set the default if necessary
|
||||
if {[string match "-*" $opt]} {
|
||||
# We no longer support documentation-only options, like "-C <dir>"
|
||||
autosetup-error "Option $opt is not supported"
|
||||
# This is a documentation-only option, like "-C <dir>"
|
||||
set opthelp $opt
|
||||
} elseif {$colon eq ""} {
|
||||
# Boolean option
|
||||
lappend autosetup(options) $name
|
||||
@@ -1611,7 +1611,7 @@ proc autosetup_output_block {type lines} {
|
||||
# Generate a command reference from inline documentation
|
||||
proc automf_command_reference {} {
|
||||
lappend files $::autosetup(prog)
|
||||
lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/{*/*.tcl,*.tcl}]]
|
||||
lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
|
||||
|
||||
# We want to process all non-module files before module files
|
||||
# and then modules in alphabetical order.
|
||||
@@ -2124,7 +2124,7 @@ if {$autosetup(istcl)} {
|
||||
set frame [info frame -$i]
|
||||
if {[dict exists $frame file]} {
|
||||
# We don't need proc, so use ""
|
||||
lappend stacktrace "" [dict get $frame file] [dict get $frame line] ""
|
||||
lappend stacktrace "" [dict get $frame file] [dict get $frame line]
|
||||
}
|
||||
}
|
||||
return $stacktrace
|
||||
@@ -2181,12 +2181,8 @@ proc error-location {msg} {
|
||||
if {$::autosetup(debug)} {
|
||||
return -code error $msg
|
||||
}
|
||||
set vars {p f l cmd}
|
||||
if {!$::autosetup(istcl) && ![dict exists $::tcl_platform stackFormat]} {
|
||||
# Older versions of Jim had a 3 element stacktrace
|
||||
set vars {p f l}
|
||||
}
|
||||
foreach $vars [stacktrace] {
|
||||
# Search back through the stack trace for the first error in a .def file
|
||||
foreach {p f l} [stacktrace] {
|
||||
if {[string match *.def $f]} {
|
||||
return "[relative-path $f]:$l: Error: $msg"
|
||||
}
|
||||
@@ -2538,7 +2534,7 @@ if {[catch {main $argv} msg opts] == 1} {
|
||||
show-notices
|
||||
autosetup-full-error [error-dump $msg $opts $autosetup(debug)]
|
||||
if {!$autosetup(debug)} {
|
||||
puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
|
||||
puts stderr "Try: '[file tail $autosetup(exe)] --autosetup-debug' for a full stack trace"
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -89,15 +89,13 @@ switch -glob -- [get-define host] {
|
||||
define SH_SOPREFIX -Wl,-h,
|
||||
}
|
||||
}
|
||||
*-*-hpux* {
|
||||
define SHOBJ_CFLAGS +z
|
||||
*-*-hpux {
|
||||
# XXX: These haven't been tested
|
||||
define SHOBJ_CFLAGS "+O3 +z"
|
||||
define SHOBJ_LDFLAGS -b
|
||||
define SH_CFLAGS +z
|
||||
define SH_LDFLAGS -b
|
||||
define SH_LINKFLAGS -Wl,+s
|
||||
define SH_LINKRPATH "-Wl,+b -Wl,%s"
|
||||
define SH_SOPREFIX -Wl,+h,
|
||||
define STRIPLIBFLAGS -Wl,-s
|
||||
define LD_LIBRARY_PATH SHLIB_PATH
|
||||
}
|
||||
*-*-haiku {
|
||||
define SHOBJ_CFLAGS ""
|
||||
|
||||
+948
-1622
File diff suppressed because it is too large
Load Diff
+13
-56
@@ -557,7 +557,7 @@ proc proj-opt-define-bool {args} {
|
||||
if {$invert} {
|
||||
set rc [expr {!$rc}]
|
||||
}
|
||||
msg-result [string map {0 no 1 yes} $rc]
|
||||
msg-result $rc
|
||||
define $defName $rc
|
||||
return $rc
|
||||
}
|
||||
@@ -706,20 +706,11 @@ proc proj-file-write {args} {
|
||||
}
|
||||
|
||||
#
|
||||
# @proj-check-compile-commands ?-assume-for-clang? ?configFlag?
|
||||
# @proj-check-compile-commands ?configFlag?
|
||||
#
|
||||
# Checks the compiler for compile_commands.json support. If
|
||||
# $configFlag is not empty then it is assumed to be the name of an
|
||||
# autosetup boolean config which controls whether to run/skip this
|
||||
# check.
|
||||
#
|
||||
# If -assume-for-clang is provided and $configFlag is not empty and CC
|
||||
# matches *clang* and no --$configFlag was explicitly provided to the
|
||||
# configure script then behave as if --$configFlag had been provided.
|
||||
# To disable that assumption, either don't pass -assume-for-clang or
|
||||
# pass --$configFlag=0 to the configure script. (The reason for this
|
||||
# behavior is that clang supports compile-commands but some other
|
||||
# compilers report false positives with these tests.)
|
||||
# Checks the compiler for compile_commands.json support. If passed an
|
||||
# argument it is assumed to be the name of an autosetup boolean config
|
||||
# which controls whether to run/skip this check.
|
||||
#
|
||||
# Returns 1 if supported, else 0, and defines HAVE_COMPILE_COMMANDS to
|
||||
# that value. Defines MAKE_COMPILATION_DB to "yes" if supported, "no"
|
||||
@@ -727,38 +718,12 @@ proc proj-file-write {args} {
|
||||
# HAVE_COMPILE_COMMANDS is preferred.
|
||||
#
|
||||
# ACHTUNG: this test has a long history of false positive results
|
||||
# because of compilers reacting differently to the -MJ flag. Because
|
||||
# of this, it is recommended that this support be an opt-in feature,
|
||||
# rather than an on-by-default default one. That is: in the
|
||||
# configure script define the option as
|
||||
# {--the-flag-name=0 => {Enable ....}}
|
||||
# because of compilers reacting differently to the -MJ flag.
|
||||
#
|
||||
proc proj-check-compile-commands {args} {
|
||||
set i 0
|
||||
set configFlag {}
|
||||
set fAssumeForClang 0
|
||||
set doAssume 0
|
||||
proc proj-check-compile-commands {{configFlag {}}} {
|
||||
msg-checking "compile_commands.json support... "
|
||||
if {"-assume-for-clang" eq [lindex $args 0]} {
|
||||
lassign $args - configFlag
|
||||
incr fAssumeForClang
|
||||
} elseif {1 == [llength $args]} {
|
||||
lassign $args configFlag
|
||||
} else {
|
||||
proj-error "Invalid arguments"
|
||||
}
|
||||
if {1 == $fAssumeForClang && "" ne $configFlag} {
|
||||
if {[string match *clang* [get-define CC]]
|
||||
&& ![proj-opt-was-provided $configFlag]
|
||||
&& ![proj-opt-truthy $configFlag]} {
|
||||
proj-indented-notice [subst -nocommands -nobackslashes {
|
||||
CC appears to be clang, so assuming that --$configFlag is likely
|
||||
to work. To disable this assumption use --$configFlag=0.}]
|
||||
incr doAssume
|
||||
}
|
||||
}
|
||||
if {!$doAssume && "" ne $configFlag && ![proj-opt-truthy $configFlag]} {
|
||||
msg-result "check disabled. Use --${configFlag} to enable it."
|
||||
if {"" ne $configFlag && ![proj-opt-truthy $configFlag]} {
|
||||
msg-result "explicitly disabled"
|
||||
define HAVE_COMPILE_COMMANDS 0
|
||||
define MAKE_COMPILATION_DB no
|
||||
return 0
|
||||
@@ -767,7 +732,7 @@ proc proj-check-compile-commands {args} {
|
||||
# This test reportedly incorrectly succeeds on one of
|
||||
# Martin G.'s older systems. drh also reports a false
|
||||
# positive on an unspecified older Mac system.
|
||||
msg-result "compiler supports -MJ. Assuming it's useful for compile_commands.json"
|
||||
msg-result "compiler supports compile_commands.json"
|
||||
define MAKE_COMPILATION_DB yes; # deprecated
|
||||
define HAVE_COMPILE_COMMANDS 1
|
||||
return 1
|
||||
@@ -1170,10 +1135,6 @@ proc proj-check-rpath {} {
|
||||
if {"" eq $wl} {
|
||||
set wl [proj-cc-check-Wl-flag -R$lp]
|
||||
}
|
||||
if {"" eq $wl} {
|
||||
# HP-UX: https://sqlite.org/forum/forumpost/d80ecdaddd
|
||||
set wl [proj-cc-check-Wl-flag +b $lp]
|
||||
}
|
||||
define LDFLAGS_RPATH $wl
|
||||
}
|
||||
}
|
||||
@@ -1183,7 +1144,7 @@ proc proj-check-rpath {} {
|
||||
#
|
||||
# @proj-check-soname ?libname?
|
||||
#
|
||||
# Checks whether CC supports the -Wl,-soname,lib... flag. If so, it
|
||||
# Checks whether CC supports the -Wl,soname,lib... flag. If so, it
|
||||
# returns 1 and defines LDFLAGS_SONAME_PREFIX to the flag's prefix, to
|
||||
# which the client would need to append "libwhatever.N". If not, it
|
||||
# returns 0 and defines LDFLAGS_SONAME_PREFIX to an empty string.
|
||||
@@ -1199,10 +1160,6 @@ proc proj-check-soname {{libname "libfoo.so.0"}} {
|
||||
if {[cc-check-flags "-Wl,-soname,${libname}"]} {
|
||||
define LDFLAGS_SONAME_PREFIX "-Wl,-soname,"
|
||||
return 1
|
||||
} elseif {[cc-check-flags "-Wl,+h,${libname}"]} {
|
||||
# HP-UX: https://sqlite.org/forum/forumpost/d80ecdaddd
|
||||
define LDFLAGS_SONAME_PREFIX "-Wl,+h,"
|
||||
return 1
|
||||
} else {
|
||||
define LDFLAGS_SONAME_PREFIX ""
|
||||
return 0
|
||||
@@ -1842,7 +1799,7 @@ proc proj-setup-autoreconfig {defName} {
|
||||
}
|
||||
|
||||
#
|
||||
# @prop-define-append defineName args...
|
||||
# @prop-append-to defineName args...
|
||||
#
|
||||
# A proxy for Autosetup's [define-append]. Appends all non-empty $args
|
||||
# to [define-append $defineName].
|
||||
@@ -1873,7 +1830,7 @@ proc proj-define-append {defineName args} {
|
||||
# but it is technically correct and still relevant on some
|
||||
# environments.
|
||||
#
|
||||
# See: proj-define-append
|
||||
# See: proj-append-to
|
||||
#
|
||||
proc proj-define-amend {args} {
|
||||
set defName ""
|
||||
|
||||
@@ -65,7 +65,7 @@ array set sqliteConfig [subst [proj-strip-hash-comments {
|
||||
# The list of feature --flags which the --all flag implies. This
|
||||
# requires special handling in a few places.
|
||||
#
|
||||
all-flag-enables {fts4 fts5 rtree geopoly session dbpage dbstat carray}
|
||||
all-flag-enables {fts4 fts5 rtree geopoly session}
|
||||
|
||||
#
|
||||
# Default value for the --all flag. Can hypothetically be modified
|
||||
@@ -220,9 +220,6 @@ proc sqlite-configure {buildMode configScript} {
|
||||
geopoly => {Enable the GEOPOLY extension}
|
||||
rtree => {Enable the RTREE extension}
|
||||
session => {Enable the SESSION extension}
|
||||
dbpage => {Enable the sqlite3_dbpage extension}
|
||||
dbstat => {Enable the sqlite3_dbstat extension}
|
||||
carray=1 => {Disable the CARRAY extension}
|
||||
all=$::sqliteConfig(all-flag-default) => {$allFlagHelp}
|
||||
largefile=1
|
||||
=> {This legacy flag has no effect on the library but may influence
|
||||
@@ -504,7 +501,6 @@ proc sqlite-configure-phase1 {buildMode} {
|
||||
if {[file exists $srcdir/sqlite3.pc.in]} {
|
||||
proj-dot-ins-append $srcdir/sqlite3.pc.in
|
||||
}
|
||||
sqlite-handle-hpux; # must be relatively early so that other config tests can work
|
||||
}; # sqlite-configure-phase1
|
||||
|
||||
########################################################################
|
||||
@@ -557,25 +553,7 @@ proc proc-debug {msg} {
|
||||
}
|
||||
|
||||
define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
|
||||
#
|
||||
# OPT_SHELL = feature-related CFLAGS for the sqlite3 CLI app. The
|
||||
# list's initial values are defaults which are always applied and not
|
||||
# affected by --feature-flags. The list is appended to by various
|
||||
# --feature-flags.
|
||||
define OPT_SHELL {
|
||||
-DSQLITE_DQS=0
|
||||
-DSQLITE_ENABLE_FTS4
|
||||
-DSQLITE_ENABLE_RTREE
|
||||
-DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
-DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
-DSQLITE_ENABLE_STMTVTAB
|
||||
-DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
-DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
-DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
-DSQLITE_ENABLE_PERCENTILE
|
||||
-DSQLITE_STRICT_SUBTYPE=1
|
||||
}
|
||||
define OPT_SHELL {} ; # Feature-related CFLAGS for the sqlite3 CLI app
|
||||
########################################################################
|
||||
# Adds $args, if not empty, to OPT_FEATURE_FLAGS. If the first arg is
|
||||
# -shell then it strips that arg and passes the remaining args the
|
||||
@@ -649,7 +627,7 @@ proc sqlite-check-common-system-deps {} {
|
||||
|
||||
# Check for needed/wanted functions
|
||||
cc-check-functions gmtime_r isnan localtime_r localtime_s \
|
||||
usleep utime pread pread64 pwrite pwrite64
|
||||
strchrnul usleep utime pread pread64 pwrite pwrite64
|
||||
|
||||
apply {{} {
|
||||
set ldrt ""
|
||||
@@ -679,7 +657,6 @@ proc sqlite-check-common-system-deps {} {
|
||||
define HAVE_ZLIB 1
|
||||
define LDFLAGS_ZLIB -lz
|
||||
sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
|
||||
sqlite-add-feature-flag -DSQLITE_HAVE_ZLIB=1
|
||||
} else {
|
||||
define HAVE_ZLIB 0
|
||||
define LDFLAGS_ZLIB ""
|
||||
@@ -743,11 +720,12 @@ proc sqlite-setup-default-cflags {} {
|
||||
# compiling binaries for the target system (CC a.k.a. $(T.cc)).
|
||||
# Normally they're the same, but they will differ when
|
||||
# cross-compiling.
|
||||
#
|
||||
# When cross-compiling we default to not using the -g flag, based on a
|
||||
# /chat discussion prompted by
|
||||
# https://sqlite.org/forum/forumpost/9a67df63eda9925c
|
||||
set defaultCFlags {-O2}
|
||||
if {!$::sqliteConfig(is-cross-compiling)} {
|
||||
# When cross-compiling we default to not using the -g flag, based
|
||||
# on a /chat discussion prompted by
|
||||
# https://sqlite.org/forum/forumpost/9a67df63eda9925c
|
||||
lappend defaultCFlags -g
|
||||
}
|
||||
define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
|
||||
@@ -805,12 +783,8 @@ proc sqlite-handle-common-feature-flags {} {
|
||||
sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
|
||||
}
|
||||
}
|
||||
bytecode-vtab -DSQLITE_ENABLE_BYTECODE_VTAB {}
|
||||
scanstatus {-DSQLITE_ENABLE_STMT_SCANSTATUS -DSQLITE_ENABLE_BYTECODE_VTAB} {}
|
||||
scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
|
||||
column-metadata -DSQLITE_ENABLE_COLUMN_METADATA {}
|
||||
dbpage -DSQLITE_ENABLE_DBPAGE_VTAB {}
|
||||
dbstat -DSQLITE_ENABLE_DBSTAT_VTAB {}
|
||||
carray -DSQLITE_ENABLE_CARRAY {}
|
||||
}] {
|
||||
if {$boolFlag ni $::autosetup(options)} {
|
||||
# Skip flags which are in the canonical build but not
|
||||
@@ -1137,27 +1111,6 @@ proc sqlite-check-line-editing {} {
|
||||
set editLibName "readline" ; # "readline" or "editline"
|
||||
set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
|
||||
set dirLn [opt-val with-linenoise]
|
||||
|
||||
# If none of --with-linenoise, --enable-readline, or --enable-editline
|
||||
# are provided, but there exists a directory "linenoise" at $HOME or
|
||||
# a sibling of the build or source directory, then try to use that linenoise
|
||||
# direcctory.
|
||||
#
|
||||
if {"" eq $dirLn
|
||||
&& ![proj-opt-was-provided readline]
|
||||
&& ![proj-opt-was-provided editline]
|
||||
} {
|
||||
set dirlist ../linenoise
|
||||
catch {lappend dirlist [file-normalize $::autosetup(srcdir)/../linenoise]}
|
||||
catch {lappend dirlist $::env(HOME)/linenoise}
|
||||
foreach d $dirlist {
|
||||
if {[file exists $d/linenoise.c] && [file exists $d/linenoise.h]} {
|
||||
set dirLn $d
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {"" ne $dirLn} {
|
||||
# Use linenoise from a copy of its sources (not a library)...
|
||||
if {![file isdir $dirLn]} {
|
||||
@@ -1193,8 +1146,6 @@ proc sqlite-check-line-editing {} {
|
||||
if {$::sqliteConfig(use-jim-for-codegen) && 2 == $lnVal} {
|
||||
define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE]
|
||||
user-notice "Adding linenoise support to jimsh."
|
||||
} else {
|
||||
msg-result "Using linenoise at [file-normalize $dirLn]"
|
||||
}
|
||||
return "linenoise ($flavor)"
|
||||
} elseif {[opt-bool editline]} {
|
||||
@@ -1532,7 +1483,7 @@ proc sqlite-handle-math {} {
|
||||
}
|
||||
define LDFLAGS_MATH [get-define lib_ceil]
|
||||
undefine lib_ceil
|
||||
sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_ENABLE_PERCENTILE
|
||||
sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
msg-result "Enabling math SQL functions"
|
||||
} {
|
||||
define LDFLAGS_MATH ""
|
||||
@@ -1594,19 +1545,6 @@ proc sqlite-handle-mac-install-name {} {
|
||||
return $rc
|
||||
}
|
||||
|
||||
#
|
||||
# Checks specific to HP-UX.
|
||||
#
|
||||
proc sqlite-handle-hpux {} {
|
||||
switch -glob -- [get-define host] {
|
||||
*hpux* {
|
||||
if {[cc-check-flags "-Ae"]} {
|
||||
define-append CFLAGS -Ae
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Handles the --dll-basename configure flag. [define]'s
|
||||
# SQLITE_DLL_BASENAME to the DLL's preferred base name (minus
|
||||
|
||||
@@ -220,9 +220,7 @@ proc teaish-configure-core {} {
|
||||
=> {Full pathname of tclsh to use. It is used for trying to find
|
||||
tclConfig.sh. Warning: if its containing dir has multiple tclsh
|
||||
versions, it may select the wrong tclConfig.sh!
|
||||
Defaults to the $TCLSH environment variable.}
|
||||
|
||||
tcl-stubs=0 => {Enable use of Tcl stubs library.}
|
||||
Defaults to the $TCLSH environment variable.}
|
||||
|
||||
# TEA has --with-tclinclude but it appears to only be useful for
|
||||
# building an extension against an uninstalled copy of TCL's own
|
||||
@@ -500,8 +498,6 @@ proc teaish__configure_phase1 {} {
|
||||
}
|
||||
teaish-checks-run -post
|
||||
|
||||
define TEAISH_USE_STUBS [opt-bool tcl-stubs]
|
||||
|
||||
apply {{} {
|
||||
# Set up "vsatisfies" code for pkgIndex.tcl.in,
|
||||
# _teaish.tester.tcl.in, and for a configure-time check. We would
|
||||
|
||||
+7
-33
@@ -22,10 +22,9 @@ guidance on building for Windows.
|
||||
or <https://sqlite.org/tmp/tcl9.0.0.tar.gz>.
|
||||
<li>Untar the source archive. CD into the "unix/" subfolder
|
||||
of the source tree.
|
||||
<li>Run:   `mkdir $HOME/local`
|
||||
<li>Run:   `./configure --prefix=$HOME/local`<br>
|
||||
SQLite deliverable builds add:   `--static CFLAGS=-Os`
|
||||
<li>Run:   `make install`
|
||||
<li>Run: `mkdir $HOME/local`
|
||||
<li>Run: `./configure --prefix=$HOME/local`
|
||||
<li>Run: `make install`
|
||||
</ol>
|
||||
<p>
|
||||
As of 2024-10-25, TCL is not longer required for many
|
||||
@@ -37,35 +36,12 @@ guidance on building for Windows.
|
||||
4. Download the SQLite source tree and unpack it. CD into the
|
||||
toplevel directory of the source tree.
|
||||
|
||||
5. *(Optional):* Download Antirez's "linenoise" command-line editing
|
||||
library to provide command-line editing in the CLI. You can find
|
||||
a suitable copy of the linenoise sources at
|
||||
<https://sqlite.org/linenoise.tar.gz> or at various other locations
|
||||
on the internet. If you put the linenoise source tree in
|
||||
a directory named $HOME/linenoise or a directory "linenoise" which
|
||||
is a sibling of the SQLite source tree, then the SQLite ./configure
|
||||
script will automatically find and use that source code to provide
|
||||
command-line editing in the CLI. If you would rather use the readline
|
||||
or editline libraries or a precompiled linenoise library, there are
|
||||
./configure options to accommodate that choice. The SQLite developers
|
||||
typically use $HOME/linenoise since linenoise is small, has no
|
||||
external dependencies, "just works", and the ./configure script
|
||||
will pick it up and use it automatically. But you do what works
|
||||
best for you.
|
||||
<p>
|
||||
You are not required to have any command-line editing support in
|
||||
order to use SQLite. But command-line editing does make the
|
||||
interactive experience more enjoyable.
|
||||
|
||||
6. Run: `./configure --enable-all --with-tclsh=$HOME/local/bin/tclsh9.0`
|
||||
5. Run: `./configure --enable-all --with-tclsh=$HOME/local/bin/tclsh9.0`
|
||||
|
||||
You do not need to use --with-tclsh if the tclsh you want to use is the
|
||||
first one on your PATH or if you are building without TCL.
|
||||
|
||||
Lots of other options to ./configure are available.
|
||||
Run `./configure --help` for further guidance.
|
||||
|
||||
7. Run the "`Makefile`" makefile with an appropriate target.
|
||||
6. Run the "`Makefile`" makefile with an appropriate target.
|
||||
Examples:
|
||||
<ul>
|
||||
<li> `make sqlite3.c`
|
||||
@@ -90,7 +66,5 @@ guidance on building for Windows.
|
||||
of SQLite.
|
||||
|
||||
|
||||
8. For a debugging build of the CLI, use `./configure --dev`. A debugging
|
||||
build contains lots of extra debugging code, so it is slow and a lot
|
||||
bigger. You probably do not want to deploy a debugging build. But if
|
||||
you are working on the code, a debugging build works much better.
|
||||
7. For a debugging build of the CLI, where the ".treetrace" and ".wheretrace"
|
||||
commands work, add the the --with-debug argument to configure.
|
||||
|
||||
+17
-44
@@ -1,7 +1,7 @@
|
||||
# Notes On Compiling SQLite On Windows 11
|
||||
|
||||
Below are step-by-step instructions on how to build SQLite from
|
||||
canonical source on a new Windows 11 PC, as of 2025-10-31.
|
||||
canonical source on a new Windows 11 PC, as of 2024-10-09.
|
||||
See [](./compile-for-unix.md) for a similar guide for unix-like
|
||||
systems, including MacOS.
|
||||
|
||||
@@ -24,8 +24,7 @@ systems, including MacOS.
|
||||
application to your task bar, as you will use it a lot. Bring up
|
||||
an instance of this command prompt and do all of the subsequent steps
|
||||
in that "x64 Native Tools" command prompt. (Or use "x86" if you want
|
||||
a 32-bit build. Or use "ARM64" if you want to do a build for Windows
|
||||
on ARM.) The subsequent steps will not work in a vanilla
|
||||
a 32-bit build.) The subsequent steps will not work in a vanilla
|
||||
DOS prompt. Nor will they work in PowerShell.
|
||||
|
||||
3. *(Optional):* Install TCL development libraries.
|
||||
@@ -134,7 +133,9 @@ following minor changes:
|
||||
The command the developers use for building the deliverable DLL on the
|
||||
[download page](https://sqlite.org/download.html) is as follows:
|
||||
|
||||
> nmake /f Makefile.msc sqlite3.dll USE_NATIVE_LIBPATHS=1 "OPTS=-DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 -DSQLITE_ENABLE_SERIALIZE=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
|
||||
> ~~~~
|
||||
nmake /f Makefile.msc sqlite3.dll USE_NATIVE_LIBPATHS=1 "OPTS=-DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 -DSQLITE_ENABLE_SERIALIZE=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
|
||||
~~~~
|
||||
|
||||
That command generates both the sqlite3.dll and sqlite3.def files. The same
|
||||
command works for both 32-bit and 64-bit builds.
|
||||
@@ -146,7 +147,9 @@ with TCL in order to function. The [sqlite3_analyzer.exe program](https://sqlit
|
||||
is an example. You can build as described above, and then
|
||||
enter:
|
||||
|
||||
> nmake /f Makefile.msc sqlite3_analyzer.exe
|
||||
> ~~~~
|
||||
nmake /f Makefile.msc sqlite3_analyzer.exe
|
||||
~~~~
|
||||
|
||||
And you will end up with a working executable. However, that executable
|
||||
will depend on having the "tcl98.dll" library somewhere on your %PATH%.
|
||||
@@ -172,47 +175,17 @@ statically linked so that it does not depend on separate DLL:
|
||||
5. CD into your SQLite source code directory and build the desired
|
||||
utility program, but add the following extra argument to the
|
||||
nmake command line:
|
||||
<blockquote><pre>STATICALLY_LINK_TCL=1</pre></blockquote>
|
||||
<blockquote><pre>
|
||||
STATICALLY_LINK_TCL=1
|
||||
</pre></blockquote>
|
||||
<p>So, for example, to build a statically linked version of
|
||||
sqlite3_analyzer.exe, you might type:
|
||||
<blockquote><pre>nmake /f Makefile.msc STATICALLY_LINK_TCL=1 sqlite3_analyzer.exe</pre></blockquote>
|
||||
<blockquote><pre>
|
||||
nmake /f Makefile.msc STATICALLY_LINK_TCL=1 sqlite3_analyzer.exe
|
||||
</pre></blockquote>
|
||||
|
||||
6. After your executable is built, you can verify that it does not
|
||||
depend on the TCL DLL by running:
|
||||
<blockquote><pre>dumpbin /dependents sqlite3_analyzer.exe</pre></blockquote>
|
||||
|
||||
## Linking Against ZLIB
|
||||
|
||||
Some feature (such as zip-file support in the CLI) require the ZLIB
|
||||
compression library. That library is more or less universally available
|
||||
on unix platforms, but is seldom provided on Windows. You will probably
|
||||
need to provide it yourself. Here the the steps needed:
|
||||
|
||||
1. Download the zlib-1.3.1.tar.gz tarball (or a similar version).
|
||||
Unpack the tarball sources. You can put them wherever you like.
|
||||
For the purposes of this document, let's assume you put the source
|
||||
tree in c:\\zlib-64. Note: If you are building for both x64 and
|
||||
x86, you will need separate builds of ZLIB for each, thus separate
|
||||
build directories.
|
||||
|
||||
2. Before building SQLite (as described above) first make these
|
||||
environment changes. The lead-programmer for SQLite (who writes
|
||||
these words) has BAT files named "env-x64.bat" and "env-x32.bat"
|
||||
and "env-arm64.bat" that make these changes, and he runs those
|
||||
BAT file whenever he starts a new shell. These are the settings
|
||||
needed:
|
||||
<blockquote>
|
||||
set USE_ZLIB=1<br>
|
||||
set BUILD_ZLIB=0<br>
|
||||
set ZLIBDIR=c:\\zlib-64
|
||||
</blockquote>
|
||||
|
||||
3. Because the settings in step 2 specify "BUILD_ZLIB=0", you will need
|
||||
to build the library at least once. I recommand:
|
||||
<blockquote>
|
||||
make clean sqlite3.exe BUILD_ZLIB=1
|
||||
</blockquote>
|
||||
|
||||
4. After making the environment changes specified in steps 1 through 3
|
||||
above, you then build and test SQLite as you normally would. The
|
||||
environment variable changes will cause ZLIB to be linked automatically.
|
||||
<blockquote><pre>
|
||||
dumpbin /dependents sqlite3_analyzer.exe
|
||||
</pre></blockquote>
|
||||
|
||||
+9
-8
@@ -149,10 +149,11 @@ RFC 8259 format, without extensions. The payload is the ASCII
|
||||
text representation of that numeric value.
|
||||
|
||||
<li value="4"><p><b>INT5</b> →
|
||||
The element is a JSON integer literal in hexadecimal notation.
|
||||
The payload is the ASCII text representation of the literal.
|
||||
Because the payload is in a non-standard format, it will need
|
||||
to be translated when the JSONB is converted into RFC 8259 text JSON.
|
||||
The element is a JSON integer value that is not in the
|
||||
canonical format. The payload is the ASCII
|
||||
text representation of that numeric value. Because the payload is in a
|
||||
non-standard format, it will need to be translated when the JSONB is
|
||||
converted into RFC 8259 text JSON.
|
||||
|
||||
<li value="5"><p><b>FLOAT</b> →
|
||||
The element is a JSON floating-point value in the canonical
|
||||
@@ -161,10 +162,10 @@ text representation of that numeric value.
|
||||
|
||||
<li value="6"><p><b>FLOAT5</b> →
|
||||
The element is a JSON floating-point value that is not in the
|
||||
canonical JSON format but rather the extended JSON5 format.
|
||||
The payload is the ASCII text representation of that numeric value.
|
||||
Because the payload is in a non-standard format, it will need to
|
||||
be translated when the JSONB is converted into RFC 8259 text JSON.
|
||||
canonical format. The payload is the ASCII
|
||||
text representation of that numeric value. Because the payload is in a
|
||||
non-standard format, it will need to be translated when the JSONB is
|
||||
converted into RFC 8259 text JSON.
|
||||
|
||||
<li value="7"><p><b>TEXT</b> →
|
||||
The element is a JSON string value that does not contain
|
||||
|
||||
+8
-22
@@ -696,7 +696,6 @@ other than that, the order of directives in Lemon is arbitrary.</p>
|
||||
<li><tt><a href='#pright'>%right</a></tt>
|
||||
<li><tt><a href='#reallc'>%realloc</a></tt>
|
||||
<li><tt><a href='#stack_overflow'>%stack_overflow</a></tt>
|
||||
<li><tt><a href='#reallc'>%stack_size_limit</a></tt>
|
||||
<li><tt><a href='#stack_size'>%stack_size</a></tt>
|
||||
<li><tt><a href='#start_symbol'>%start_symbol</a></tt>
|
||||
<li><tt><a href='#syntax_error'>%syntax_error</a></tt>
|
||||
@@ -1204,33 +1203,20 @@ the wildcard token and some other token, the other token is always used.
|
||||
The wildcard token is only matched if there are no alternatives.</p>
|
||||
|
||||
<a id='reallc'></a>
|
||||
<h4>4.4.26 The <tt>%realloc</tt>, <tt>%free</tt>, and
|
||||
<tt>%stack_size_limit</tt> directives</h4>
|
||||
<h4>4.4.26 The <tt>%realloc</tt> and <tt>%free</tt> directives</h4>
|
||||
|
||||
<p>The <tt>%realloc</tt> and <tt>%free</tt> directives defines function
|
||||
that allocate and free heap memory. The signatures and semantics of
|
||||
these functions are similar to the realloc() and free() functions from
|
||||
the standard C library, except that these functions take an extra
|
||||
parameter at the end that is determined by %extra_context. If
|
||||
%extra_context is not defined, then the extra argument is 0. The
|
||||
extra parameter provides the capability to do better error reporting
|
||||
in the event of a memory allocation error, and/or to use an alternative
|
||||
private application heap.
|
||||
that allocate and free heap memory. The signatures of these functions
|
||||
should be the same as the realloc() and free() functions from the standard
|
||||
C library.
|
||||
|
||||
<p>If both of these functions are defined then they are used to
|
||||
allocate and free memory for supplemental parser stack space, if
|
||||
the initial parse stack space is exceeded. The initial parser stack size
|
||||
<p>If both of these functions are defined
|
||||
then these functions are used to allocate and free
|
||||
memory for supplemental parser stack space, if the initial
|
||||
parse stack space is exceeded. The initial parser stack size
|
||||
is specified by either <tt>%stack_size</tt> or the
|
||||
-DYYSTACKDEPTH compile-time flag.
|
||||
|
||||
<p>The <tt>%stack_size_limit</tt> directive defines a function that returns
|
||||
the maximum allowed parser stack size. If this diretive does not exist,
|
||||
no size limit is enforced. This function takes a single argument which
|
||||
is the %extra_context value or "0" if %extra_context is not defined.
|
||||
The function should return an integer that is the maximum
|
||||
number of parser stack entries. If more stack space
|
||||
than this is needed, the %stack_overflow code is invoked.
|
||||
|
||||
<a id='errors'></a>
|
||||
<h2>5.0 Error Processing</h2>
|
||||
|
||||
|
||||
+57
-102
@@ -4,12 +4,6 @@
|
||||
|
||||
<ul type=none>
|
||||
<li> 1. <a href=#overview>Overview</a>
|
||||
<ul type=none>
|
||||
<li> 1.1. <a href=#runtr>Running testrunner.tcl</a>
|
||||
<li> 1.2. <a href=#runviamake>Run using "make"</a>
|
||||
<li> 1.3. <a href=#outputs>Outputs from testrunner.tcl</a>
|
||||
<li> 1.4. <a href=#help>Built-in help</a>
|
||||
</ul>
|
||||
<li> 2. <a href=#binary_tests>Binary Tests</a>
|
||||
<ul type=none>
|
||||
<li> 2.1. <a href=#organization_tests>Organization of Tcl Tests</a>
|
||||
@@ -32,40 +26,17 @@
|
||||
|
||||
The testrunner.tcl program is a Tcl script used to run multiple SQLite
|
||||
tests in parallel, thus reducing testing time on multi-core machines.
|
||||
The testrunner.tcl supports running tests that based on `testfixture`,
|
||||
`sqlite3`, and `fuzzcheck`.
|
||||
It supports the following types of tests:
|
||||
|
||||
<a name="runtr"></a>
|
||||
## 1.1 Running testrunner.tcl
|
||||
* Tcl test scripts.
|
||||
|
||||
The testrunner.tcl script is located in the "test" subdirectory of the
|
||||
SQLite source tree. So if your shell is current positioned at the top
|
||||
of the source tree, you would normally run the script using the command:
|
||||
"<tt>test/testrunner.tcl</tt>". On Windows, you have to specify the
|
||||
`tclsh` interpreter command first, like this:
|
||||
"<tt>tclsh test/testrunner.tcl</tt>".
|
||||
* Fuzzcheck tests, including using an external fuzzcheck database.
|
||||
|
||||
In this document, we will assume that you are on a unix-like OS
|
||||
(not on Windows) and that your current directory is the root
|
||||
of the SQLite source tree, and so all invocations of the testrunner.tcl
|
||||
script will be of the form "<tt>test/testrunner.tcl</tt>". If you
|
||||
are in a different directory, then make appropriate adjustments to
|
||||
the path. On Windows, add the "<tt>tclsh</tt>" interpreter command
|
||||
up front.
|
||||
|
||||
<a name="runviamake"></a>
|
||||
## 1.2 Run using make
|
||||
|
||||
The standard Makefiles for SQLite include targets that invoke
|
||||
testrunner.tcl. So the following commands also run testrunner.tcl:
|
||||
|
||||
* `make devtest`
|
||||
* `make releasetest`
|
||||
* `make sdevtest`
|
||||
* `make testrunner`
|
||||
|
||||
<a name="outputs"></a>
|
||||
## 1.3 Outputs from testrunner.tcl
|
||||
* Tests run with `make` commands. Examples:
|
||||
- `make devtest`
|
||||
- `make releasetest`
|
||||
- `make sdevtest`
|
||||
- `make testrunner`
|
||||
|
||||
The testrunner.tcl program stores output of all tests and builds run in
|
||||
log file **testrunner.log**, created in the current working directory.
|
||||
@@ -83,19 +54,17 @@ A useful query might be:
|
||||
```
|
||||
|
||||
You can get a summary of errors in a prior run by invoking commands like
|
||||
those shown below. Note that the testrunner.tcl script can be run directly
|
||||
on unix systems (including Macs) but you will need to add <tt>tclsh</tt>
|
||||
to the front on Windows.
|
||||
these:
|
||||
|
||||
```
|
||||
test/testrunner.tcl errors
|
||||
test/testrunner.tcl errors -v
|
||||
tclsh $(TESTDIR)/testrunner.tcl errors
|
||||
tclsh $(TESTDIR)/testrunner.tcl errors -v
|
||||
```
|
||||
|
||||
Running the command:
|
||||
|
||||
```
|
||||
test/testrunner.tcl status
|
||||
tclsh $(TESTDIR)/testrunner.tcl status
|
||||
```
|
||||
|
||||
in the directory containing the testrunner.db database runs various queries
|
||||
@@ -104,43 +73,32 @@ A good way to keep and eye on test progress is to run either of the two
|
||||
following commands:
|
||||
|
||||
```
|
||||
watch test/testrunner.tcl status
|
||||
test/testrunner.tcl status -d 2
|
||||
watch tclsh $(TESTDIR)/testrunner.tcl status
|
||||
tclsh $(TESTDIR)/testrunner.tcl status -d 2
|
||||
```
|
||||
|
||||
Both of the commands above accomplish about the same thing, but the second
|
||||
one has the advantage of not requiring "watch" to be installed on your
|
||||
system.
|
||||
|
||||
Sometimes testrunner.tcl uses the `testfixture` and `sqlite3` binaries that
|
||||
are in the directory from which testrunner.tcl is run.
|
||||
(see "Binary Tests" below). Sometimes it builds testfixture and
|
||||
Sometimes testrunner.tcl uses the `testfixture` binary that it is run with
|
||||
to run tests (see "Binary Tests" below). Sometimes it builds testfixture and
|
||||
other binaries in specific configurations to test (see "Source Tests").
|
||||
|
||||
<a name=help></a>
|
||||
## 1.4 Built-in help
|
||||
|
||||
Run this command:
|
||||
|
||||
```
|
||||
test/testrunner.tcl help
|
||||
```
|
||||
|
||||
To get a summary of all of the various command-line options available
|
||||
with testrunner.tcl
|
||||
|
||||
|
||||
<a name=binary_tests></a>
|
||||
# 2. Binary Tests
|
||||
|
||||
The commands described in this section all run various combinations of the Tcl
|
||||
test scripts using whatever `testfixture` binary (and maybe also the `sqlite3`
|
||||
binary, depending on the test) that is found in the directory from which
|
||||
testrunner.tcl is launched. So typically, one must first run something
|
||||
like "`make testfixture sqlite3`" before launching binary tests. In other
|
||||
words, testrunner.tcl does not automatically build the binaries under test
|
||||
for binary tests. The testrunner.tcl expects the binaries to be available
|
||||
already.
|
||||
test scripts using the `testfixture` binary used to run the testrunner.tcl
|
||||
script (i.e. they do not invoke the compiler to build new binaries, or the
|
||||
`make` command to run tests that are not Tcl scripts). The procedure to run
|
||||
these tests is therefore:
|
||||
|
||||
1. Build the "testfixture" (or "testfixture.exe" for windows) binary using
|
||||
whatever method seems convenient.
|
||||
|
||||
2. Test the binary built in step 1 by running testrunner.tcl with it,
|
||||
perhaps with various options.
|
||||
|
||||
The following sub-sections describe the various options that can be
|
||||
passed to testrunner.tcl to test binary testfixture builds.
|
||||
@@ -182,22 +140,22 @@ are defined in file *testrunner_data.tcl*.
|
||||
To run the "veryquick" test set, use either of the following:
|
||||
|
||||
```
|
||||
test/testrunner.tcl
|
||||
test/testrunner.tcl veryquick
|
||||
./testfixture $TESTDIR/testrunner.tcl
|
||||
./testfixture $TESTDIR/testrunner.tcl veryquick
|
||||
```
|
||||
|
||||
To run the "full" test suite:
|
||||
|
||||
```
|
||||
test/testrunner.tcl full
|
||||
./testfixture $TESTDIR/testrunner.tcl full
|
||||
```
|
||||
|
||||
To run the subset of the "full" test suite for which the test file name matches
|
||||
a specified pattern (e.g. all tests that start with "fts5"), either of:
|
||||
|
||||
```
|
||||
test/testrunner.tcl fts5%
|
||||
test/testrunner.tcl 'fts5*'
|
||||
./testfixture $TESTDIR/testrunner.tcl fts5%
|
||||
./testfixture $TESTDIR/testrunner.tcl 'fts5*'
|
||||
```
|
||||
|
||||
Strictly speaking, for a test to be run the pattern must match the script
|
||||
@@ -209,7 +167,7 @@ characters specified as part of the pattern are transformed to "\*".
|
||||
To run "all" tests (full + permutations):
|
||||
|
||||
```
|
||||
test/testrunner.tcl all
|
||||
./testfixture $TESTDIR/testrunner.tcl all
|
||||
```
|
||||
|
||||
<a name=binary_test_failures></a>
|
||||
@@ -228,15 +186,10 @@ If there is no permutation, the individual test script may be run with:
|
||||
Or, if the failure occured as part of a permutation:
|
||||
|
||||
```
|
||||
test/testrunner.tcl $PERMUTATION $PATH_TO_SCRIPT
|
||||
./testfixture $TESTDIR/testrunner.tcl $PERMUTATION $PATH_TO_SCRIPT
|
||||
```
|
||||
|
||||
One can also rerun all tests that failed or did not complete
|
||||
in the previous invocation by typing:
|
||||
|
||||
```
|
||||
test/testrunner.tcl retest
|
||||
```
|
||||
TODO: An example instead of "$PERMUTATION" and $PATH\_TO\_SCRIPT?
|
||||
|
||||
<a name=source_code_tests></a>
|
||||
# 3. Source Code Tests
|
||||
@@ -251,9 +204,11 @@ other tests. The advantages of this are that:
|
||||
* it ensures that tests are always run using binaries created with the
|
||||
same set of compiler options.
|
||||
|
||||
The testrunner.tcl commands described in this section do not require that
|
||||
the testfixture and/or sqlite3 binaries be built ahead of time. Those
|
||||
binaries will be constructed automatically.
|
||||
The testrunner.tcl commands described in this section may be run using
|
||||
either a *testfixture* (or testfixture.exe) build, or with any other Tcl
|
||||
shell that supports SQLite 3.31.1 or newer via "package require sqlite3".
|
||||
|
||||
TODO: ./configure + Makefile.msc build systems.
|
||||
|
||||
<a name=commands_to_run_tests></a>
|
||||
## 3.1. Commands to Run SQLite Tests
|
||||
@@ -263,7 +218,7 @@ the `make fuzztest` target once for each of two --enable-all builds - one
|
||||
with debugging enabled and one without:
|
||||
|
||||
```
|
||||
test/testrunner.tcl mdevtest
|
||||
tclsh $TESTDIR/testrunner.tcl mdevtest
|
||||
```
|
||||
|
||||
In other words, it is equivalent to running:
|
||||
@@ -272,13 +227,13 @@ In other words, it is equivalent to running:
|
||||
$TOP/configure --enable-all --enable-debug
|
||||
make fuzztest
|
||||
make testfixture
|
||||
$TOP/test/testrunner.tcl veryquick
|
||||
./testfixture $TOP/test/testrunner.tcl veryquick
|
||||
|
||||
# Then, after removing files created by the tests above:
|
||||
$TOP/configure --enable-all OPTS="-O0"
|
||||
make fuzztest
|
||||
make testfixture
|
||||
$TOP/test/testrunner.tcl veryquick
|
||||
./testfixture $TOP/test/testrunner.tcl veryquick
|
||||
```
|
||||
|
||||
The **sdevtest** command is identical to the mdevtest command, except that the
|
||||
@@ -286,7 +241,7 @@ second of the two builds is a sanitizer build. Specifically, this means that
|
||||
OPTS="-fsanitize=address,undefined" is specified instead of OPTS="-O0":
|
||||
|
||||
```
|
||||
test/testrunner.tcl sdevtest
|
||||
tclsh $TESTDIR/testrunner.tcl sdevtest
|
||||
```
|
||||
|
||||
The **release** command runs lots of tests under lots of builds. It runs
|
||||
@@ -295,7 +250,7 @@ on Linux, Windows or OSX. Refer to *testrunner\_data.tcl* for the details
|
||||
of the specific tests run.
|
||||
|
||||
```
|
||||
test/testrunner.tcl release
|
||||
tclsh $TESTDIR/testrunner.tcl release
|
||||
```
|
||||
|
||||
As with <a href=#source code tests>source code tests</a>, one or more patterns
|
||||
@@ -303,7 +258,7 @@ may be appended to any of the above commands (mdevtest, sdevtest or release).
|
||||
Pattern matching is used for both Tcl tests and fuzz tests.
|
||||
|
||||
```
|
||||
test/testrunner.tcl release rtree%
|
||||
tclsh $TESTDIR/testrunner.tcl release rtree%
|
||||
```
|
||||
|
||||
<a name=zipvfs_tests></a>
|
||||
@@ -313,14 +268,14 @@ testrunner.tcl can build a zipvfs-enabled testfixture and use it to run
|
||||
tests from the Zipvfs project with the following command:
|
||||
|
||||
```
|
||||
test/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS
|
||||
tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS
|
||||
```
|
||||
|
||||
This can be combined with any of "mdevtest", "sdevtest" or "release" to
|
||||
test both SQLite and Zipvfs with a single command:
|
||||
|
||||
```
|
||||
test/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
|
||||
tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
|
||||
```
|
||||
|
||||
<a name=source_code_test_failures></a>
|
||||
@@ -340,10 +295,10 @@ a dos \*.bat file on windows. For example:
|
||||
```
|
||||
# Create a script that recreates build configuration "Device-One" on
|
||||
# Linux or OSX:
|
||||
test/testrunner.tcl script Device-One > make.sh
|
||||
tclsh $TESTDIR/testrunner.tcl script Device-One > make.sh
|
||||
|
||||
# Create a script that recreates build configuration "Have-Not" on Windows:
|
||||
test/testrunner.tcl script Have-Not > make.bat
|
||||
tclsh $TESTDIR/testrunner.tcl script Have-Not > make.bat
|
||||
```
|
||||
|
||||
The generated bash or \*.bat file script accepts a single argument - a makefile
|
||||
@@ -366,7 +321,7 @@ Thus, for example, to run a full releasetest including an external
|
||||
dbsqlfuzz database, run a command like one of these:
|
||||
|
||||
```
|
||||
test/testrunner.tcl releasetest --fuzzdb ../fuzz/20250415.db
|
||||
tclsh test/testrunner.tcl releasetest --fuzzdb ../fuzz/20250415.db
|
||||
FUZZDB=../fuzz/20250415.db make releasetest
|
||||
nmake /f Makefile.msc FUZZDB=../fuzz/20250415.db releasetest
|
||||
```
|
||||
@@ -376,7 +331,7 @@ databases. So if you want to run *only* tests involving the external
|
||||
database, you can use a command something like this:
|
||||
|
||||
```
|
||||
test/testrunner.tcl releasetest 20250415 --fuzzdb ../fuzz/20250415.db
|
||||
tclsh test/testrunner.tcl releasetest 20250415 --fuzzdb ../fuzz/20250415.db
|
||||
```
|
||||
|
||||
<a name=testrunner_options></a>
|
||||
@@ -390,7 +345,7 @@ required by a test, not to run any actual tests. For example:
|
||||
|
||||
```
|
||||
# Build binaries required by release test.
|
||||
test/testrunner.tcl --buildonly release"
|
||||
tclsh $TESTDIR/testrunner.tcl --buildonly release"
|
||||
```
|
||||
|
||||
The **--dryrun** option prevents testrunner.tcl from building any binaries
|
||||
@@ -399,7 +354,7 @@ would normally execute into the testrunner.log file. Example:
|
||||
|
||||
```
|
||||
# Log the shell commmands that make up the mdevtest test.
|
||||
test/testrunner.tcl --dryrun mdevtest"
|
||||
tclsh $TESTDIR/testrunner.tcl --dryrun mdevtest"
|
||||
```
|
||||
|
||||
The **--explain** option is similar to --dryrun in that it prevents
|
||||
@@ -409,7 +364,7 @@ summary of all the builds and tests that would have been run.
|
||||
|
||||
```
|
||||
# Show what builds and tests would have been run
|
||||
test/testrunner.tcl --explain mdevtest
|
||||
tclsh $TESTDIR/testrunner.tcl --explain mdevtest
|
||||
```
|
||||
|
||||
The **--status** option uses VT100 escape sequences to display the test
|
||||
@@ -425,7 +380,7 @@ When running either binary or source code tests, testrunner.tcl reports the
|
||||
number of jobs it intends to use to stdout. e.g.
|
||||
|
||||
```
|
||||
$ test/testrunner.tcl
|
||||
$ ./testfixture $TESTDIR/testrunner.tcl
|
||||
splitting work across 16 jobs
|
||||
... more output ...
|
||||
```
|
||||
@@ -435,7 +390,7 @@ of real cores on the machine. This can be overridden using the "--jobs" (or -j)
|
||||
switch:
|
||||
|
||||
```
|
||||
$ test/testrunner.tcl --jobs 8
|
||||
$ ./testfixture $TESTDIR/testrunner.tcl --jobs 8
|
||||
splitting work across 8 jobs
|
||||
... more output ...
|
||||
```
|
||||
@@ -445,5 +400,5 @@ running by exucuting the following command from the directory containing the
|
||||
testrunner.log and testrunner.db files:
|
||||
|
||||
```
|
||||
$ test/testrunner.tcl njob $NEW_NUMBER_OF_JOBS
|
||||
$ ./testfixture $TESTDIR/testrunner.tcl njob $NEW_NUMBER_OF_JOBS
|
||||
```
|
||||
|
||||
@@ -90,7 +90,7 @@ foreach {tn setup} {
|
||||
proc do_rec_test {tn sql res} {
|
||||
set res [squish [string trim $res]]
|
||||
set tst [subst -nocommands {
|
||||
squish [string trim [exec $::CLI -noinit test.db ".expert" {$sql;}]]
|
||||
squish [string trim [exec $::CLI test.db ".expert" {$sql;}]]
|
||||
}]
|
||||
uplevel [list do_test $tn $tst $res]
|
||||
}
|
||||
|
||||
+25
-27
@@ -172,11 +172,11 @@ struct sqlite3expert {
|
||||
** Allocate and return nByte bytes of zeroed memory using sqlite3_malloc().
|
||||
** If the allocation fails, set *pRc to SQLITE_NOMEM and return NULL.
|
||||
*/
|
||||
static void *idxMalloc(int *pRc, i64 nByte){
|
||||
static void *idxMalloc(int *pRc, int nByte){
|
||||
void *pRet;
|
||||
assert( *pRc==SQLITE_OK );
|
||||
assert( nByte>0 );
|
||||
pRet = sqlite3_malloc64(nByte);
|
||||
pRet = sqlite3_malloc(nByte);
|
||||
if( pRet ){
|
||||
memset(pRet, 0, nByte);
|
||||
}else{
|
||||
@@ -243,7 +243,7 @@ static int idxHashAdd(
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + (i64)nKey+1 + (i64)nVal+1);
|
||||
pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + nKey+1 + nVal+1);
|
||||
if( pEntry ){
|
||||
pEntry->zKey = (char*)&pEntry[1];
|
||||
memcpy(pEntry->zKey, zKey, nKey);
|
||||
@@ -378,15 +378,15 @@ struct ExpertCsr {
|
||||
};
|
||||
|
||||
static char *expertDequote(const char *zIn){
|
||||
i64 n = STRLEN(zIn);
|
||||
char *zRet = sqlite3_malloc64(n);
|
||||
int n = STRLEN(zIn);
|
||||
char *zRet = sqlite3_malloc(n);
|
||||
|
||||
assert( zIn[0]=='\'' );
|
||||
assert( zIn[n-1]=='\'' );
|
||||
|
||||
if( zRet ){
|
||||
i64 iOut = 0;
|
||||
i64 iIn = 0;
|
||||
int iOut = 0;
|
||||
int iIn = 0;
|
||||
for(iIn=1; iIn<(n-1); iIn++){
|
||||
if( zIn[iIn]=='\'' ){
|
||||
assert( zIn[iIn+1]=='\'' );
|
||||
@@ -699,7 +699,7 @@ static int idxGetTableInfo(
|
||||
sqlite3_stmt *p1 = 0;
|
||||
int nCol = 0;
|
||||
int nTab;
|
||||
i64 nByte;
|
||||
int nByte;
|
||||
IdxTable *pNew = 0;
|
||||
int rc, rc2;
|
||||
char *pCsr = 0;
|
||||
@@ -791,14 +791,14 @@ static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){
|
||||
va_list ap;
|
||||
char *zAppend = 0;
|
||||
char *zRet = 0;
|
||||
i64 nIn = zIn ? STRLEN(zIn) : 0;
|
||||
i64 nAppend = 0;
|
||||
int nIn = zIn ? STRLEN(zIn) : 0;
|
||||
int nAppend = 0;
|
||||
va_start(ap, zFmt);
|
||||
if( *pRc==SQLITE_OK ){
|
||||
zAppend = sqlite3_vmprintf(zFmt, ap);
|
||||
if( zAppend ){
|
||||
nAppend = STRLEN(zAppend);
|
||||
zRet = (char*)sqlite3_malloc64(nIn + nAppend + 1);
|
||||
zRet = (char*)sqlite3_malloc(nIn + nAppend + 1);
|
||||
}
|
||||
if( zAppend && zRet ){
|
||||
if( nIn ) memcpy(zRet, zIn, nIn);
|
||||
@@ -1562,8 +1562,8 @@ struct IdxRemCtx {
|
||||
int eType; /* SQLITE_NULL, INTEGER, REAL, TEXT, BLOB */
|
||||
i64 iVal; /* SQLITE_INTEGER value */
|
||||
double rVal; /* SQLITE_FLOAT value */
|
||||
i64 nByte; /* Bytes of space allocated at z */
|
||||
i64 n; /* Size of buffer z */
|
||||
int nByte; /* Bytes of space allocated at z */
|
||||
int n; /* Size of buffer z */
|
||||
char *z; /* SQLITE_TEXT/BLOB value */
|
||||
} aSlot[1];
|
||||
};
|
||||
@@ -1599,13 +1599,11 @@ static void idxRemFunc(
|
||||
break;
|
||||
|
||||
case SQLITE_BLOB:
|
||||
assert( pSlot->n <= 0x7fffffff );
|
||||
sqlite3_result_blob(pCtx, pSlot->z, (int)pSlot->n, SQLITE_TRANSIENT);
|
||||
sqlite3_result_blob(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
|
||||
break;
|
||||
|
||||
case SQLITE_TEXT:
|
||||
assert( pSlot->n <= 0x7fffffff );
|
||||
sqlite3_result_text(pCtx, pSlot->z, (int)pSlot->n, SQLITE_TRANSIENT);
|
||||
sqlite3_result_text(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1625,10 +1623,10 @@ static void idxRemFunc(
|
||||
|
||||
case SQLITE_BLOB:
|
||||
case SQLITE_TEXT: {
|
||||
i64 nByte = sqlite3_value_bytes(argv[1]);
|
||||
int nByte = sqlite3_value_bytes(argv[1]);
|
||||
const void *pData = 0;
|
||||
if( nByte>pSlot->nByte ){
|
||||
char *zNew = (char*)sqlite3_realloc64(pSlot->z, nByte*2);
|
||||
char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2);
|
||||
if( zNew==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return;
|
||||
@@ -1683,7 +1681,7 @@ static int idxPopulateOneStat1(
|
||||
int nCol = 0;
|
||||
int i;
|
||||
sqlite3_stmt *pQuery = 0;
|
||||
i64 *aStat = 0;
|
||||
int *aStat = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( p->iSample>0 );
|
||||
@@ -1729,7 +1727,7 @@ static int idxPopulateOneStat1(
|
||||
sqlite3_free(zQuery);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
aStat = (i64*)idxMalloc(&rc, sizeof(i64)*(nCol+1));
|
||||
aStat = (int*)idxMalloc(&rc, sizeof(int)*(nCol+1));
|
||||
}
|
||||
if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
|
||||
IdxHashEntry *pEntry;
|
||||
@@ -1746,11 +1744,11 @@ static int idxPopulateOneStat1(
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 s0 = aStat[0];
|
||||
zStat = sqlite3_mprintf("%lld", s0);
|
||||
int s0 = aStat[0];
|
||||
zStat = sqlite3_mprintf("%d", s0);
|
||||
if( zStat==0 ) rc = SQLITE_NOMEM;
|
||||
for(i=1; rc==SQLITE_OK && i<=nCol; i++){
|
||||
zStat = idxAppendText(&rc, zStat, " %lld", (s0+aStat[i]/2) / aStat[i]);
|
||||
zStat = idxAppendText(&rc, zStat, " %d", (s0+aStat[i]/2) / aStat[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1829,7 +1827,7 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
|
||||
rc = sqlite3_exec(p->dbm, "ANALYZE; PRAGMA writable_schema=1", 0, 0, 0);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
|
||||
int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
|
||||
pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte);
|
||||
}
|
||||
|
||||
@@ -1846,7 +1844,7 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pCtx->nSlot = (i64)nMax+1;
|
||||
pCtx->nSlot = nMax+1;
|
||||
rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -2113,7 +2111,7 @@ int sqlite3_expert_sql(
|
||||
if( pStmt ){
|
||||
IdxStatement *pNew;
|
||||
const char *z = sqlite3_sql(pStmt);
|
||||
i64 n = STRLEN(z);
|
||||
int n = STRLEN(z);
|
||||
pNew = (IdxStatement*)idxMalloc(&rc, sizeof(IdxStatement) + n+1);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew->zSql = (char*)&pNew[1];
|
||||
|
||||
+6
-3
@@ -1816,7 +1816,9 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
|
||||
zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
|
||||
if( !zSql ) return SQLITE_NOMEM;
|
||||
p->bLock++;
|
||||
rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt);
|
||||
rc = sqlite3_prepare_v3(
|
||||
p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
|
||||
);
|
||||
p->bLock--;
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
@@ -3391,7 +3393,9 @@ static int fts3FilterMethod(
|
||||
}
|
||||
if( zSql ){
|
||||
p->bLock++;
|
||||
rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt);
|
||||
rc = sqlite3_prepare_v3(
|
||||
p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
|
||||
);
|
||||
p->bLock--;
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
@@ -4014,7 +4018,6 @@ static int fts3IntegrityMethod(
|
||||
|
||||
UNUSED_PARAMETER(isQuick);
|
||||
rc = sqlite3Fts3IntegrityCheck(p, &bOk);
|
||||
assert( pVtab->zErrMsg==0 || rc!=SQLITE_OK );
|
||||
assert( rc!=SQLITE_CORRUPT_VTAB );
|
||||
if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){
|
||||
*pzErr = sqlite3_mprintf("unable to validate the inverted index for"
|
||||
|
||||
+1
-19
@@ -203,16 +203,7 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
|
||||
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
||||
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
||||
|
||||
#if !defined(deliberate_fall_through)
|
||||
# if defined(__has_attribute)
|
||||
# if __has_attribute(fallthrough)
|
||||
# define deliberate_fall_through __attribute__((fallthrough));
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(deliberate_fall_through)
|
||||
# define deliberate_fall_through
|
||||
#endif
|
||||
#define deliberate_fall_through
|
||||
|
||||
/*
|
||||
** Macros needed to provide flexible arrays in a portable way
|
||||
@@ -610,15 +601,6 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
|
||||
(*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \
|
||||
)
|
||||
|
||||
int sqlite3Fts3PrepareStmt(
|
||||
Fts3Table *p, /* Prepare for this connection */
|
||||
const char *zSql, /* SQL to prepare */
|
||||
int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */
|
||||
int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */
|
||||
sqlite3_stmt **pp /* OUT: Prepared statement */
|
||||
);
|
||||
|
||||
|
||||
/* fts3.c */
|
||||
void sqlite3Fts3ErrMsg(char**,const char*,...);
|
||||
int sqlite3Fts3PutVarint(char *, sqlite3_int64);
|
||||
|
||||
+1
-1
@@ -325,7 +325,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
pCsr->aStat[1].nDoc++;
|
||||
}
|
||||
eState = 2;
|
||||
/* no break */ deliberate_fall_through
|
||||
/* fall through */
|
||||
|
||||
case 2:
|
||||
if( v==0 ){ /* 0x00. Next integer will be a docid. */
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
typedef sqlite3_int64 i64;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Characters that may appear in the second argument to matchinfo().
|
||||
*/
|
||||
|
||||
+10
-32
@@ -98,9 +98,9 @@ typedef struct SegmentWriter SegmentWriter;
|
||||
** incrementally. See function fts3PendingListAppend() for details.
|
||||
*/
|
||||
struct PendingList {
|
||||
sqlite3_int64 nData;
|
||||
int nData;
|
||||
char *aData;
|
||||
sqlite3_int64 nSpace;
|
||||
int nSpace;
|
||||
sqlite3_int64 iLastDocid;
|
||||
sqlite3_int64 iLastCol;
|
||||
sqlite3_int64 iLastPos;
|
||||
@@ -273,24 +273,6 @@ struct SegmentNode {
|
||||
#define SQL_UPDATE_LEVEL_IDX 38
|
||||
#define SQL_UPDATE_LEVEL 39
|
||||
|
||||
/*
|
||||
** Wrapper around sqlite3_prepare_v3() to ensure that SQLITE_PREPARE_FROM_DDL
|
||||
** is always set.
|
||||
*/
|
||||
int sqlite3Fts3PrepareStmt(
|
||||
Fts3Table *p, /* Prepare for this connection */
|
||||
const char *zSql, /* SQL to prepare */
|
||||
int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */
|
||||
int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */
|
||||
sqlite3_stmt **pp /* OUT: Prepared statement */
|
||||
){
|
||||
int f = SQLITE_PREPARE_FROM_DDL
|
||||
|((bAllowVtab==0) ? SQLITE_PREPARE_NO_VTAB : 0)
|
||||
|(bPersist ? SQLITE_PREPARE_PERSISTENT : 0);
|
||||
|
||||
return sqlite3_prepare_v3(p->db, zSql, -1, f, pp, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to obtain an SQLite prepared statement handle
|
||||
** for the statement identified by the second argument. If successful,
|
||||
@@ -416,12 +398,12 @@ static int fts3SqlStmt(
|
||||
|
||||
pStmt = p->aStmt[eStmt];
|
||||
if( !pStmt ){
|
||||
int bAllowVtab = 0;
|
||||
int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
|
||||
char *zSql;
|
||||
if( eStmt==SQL_CONTENT_INSERT ){
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
|
||||
}else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
|
||||
bAllowVtab = 1;
|
||||
f &= ~SQLITE_PREPARE_NO_VTAB;
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
|
||||
}else{
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
|
||||
@@ -429,7 +411,7 @@ static int fts3SqlStmt(
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3Fts3PrepareStmt(p, zSql, 1, bAllowVtab, &pStmt);
|
||||
rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL);
|
||||
sqlite3_free(zSql);
|
||||
assert( rc==SQLITE_OK || pStmt==0 );
|
||||
p->aStmt[eStmt] = pStmt;
|
||||
@@ -778,9 +760,7 @@ static int fts3PendingTermsAddOne(
|
||||
|
||||
pList = (PendingList *)fts3HashFind(pHash, zToken, nToken);
|
||||
if( pList ){
|
||||
assert( (i64)pList->nData+(i64)nToken+(i64)sizeof(Fts3HashElem)
|
||||
<= (i64)p->nPendingData );
|
||||
p->nPendingData -= (int)(pList->nData + nToken + sizeof(Fts3HashElem));
|
||||
p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem));
|
||||
}
|
||||
if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){
|
||||
if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){
|
||||
@@ -793,9 +773,7 @@ static int fts3PendingTermsAddOne(
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( (i64)p->nPendingData + pList->nData + nToken
|
||||
+ sizeof(Fts3HashElem) <= 0x3fffffff );
|
||||
p->nPendingData += (int)(pList->nData + nToken + sizeof(Fts3HashElem));
|
||||
p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -3596,7 +3574,7 @@ static int fts3DoRebuild(Fts3Table *p){
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt);
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
@@ -5349,7 +5327,7 @@ int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt);
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
@@ -5479,7 +5457,7 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
v = atoi(&zVal[9]);
|
||||
if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v;
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 11) ){
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
|
||||
v = atoi(&zVal[11]);
|
||||
if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v;
|
||||
rc = SQLITE_OK;
|
||||
|
||||
+2
-8
@@ -81,13 +81,7 @@ typedef sqlite3_uint64 u64;
|
||||
# define FLEXARRAY 1
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_AMALGAMATION */
|
||||
|
||||
/*
|
||||
** Constants for the largest and smallest possible 32-bit signed integers.
|
||||
*/
|
||||
# define LARGEST_INT32 ((int)(0x7fffffff))
|
||||
# define SMALLEST_INT32 ((int)((-1) - LARGEST_INT32))
|
||||
#endif
|
||||
|
||||
/* Truncate very long tokens to this many bytes. Hard limit is
|
||||
** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
|
||||
@@ -821,7 +815,7 @@ int sqlite3Fts5ExprPattern(
|
||||
** i64 iRowid = sqlite3Fts5ExprRowid(pExpr);
|
||||
** }
|
||||
*/
|
||||
int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, i64, int bDesc);
|
||||
int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc);
|
||||
int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax);
|
||||
int sqlite3Fts5ExprEof(Fts5Expr*);
|
||||
i64 sqlite3Fts5ExprRowid(Fts5Expr*);
|
||||
|
||||
+1
-1
@@ -455,7 +455,7 @@ static void fts5SnippetFunction(
|
||||
|
||||
iBestCol = (iCol>=0 ? iCol : 0);
|
||||
nPhrase = pApi->xPhraseCount(pFts);
|
||||
aSeen = sqlite3_malloc64(nPhrase);
|
||||
aSeen = sqlite3_malloc(nPhrase);
|
||||
if( aSeen==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
|
||||
if( nIn<0 ){
|
||||
nIn = (int)strlen(pIn);
|
||||
}
|
||||
zRet = (char*)sqlite3_malloc64((i64)nIn+1);
|
||||
zRet = (char*)sqlite3_malloc(nIn+1);
|
||||
if( zRet ){
|
||||
memcpy(zRet, pIn, nIn);
|
||||
zRet[nIn] = '\0';
|
||||
|
||||
@@ -576,7 +576,7 @@ int sqlite3Fts5ConfigParse(
|
||||
sqlite3_int64 nByte;
|
||||
int bUnindexed = 0; /* True if there are one or more UNINDEXED */
|
||||
|
||||
*ppOut = pRet = (Fts5Config*)sqlite3_malloc64(sizeof(Fts5Config));
|
||||
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
|
||||
if( pRet==0 ) return SQLITE_NOMEM;
|
||||
memset(pRet, 0, sizeof(Fts5Config));
|
||||
pRet->pGlobal = pGlobal;
|
||||
@@ -1123,3 +1123,5 @@ void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-12
@@ -314,7 +314,7 @@ int sqlite3Fts5ExprNew(
|
||||
|
||||
assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
|
||||
if( sParse.rc==SQLITE_OK ){
|
||||
*ppNew = pNew = sqlite3_malloc64(sizeof(Fts5Expr));
|
||||
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
|
||||
if( pNew==0 ){
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
sqlite3Fts5ParseNodeFree(sParse.pExpr);
|
||||
@@ -466,7 +466,7 @@ int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
|
||||
p2->pRoot = 0;
|
||||
|
||||
if( sParse.rc==SQLITE_OK ){
|
||||
Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc64(
|
||||
Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc(
|
||||
p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*)
|
||||
);
|
||||
if( ap==0 ){
|
||||
@@ -1549,13 +1549,7 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
|
||||
** Return SQLITE_OK if successful, or an SQLite error code otherwise. It
|
||||
** is not considered an error if the query does not match any documents.
|
||||
*/
|
||||
int sqlite3Fts5ExprFirst(
|
||||
Fts5Expr *p,
|
||||
Fts5Index *pIdx,
|
||||
i64 iFirst,
|
||||
i64 iLast,
|
||||
int bDesc
|
||||
){
|
||||
int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
|
||||
Fts5ExprNode *pRoot = p->pRoot;
|
||||
int rc; /* Return code */
|
||||
|
||||
@@ -1577,9 +1571,6 @@ int sqlite3Fts5ExprFirst(
|
||||
assert( pRoot->bEof==0 );
|
||||
rc = fts5ExprNodeNext(p, pRoot, 0, 0);
|
||||
}
|
||||
if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){
|
||||
pRoot->bEof = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
|
||||
int rc = SQLITE_OK;
|
||||
Fts5Hash *pNew;
|
||||
|
||||
*ppNew = pNew = (Fts5Hash*)sqlite3_malloc64(sizeof(Fts5Hash));
|
||||
*ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash));
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
|
||||
+39
-46
@@ -877,9 +877,9 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 *aOut = 0; /* Read blob data into this buffer */
|
||||
i64 nByte = sqlite3_blob_bytes(p->pReader);
|
||||
i64 szData = (sizeof(Fts5Data) + 7) & ~7;
|
||||
i64 nAlloc = szData + nByte + FTS5_DATA_PADDING;
|
||||
int nByte = sqlite3_blob_bytes(p->pReader);
|
||||
int szData = (sizeof(Fts5Data) + 7) & ~7;
|
||||
sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING;
|
||||
pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
|
||||
if( pRet ){
|
||||
pRet->nn = nByte;
|
||||
@@ -2074,7 +2074,6 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
|
||||
while( 1 ){
|
||||
u64 iDelta = 0;
|
||||
|
||||
if( i>=n ) break;
|
||||
if( eDetail==FTS5_DETAIL_NONE ){
|
||||
/* todo */
|
||||
if( i<n && a[i]==0 ){
|
||||
@@ -2093,7 +2092,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
|
||||
|
||||
/* If necessary, grow the pIter->aRowidOffset[] array. */
|
||||
if( iRowidOffset>=pIter->nRowidOffset ){
|
||||
i64 nNew = pIter->nRowidOffset + 8;
|
||||
int nNew = pIter->nRowidOffset + 8;
|
||||
int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int));
|
||||
if( aNew==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
@@ -5240,7 +5239,7 @@ static void fts5DoSecureDelete(
|
||||
int iSegid = pSeg->pSeg->iSegid;
|
||||
u8 *aPg = pSeg->pLeaf->p;
|
||||
int nPg = pSeg->pLeaf->nn;
|
||||
int iPgIdx = pSeg->pLeaf->szLeaf; /* Offset of page footer */
|
||||
int iPgIdx = pSeg->pLeaf->szLeaf;
|
||||
|
||||
u64 iDelta = 0;
|
||||
int iNextOff = 0;
|
||||
@@ -5319,7 +5318,7 @@ static void fts5DoSecureDelete(
|
||||
iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
|
||||
}
|
||||
assert_nc( iSOP==pSeg->iLeafOffset );
|
||||
iNextOff = iSOP + pSeg->nPos;
|
||||
iNextOff = pSeg->iLeafOffset + pSeg->nPos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5399,31 +5398,31 @@ static void fts5DoSecureDelete(
|
||||
** is another term following it on this page. So the subsequent term
|
||||
** needs to be moved to replace the term associated with the entry
|
||||
** being removed. */
|
||||
u64 nPrefix = 0;
|
||||
u64 nSuffix = 0;
|
||||
u64 nPrefix2 = 0;
|
||||
u64 nSuffix2 = 0;
|
||||
int nPrefix = 0;
|
||||
int nSuffix = 0;
|
||||
int nPrefix2 = 0;
|
||||
int nSuffix2 = 0;
|
||||
|
||||
iDelKeyOff = iNextOff;
|
||||
iNextOff += fts5GetVarint(&aPg[iNextOff], &nPrefix2);
|
||||
iNextOff += fts5GetVarint(&aPg[iNextOff], &nSuffix2);
|
||||
iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
|
||||
iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
|
||||
|
||||
if( iKey!=1 ){
|
||||
iKeyOff += fts5GetVarint(&aPg[iKeyOff], &nPrefix);
|
||||
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
|
||||
}
|
||||
iKeyOff += fts5GetVarint(&aPg[iKeyOff], &nSuffix);
|
||||
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
|
||||
|
||||
nPrefix = MIN(nPrefix, nPrefix2);
|
||||
nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
|
||||
|
||||
if( (iKeyOff+nSuffix)>(u64)iPgIdx || (iNextOff+nSuffix2)>(u64)iPgIdx ){
|
||||
if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
|
||||
FTS5_CORRUPT_IDX(p);
|
||||
}else{
|
||||
if( iKey!=1 ){
|
||||
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
|
||||
}
|
||||
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
|
||||
if( nPrefix2>(u64)pSeg->term.n ){
|
||||
if( nPrefix2>pSeg->term.n ){
|
||||
FTS5_CORRUPT_IDX(p);
|
||||
}else if( nPrefix2>nPrefix ){
|
||||
memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
|
||||
@@ -5454,7 +5453,7 @@ static void fts5DoSecureDelete(
|
||||
u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
|
||||
int nTermIdx = pTerm->nn - pTerm->szLeaf;
|
||||
int iTermIdx = 0;
|
||||
i64 iTermOff = 0;
|
||||
int iTermOff = 0;
|
||||
|
||||
while( 1 ){
|
||||
u32 iVal = 0;
|
||||
@@ -5465,15 +5464,12 @@ static void fts5DoSecureDelete(
|
||||
}
|
||||
nTermIdx = iTermIdx;
|
||||
|
||||
if( iTermOff>pTerm->szLeaf ){
|
||||
FTS5_CORRUPT_IDX(p);
|
||||
}else{
|
||||
memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
|
||||
fts5PutU16(&pTerm->p[2], iTermOff);
|
||||
fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
|
||||
if( nTermIdx==0 ){
|
||||
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
|
||||
}
|
||||
memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
|
||||
fts5PutU16(&pTerm->p[2], iTermOff);
|
||||
|
||||
fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
|
||||
if( nTermIdx==0 ){
|
||||
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
|
||||
}
|
||||
}
|
||||
fts5DataRelease(pTerm);
|
||||
@@ -5496,9 +5492,7 @@ static void fts5DoSecureDelete(
|
||||
int iPrevKeyOut = 0;
|
||||
int iKeyIn = 0;
|
||||
|
||||
if( nMove>0 ){
|
||||
memmove(&aPg[iOff], &aPg[iNextOff], nMove);
|
||||
}
|
||||
memmove(&aPg[iOff], &aPg[iNextOff], nMove);
|
||||
iPgIdx -= nShift;
|
||||
nPg = iPgIdx;
|
||||
fts5PutU16(&aPg[2], iPgIdx);
|
||||
@@ -5936,7 +5930,7 @@ int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
|
||||
fts5StructureRelease(pStruct);
|
||||
pStruct = pNew;
|
||||
nMin = 1;
|
||||
nMerge = (nMerge==SMALLEST_INT32 ? LARGEST_INT32 : (nMerge*-1));
|
||||
nMerge = nMerge*-1;
|
||||
}
|
||||
if( pStruct && pStruct->nLevel ){
|
||||
if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
|
||||
@@ -6418,16 +6412,16 @@ struct Fts5TokenDataMap {
|
||||
** aMap[] variables.
|
||||
*/
|
||||
struct Fts5TokenDataIter {
|
||||
i64 nMapAlloc; /* Allocated size of aMap[] in entries */
|
||||
i64 nMap; /* Number of valid entries in aMap[] */
|
||||
int nMapAlloc; /* Allocated size of aMap[] in entries */
|
||||
int nMap; /* Number of valid entries in aMap[] */
|
||||
Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */
|
||||
|
||||
/* The following are used for prefix-queries only. */
|
||||
Fts5Buffer terms;
|
||||
|
||||
/* The following are used for other full-token tokendata queries only. */
|
||||
i64 nIter;
|
||||
i64 nIterAlloc;
|
||||
int nIter;
|
||||
int nIterAlloc;
|
||||
Fts5PoslistReader *aPoslistReader;
|
||||
int *aPoslistToIter;
|
||||
Fts5Iter *apIter[FLEXARRAY];
|
||||
@@ -6483,11 +6477,11 @@ static void fts5TokendataIterAppendMap(
|
||||
){
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( pT->nMap==pT->nMapAlloc ){
|
||||
i64 nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
|
||||
i64 nAlloc = nNew * sizeof(Fts5TokenDataMap);
|
||||
int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
|
||||
int nAlloc = nNew * sizeof(Fts5TokenDataMap);
|
||||
Fts5TokenDataMap *aNew;
|
||||
|
||||
aNew = (Fts5TokenDataMap*)sqlite3_realloc64(pT->aMap, nAlloc);
|
||||
aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc);
|
||||
if( aNew==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return;
|
||||
@@ -6513,7 +6507,7 @@ static void fts5TokendataIterAppendMap(
|
||||
*/
|
||||
static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
|
||||
Fts5TokenDataMap *aTmp = 0;
|
||||
i64 nByte = pT->nMap * sizeof(Fts5TokenDataMap);
|
||||
int nByte = pT->nMap * sizeof(Fts5TokenDataMap);
|
||||
|
||||
aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte);
|
||||
if( aTmp ){
|
||||
@@ -6835,7 +6829,7 @@ int sqlite3Fts5IndexReinit(Fts5Index *p){
|
||||
fts5StructureInvalidate(p);
|
||||
fts5IndexDiscardData(p);
|
||||
pTmp = &uFts.sFts;
|
||||
memset(uFts.tmpSpace, 0, sizeof(uFts.tmpSpace));
|
||||
memset(pTmp, 0, SZ_FTS5STRUCTURE(1));
|
||||
if( p->pConfig->bContentlessDelete ){
|
||||
pTmp->nOriginCntr = 1;
|
||||
}
|
||||
@@ -7047,10 +7041,9 @@ static Fts5TokenDataIter *fts5AppendTokendataIter(
|
||||
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
|
||||
i64 nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
|
||||
i64 nByte = SZ_FTS5TOKENDATAITER(nAlloc+1);
|
||||
Fts5TokenDataIter *pNew;
|
||||
pNew = (Fts5TokenDataIter*)sqlite3_realloc64(pIn, nByte);
|
||||
int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
|
||||
int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1);
|
||||
Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);
|
||||
|
||||
if( pNew==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
@@ -7147,8 +7140,8 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
|
||||
|
||||
/* Ensure the token-mapping is large enough */
|
||||
if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){
|
||||
i64 nNew = (pT->nMapAlloc + nByte) * 2;
|
||||
Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc64(
|
||||
int nNew = (pT->nMapAlloc + nByte) * 2;
|
||||
Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc(
|
||||
pT->aMap, nNew*sizeof(Fts5TokenDataMap)
|
||||
);
|
||||
if( aNew==0 ){
|
||||
|
||||
+27
-73
@@ -511,17 +511,6 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
|
||||
#endif
|
||||
}
|
||||
|
||||
static void fts5SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
|
||||
#if SQLITE_VERSION_NUMBER>=3008002
|
||||
#ifndef SQLITE_CORE
|
||||
if( sqlite3_libversion_number()>=3008002 )
|
||||
#endif
|
||||
{
|
||||
pIdxInfo->estimatedRows = MAX(1, nRow);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int fts5UsePatternMatch(
|
||||
Fts5Config *pConfig,
|
||||
struct sqlite3_index_constraint *p
|
||||
@@ -586,30 +575,19 @@ static int fts5UsePatternMatch(
|
||||
** a) If a MATCH operator is present, the cost depends on the other
|
||||
** constraints also present. As follows:
|
||||
**
|
||||
** * No other constraints: cost=50000.0
|
||||
** * One rowid range constraint: cost=37500.0
|
||||
** * Both rowid range constraints: cost=30000.0
|
||||
** * An == rowid constraint: cost=25000.0
|
||||
** * No other constraints: cost=1000.0
|
||||
** * One rowid range constraint: cost=750.0
|
||||
** * Both rowid range constraints: cost=500.0
|
||||
** * An == rowid constraint: cost=100.0
|
||||
**
|
||||
** b) Otherwise, if there is no MATCH:
|
||||
**
|
||||
** * No other constraints: cost=3000000.0
|
||||
** * One rowid range constraints: cost=2250000.0
|
||||
** * Both rowid range constraint: cost=750000.0
|
||||
** * An == rowid constraint: cost=25.0
|
||||
** * No other constraints: cost=1000000.0
|
||||
** * One rowid range constraint: cost=750000.0
|
||||
** * Both rowid range constraints: cost=250000.0
|
||||
** * An == rowid constraint: cost=10.0
|
||||
**
|
||||
** Costs are not modified by the ORDER BY clause.
|
||||
**
|
||||
** The ratios used in case (a) are based on informal results obtained from
|
||||
** the tool/fts5cost.tcl script. The "MATCH and ==" combination has the
|
||||
** cost set quite high because the query may be a prefix query. Unless
|
||||
** there is a prefix index, prefix queries with rowid constraints are much
|
||||
** more expensive than non-prefix queries with rowid constraints.
|
||||
**
|
||||
** The estimated rows returned is set to the cost/40. For simple queries,
|
||||
** experimental results show that cost/4 might be about right. But for
|
||||
** more complex queries that use multiple terms the number of rows might
|
||||
** be far fewer than this. So we compromise and use cost/40.
|
||||
*/
|
||||
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
Fts5Table *pTab = (Fts5Table*)pVTab;
|
||||
@@ -642,7 +620,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
idxStr = (char*)sqlite3_malloc64((i64)pInfo->nConstraint * 8 + 1);
|
||||
idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1);
|
||||
if( idxStr==0 ) return SQLITE_NOMEM;
|
||||
pInfo->idxStr = idxStr;
|
||||
pInfo->needToFreeIdxStr = 1;
|
||||
@@ -668,7 +646,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
nSeenMatch++;
|
||||
idxStr[iIdxStr++] = 'M';
|
||||
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
|
||||
iIdxStr += (int)strlen(&idxStr[iIdxStr]);
|
||||
idxStr += strlen(&idxStr[iIdxStr]);
|
||||
assert( idxStr[iIdxStr]=='\0' );
|
||||
}
|
||||
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
|
||||
@@ -687,7 +665,6 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
idxStr[iIdxStr++] = '=';
|
||||
bSeenEq = 1;
|
||||
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
|
||||
pInfo->aConstraintUsage[i].omit = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -735,35 +712,17 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
|
||||
/* Calculate the estimated cost based on the flags set in idxFlags. */
|
||||
if( bSeenEq ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 25000.0 : 25.0;
|
||||
fts5SetEstimatedRows(pInfo, 1);
|
||||
fts5SetUniqueFlag(pInfo);
|
||||
pInfo->estimatedCost = nSeenMatch ? 1000.0 : 10.0;
|
||||
if( nSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
|
||||
}else if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 5000.0 : 250000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 7500.0 : 750000.0;
|
||||
}else{
|
||||
i64 nEstRows;
|
||||
if( nSeenMatch ){
|
||||
if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = 50000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = 37500.0;
|
||||
}else{
|
||||
pInfo->estimatedCost = 50000.0;
|
||||
}
|
||||
nEstRows = (i64)(pInfo->estimatedCost / 40.0);
|
||||
for(i=1; i<nSeenMatch; i++){
|
||||
pInfo->estimatedCost *= 2.5;
|
||||
nEstRows = nEstRows / 2;
|
||||
}
|
||||
}else{
|
||||
if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = 750000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = 2250000.0;
|
||||
}else{
|
||||
pInfo->estimatedCost = 3000000.0;
|
||||
}
|
||||
nEstRows = (i64)(pInfo->estimatedCost / 4.0);
|
||||
}
|
||||
fts5SetEstimatedRows(pInfo, nEstRows);
|
||||
pInfo->estimatedCost = nSeenMatch ? 10000.0 : 1000000.0;
|
||||
}
|
||||
for(i=1; i<nSeenMatch; i++){
|
||||
pInfo->estimatedCost *= 0.4;
|
||||
}
|
||||
|
||||
pInfo->idxNum = idxFlags;
|
||||
@@ -962,9 +921,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
|
||||
int bDesc = pCsr->bDesc;
|
||||
i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
|
||||
|
||||
rc = sqlite3Fts5ExprFirst(
|
||||
pCsr->pExpr, pTab->p.pIndex, iRowid, pCsr->iLastRowid, bDesc
|
||||
);
|
||||
rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc);
|
||||
if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
|
||||
*pbSkip = 1;
|
||||
}
|
||||
@@ -1136,9 +1093,7 @@ static int fts5CursorFirstSorted(
|
||||
static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){
|
||||
int rc;
|
||||
Fts5Expr *pExpr = pCsr->pExpr;
|
||||
rc = sqlite3Fts5ExprFirst(
|
||||
pExpr, pTab->p.pIndex, pCsr->iFirstRowid, pCsr->iLastRowid, bDesc
|
||||
);
|
||||
rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc);
|
||||
if( sqlite3Fts5ExprEof(pExpr) ){
|
||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||
}
|
||||
@@ -2106,7 +2061,6 @@ static int fts5UpdateMethod(
|
||||
}
|
||||
|
||||
update_out:
|
||||
sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
|
||||
pTab->p.pConfig->pzErrmsg = 0;
|
||||
return rc;
|
||||
}
|
||||
@@ -3647,9 +3601,9 @@ static void fts5LocaleFunc(
|
||||
sqlite3_value **apArg /* Function arguments */
|
||||
){
|
||||
const char *zLocale = 0;
|
||||
i64 nLocale = 0;
|
||||
int nLocale = 0;
|
||||
const char *zText = 0;
|
||||
i64 nText = 0;
|
||||
int nText = 0;
|
||||
|
||||
assert( nArg==2 );
|
||||
UNUSED_PARAM(nArg);
|
||||
@@ -3666,10 +3620,10 @@ static void fts5LocaleFunc(
|
||||
Fts5Global *p = (Fts5Global*)sqlite3_user_data(pCtx);
|
||||
u8 *pBlob = 0;
|
||||
u8 *pCsr = 0;
|
||||
i64 nBlob = 0;
|
||||
int nBlob = 0;
|
||||
|
||||
nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText;
|
||||
pBlob = (u8*)sqlite3_malloc64(nBlob);
|
||||
pBlob = (u8*)sqlite3_malloc(nBlob);
|
||||
if( pBlob==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return;
|
||||
@@ -3788,7 +3742,7 @@ static int fts5Init(sqlite3 *db){
|
||||
int rc;
|
||||
Fts5Global *pGlobal = 0;
|
||||
|
||||
pGlobal = (Fts5Global*)sqlite3_malloc64(sizeof(Fts5Global));
|
||||
pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
|
||||
if( pGlobal==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
|
||||
+4
-4
@@ -391,7 +391,7 @@ static int SQLITE_TCLAPI xF5tApi(
|
||||
break;
|
||||
}
|
||||
CASE(12, "xSetAuxdata") {
|
||||
F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc64(sizeof(F5tAuxData));
|
||||
F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData));
|
||||
if( pData==0 ){
|
||||
Tcl_AppendResult(interp, "out of memory", (char*)0);
|
||||
return TCL_ERROR;
|
||||
@@ -780,7 +780,7 @@ static int SQLITE_TCLAPI f5tTokenize(
|
||||
}
|
||||
|
||||
if( nText>0 ){
|
||||
pCopy = sqlite3_malloc64(nText);
|
||||
pCopy = sqlite3_malloc(nText);
|
||||
if( pCopy==0 ){
|
||||
tokenizer.xDelete(pTok);
|
||||
Tcl_AppendResult(interp, "error in sqlite3_malloc()", (char*)0);
|
||||
@@ -1420,7 +1420,7 @@ static int f5tOrigintextCreate(
|
||||
void *pTokCtx = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
pTok = (OriginTextTokenizer*)sqlite3_malloc64(sizeof(OriginTextTokenizer));
|
||||
pTok = (OriginTextTokenizer*)sqlite3_malloc(sizeof(OriginTextTokenizer));
|
||||
if( pTok==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else if( nArg<1 ){
|
||||
@@ -1480,7 +1480,7 @@ static int xOriginToken(
|
||||
int nReq = nToken + 1 + (iEnd-iStart);
|
||||
if( nReq>p->nBuf ){
|
||||
sqlite3_free(p->aBuf);
|
||||
p->aBuf = sqlite3_malloc64(nReq*2);
|
||||
p->aBuf = sqlite3_malloc(nReq*2);
|
||||
if( p->aBuf==0 ) return SQLITE_NOMEM;
|
||||
p->nBuf = nReq*2;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ static int fts5tokConnectMethod(
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab = (Fts5tokTable*)sqlite3_malloc64(sizeof(Fts5tokTable));
|
||||
pTab = (Fts5tokTable*)sqlite3_malloc(sizeof(Fts5tokTable));
|
||||
if( pTab==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -275,7 +275,7 @@ static int fts5tokBestIndexMethod(
|
||||
static int fts5tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
|
||||
Fts5tokCursor *pCsr;
|
||||
|
||||
pCsr = (Fts5tokCursor *)sqlite3_malloc64(sizeof(Fts5tokCursor));
|
||||
pCsr = (Fts5tokCursor *)sqlite3_malloc(sizeof(Fts5tokCursor));
|
||||
if( pCsr==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -347,7 +347,7 @@ static int fts5tokCb(
|
||||
if( pCsr->nRow ){
|
||||
pRow->iPos = pRow[-1].iPos + ((tflags & FTS5_TOKEN_COLOCATED) ? 0 : 1);
|
||||
}
|
||||
pRow->zToken = sqlite3_malloc64((sqlite3_int64)nToken+1);
|
||||
pRow->zToken = sqlite3_malloc(nToken+1);
|
||||
if( pRow->zToken==0 ) return SQLITE_NOMEM;
|
||||
memcpy(pRow->zToken, pToken, nToken);
|
||||
pRow->zToken[nToken] = 0;
|
||||
@@ -373,8 +373,8 @@ static int fts5tokFilterMethod(
|
||||
fts5tokResetCursor(pCsr);
|
||||
if( idxNum==1 ){
|
||||
const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
|
||||
sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]);
|
||||
pCsr->zInput = sqlite3_malloc64(nByte+1);
|
||||
int nByte = sqlite3_value_bytes(apVal[0]);
|
||||
pCsr->zInput = sqlite3_malloc(nByte+1);
|
||||
if( pCsr->zInput==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
|
||||
@@ -72,7 +72,7 @@ static int fts5AsciiCreate(
|
||||
if( nArg%2 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
p = sqlite3_malloc64(sizeof(AsciiTokenizer));
|
||||
p = sqlite3_malloc(sizeof(AsciiTokenizer));
|
||||
if( p==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -367,7 +367,7 @@ static int fts5UnicodeCreate(
|
||||
if( nArg%2 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
p = (Unicode61Tokenizer*)sqlite3_malloc64(sizeof(Unicode61Tokenizer));
|
||||
p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer));
|
||||
if( p ){
|
||||
const char *zCat = "L* N* Co";
|
||||
int i;
|
||||
@@ -590,7 +590,7 @@ static int fts5PorterCreate(
|
||||
zBase = azArg[0];
|
||||
}
|
||||
|
||||
pRet = (PorterTokenizer*)sqlite3_malloc64(sizeof(PorterTokenizer));
|
||||
pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
|
||||
if( pRet ){
|
||||
memset(pRet, 0, sizeof(PorterTokenizer));
|
||||
rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2);
|
||||
@@ -1297,7 +1297,7 @@ static int fts5TriCreate(
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
int i;
|
||||
pNew = (TrigramTokenizer*)sqlite3_malloc64(sizeof(*pNew));
|
||||
pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
|
||||
+1
-12
@@ -396,12 +396,7 @@ static int fts5VocabOpenMethod(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Restore cursor pCsr to the state it was in immediately after being
|
||||
** created by the xOpen() method.
|
||||
*/
|
||||
static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
||||
int nCol = pCsr->pFts5->pConfig->nCol;
|
||||
pCsr->rowid = 0;
|
||||
sqlite3Fts5IterClose(pCsr->pIter);
|
||||
sqlite3Fts5StructureRelease(pCsr->pStruct);
|
||||
@@ -411,12 +406,6 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
||||
pCsr->nLeTerm = -1;
|
||||
pCsr->zLeTerm = 0;
|
||||
pCsr->bEof = 0;
|
||||
pCsr->iCol = 0;
|
||||
pCsr->iInstPos = 0;
|
||||
pCsr->iInstOff = 0;
|
||||
pCsr->colUsed = 0;
|
||||
memset(pCsr->aCnt, 0, sizeof(i64)*nCol);
|
||||
memset(pCsr->aDoc, 0, sizeof(i64)*nCol);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -666,7 +655,7 @@ static int fts5VocabFilterMethod(
|
||||
const char *zCopy = (const char *)sqlite3_value_text(pLe);
|
||||
if( zCopy==0 ) zCopy = "";
|
||||
pCsr->nLeTerm = sqlite3_value_bytes(pLe);
|
||||
pCsr->zLeTerm = sqlite3_malloc64((i64)pCsr->nLeTerm+1);
|
||||
pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
|
||||
if( pCsr->zLeTerm==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
|
||||
@@ -294,39 +294,6 @@ do_execsql_test 7.0 {
|
||||
INSERT INTO x1 VALUES($doc);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Forum post: https://sqlite.org/forum/forumpost/ea4d8c9acb
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
PRAGMA encoding = 'UTF-16le';
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
}
|
||||
set v [db one {SELECT x'2a12'}]
|
||||
do_execsql_test 8.1 {
|
||||
INSERT INTO vt0 VALUES ($v);
|
||||
}
|
||||
do_execsql_test 8.2 {
|
||||
SELECT quote(c0) FROM vt0
|
||||
} {X'2A12'}
|
||||
do_execsql_test 8.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
} {}
|
||||
reset_db
|
||||
do_execsql_test 8.4 {
|
||||
PRAGMA encoding = 'UTF-16le';
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
}
|
||||
do_execsql_test 8.5 {
|
||||
INSERT INTO vt0 VALUES (x'2a12');
|
||||
}
|
||||
do_execsql_test 8.6 {
|
||||
SELECT quote(c0) FROM vt0
|
||||
} {X'2A12'}
|
||||
do_execsql_test 8.7 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
} {}
|
||||
|
||||
} ;# foreach_detail_mode...
|
||||
|
||||
|
||||
|
||||
@@ -16124,367 +16124,5 @@ do_catchsql_test 83.1 {
|
||||
SELECT * FROM t1('R*R*R*R*R*R*R*R*') WHERE (a,b)<=(current_date,0 BETWEEN 'a'<>11 AND '') ORDER BY rowid DESC;
|
||||
} {/.*fts5: corruption found/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 84.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 53248 pagesize 4096 filename c1a.txt.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 0d .....@ ........
|
||||
| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
|
||||
| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............
|
||||
| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
|
||||
| 3488: 32 74 32 0d 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
|
||||
| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
|
||||
| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
|
||||
| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
|
||||
| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
|
||||
| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
|
||||
| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
|
||||
| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
|
||||
| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
|
||||
| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
|
||||
| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
|
||||
| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
|
||||
| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
|
||||
| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
|
||||
| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
|
||||
| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
|
||||
| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
|
||||
| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
|
||||
| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i....
|
||||
| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
|
||||
| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
|
||||
| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
|
||||
| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
|
||||
| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
|
||||
| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
|
||||
| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
|
||||
| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
|
||||
| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
|
||||
| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
|
||||
| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
|
||||
| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
|
||||
| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
|
||||
| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
|
||||
| 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9.....
|
||||
| page 3 offset 8192
|
||||
| 0: 05 00 00 00 02 0f f1 00 00 00 00 0c 0f fb 0f f1 ................
|
||||
| 4064: 00 00 0b 01 03 00 1c 81 3a 84 5e 81 3a 81 3a 0a ........:.^.:.:.
|
||||
| 4080: 0a 00 00 00 0b 84 80 80 80 80 01 00 00 00 0a 0a ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
|
||||
| page 7 offset 24576
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| page 10 offset 36864
|
||||
| 0: 0d 00 00 00 02 0f e2 00 0f e2 0f ef 00 00 00 00 ................
|
||||
| 4064: 00 00 0b 01 03 00 1c 81 3a 84 5e 81 3a 81 3a 0f ........:.^.:.:.
|
||||
| 4080: 0a 03 00 24 00 00 00 00 01 01 02 00 01 01 01 09 ...$............
|
||||
| page 11 offset 40960
|
||||
| 0: 0d 00 00 00 01 00 22 00 00 22 00 00 00 00 00 00 ................
|
||||
| 32: 00 00 9f 56 84 80 80 80 80 01 04 00 bf 30 00 00 ...V.........0..
|
||||
| 48: 0f 58 02 30 30 19 02 05 01 02 05 01 02 05 16 02 .X.00...........
|
||||
| 64: 05 01 02 05 01 02 05 61 02 05 01 02 05 01 02 05 .......a........
|
||||
| 80: 13 02 05 01 02 05 01 02 05 0d 02 03 01 02 03 01 ................
|
||||
| 96: 02 03 02 09 78 66 66 66 66 66 66 66 65 81 17 02 ....xfffffffe...
|
||||
| 112: 05 01 02 05 01 02 05 01 01 31 04 02 04 01 02 04 .........1......
|
||||
| 128: 01 02 04 01 02 05 01 02 05 01 02 05 0d 02 06 01 ................
|
||||
| 144: 02 06 01 02 06 02 01 30 79 02 04 01 02 04 01 02 .......0y.......
|
||||
| 160: 04 03 02 30 30 2b 02 05 01 02 05 01 02 05 58 02 ...00+........X.
|
||||
| 176: 05 01 02 05 01 02 05 01 02 05 01 02 05 01 02 05 ................
|
||||
| 192: 16 02 05 01 02 05 01 02 05 05 06 30 30 30 30 30 ...........00000
|
||||
| 208: 30 81 0b 02 04 01 02 04 01 02 04 10 02 05 01 02 0...............
|
||||
| 224: 05 01 02 05 03 02 32 34 76 02 05 01 02 05 01 02 ......24v.......
|
||||
| 240: 05 02 01 38 07 02 04 01 02 04 01 02 04 01 01 32 ...8...........2
|
||||
| 256: 28 02 04 01 02 04 01 02 04 04 02 05 01 02 05 01 (...............
|
||||
| 272: 02 05 02 01 30 1f 02 05 01 02 05 01 02 05 03 02 ....0...........
|
||||
| 288: 30 30 10 02 05 01 02 05 01 02 05 6a 02 04 01 02 00.........j....
|
||||
| 304: 04 01 02 04 02 08 35 30 30 30 30 30 30 30 81 26 ......50000000.&
|
||||
| 320: 02 05 01 02 05 01 02 05 01 01 33 07 02 06 01 02 ..........3.....
|
||||
| 336: 06 01 02 06 81 2c 02 04 01 02 04 01 02 04 02 04 .....,..........
|
||||
| 352: 32 37 36 36 81 23 02 05 01 02 05 01 02 05 01 01 2766.#..........
|
||||
| 368: 34 13 02 05 01 02 05 01 02 05 02 03 30 39 36 1c 4...........096.
|
||||
| 384: 02 05 01 02 05 01 02 05 07 02 05 01 02 05 01 02 ................
|
||||
| 400: 05 01 03 35 30 30 7f 02 05 01 02 05 01 02 05 04 ...500..........
|
||||
| 416: 02 30 30 81 0e 02 06 01 02 06 01 02 06 06 03 30 .00............0
|
||||
| 432: 30 30 81 11 02 04 01 02 04 01 02 04 01 05 36 35 00............65
|
||||
| 448: 35 33 36 81 1a 02 05 01 02 05 01 02 05 01 04 38 536............8
|
||||
| 464: 31 39 32 81 02 02 06 01 02 06 01 02 06 01 05 61 192............a
|
||||
| 480: 6c 6c 6f 77 01 02 02 01 02 02 01 02 02 02 02 72 llow...........r
|
||||
| 496: 67 81 08 02 04 01 02 04 01 02 04 02 05 74 6f 6d g............tom
|
||||
| 512: 69 63 04 02 02 01 02 02 01 02 02 03 06 74 61 63 ic...........tac
|
||||
| 528: 68 65 64 79 02 03 01 02 03 01 02 03 02 0d 75 74 hedy..........ut
|
||||
| 544: 6f 63 68 65 63 6b 70 6f 69 6e 74 2b 02 04 01 02 ocheckpoint+....
|
||||
| 560: 04 01 02 04 05 06 76 61 63 75 75 6d 0d 02 03 01 ......vacuum....
|
||||
| 576: 02 03 01 02 03 01 06 62 69 6e 61 72 79 03 06 01 .......binary...
|
||||
| 592: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 608: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 624: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 640: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 656: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 672: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 688: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 704: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 720: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 736: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 752: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 768: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 784: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 800: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 816: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 832: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 848: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 864: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 880: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 896: 01 02 02 02 07 79 74 65 63 6f 64 65 37 02 03 01 .....ytecode7...
|
||||
| 912: 02 03 01 02 03 01 05 63 61 63 68 65 10 02 03 01 .......cache....
|
||||
| 928: 02 03 01 01 03 02 04 6c 61 6e 67 07 02 03 01 02 .......lang.....
|
||||
| 944: 03 01 02 03 02 05 6f 6c 75 6d 6e 7c 02 03 01 02 ......olumn|....
|
||||
| 960: 03 01 02 03 03 06 6d 6d 65 6e 74 73 43 02 04 01 ......mmentsC...
|
||||
| 976: 02 04 01 02 04 04 05 70 69 6c 65 72 07 02 02 01 .......piler....
|
||||
| 992: 02 02 01 02 02 05 04 6f 75 6e 64 7f 02 03 01 02 .......ound.....
|
||||
| 1008: 03 01 02 03 03 03 75 6e 74 81 17 02 04 01 02 04 ......unt.......
|
||||
| 1024: 01 02 04 02 05 75 72 73 6f 72 3a 02 03 01 02 03 .....ursor:.....
|
||||
| 1040: 01 02 03 01 06 64 62 70 61 67 65 3d 02 03 01 02 .....dbpage=....
|
||||
| 1056: 03 01 02 03 03 04 73 74 61 74 40 02 03 01 02 03 ......stat@.....
|
||||
| 1072: 01 02 03 02 04 65 62 75 67 0a 02 02 01 02 02 01 .....ebug.......
|
||||
| 1088: 02 02 03 05 66 61 75 6c 74 0d 02 02 01 02 02 01 ....fault.......
|
||||
| 1104: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1120: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1136: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1152: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1168: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1184: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1200: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 4f 02 ..............O.
|
||||
| 1216: 03 01 02 03 01 02 03 03 03 70 74 68 81 05 02 04 .........pth....
|
||||
| 1232: 01 02 04 01 02 04 19 02 04 01 02 04 01 02 04 02 ................
|
||||
| 1248: 05 69 72 65 63 74 34 02 02 01 02 02 01 02 02 01 .irect4.........
|
||||
| 1264: 06 65 6e 61 62 6c 65 37 02 02 01 02 02 01 02 02 .enable7........
|
||||
| 1280: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1296: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1312: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1328: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1344: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1360: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1376: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1392: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1408: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1424: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1440: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1456: 02 01 02 02 02 06 78 70 6c 61 69 6e 43 02 03 01 ......xplainC...
|
||||
| 1472: 02 03 01 02 03 04 01 72 81 05 02 03 01 02 03 01 .......r........
|
||||
| 1488: 02 03 03 07 74 65 6e 73 69 6f 6e 81 2f 02 04 01 ....tension./...
|
||||
| 1504: 02 04 01 02 04 01 04 66 69 6c 65 13 02 03 01 02 .......file.....
|
||||
| 1520: 03 01 02 03 02 05 6f 72 6d 61 74 13 02 04 01 02 ......ormat.....
|
||||
| 1536: 04 01 02 04 02 03 74 73 33 46 02 03 01 02 03 01 ......ts3F......
|
||||
| 1552: 02 03 01 02 03 01 02 03 01 02 03 04 01 34 4c 02 .............4L.
|
||||
| 1568: 03 01 02 03 01 02 03 04 01 35 4f 02 03 01 02 03 .........5O.....
|
||||
| 1584: 01 02 03 02 03 75 6e 63 5e 02 05 01 02 05 01 02 .....unc^.......
|
||||
| 1600: 05 05 04 74 69 6f 6e 73 02 05 01 02 05 01 02 05 ...tions........
|
||||
| 1616: 13 02 03 01 02 03 01 02 03 09 01 73 55 02 04 01 ...........sU...
|
||||
| 1632: 02 04 01 02 04 01 07 67 65 6f 70 6f 6c 79 52 02 .......geopolyR.
|
||||
| 1648: 03 01 02 03 01 02 03 01 05 68 69 6e 74 73 3a 02 .........hints:.
|
||||
| 1664: 04 01 02 04 01 02 04 02 03 6f 6f 6b 61 02 04 01 .........ooka...
|
||||
| 1680: 02 04 01 02 04 01 02 69 6e 01 02 04 01 02 04 01 .......in.......
|
||||
| 1696: 02 04 03 04 69 74 73 7a 1f 02 04 01 02 04 01 02 ....itsz........
|
||||
| 1712: 04 03 08 74 72 69 6e 73 69 63 73 04 02 03 01 02 ...trinsics.....
|
||||
| 1728: 03 01 02 03 01 07 6a 6f 75 72 6e 61 6c 16 02 03 ......journal...
|
||||
| 1744: 01 02 03 01 02 03 01 06 6c 65 6e 67 74 68 81 0b ........length..
|
||||
| 1760: 02 03 01 02 03 01 02 03 01 02 05 01 02 05 01 02 ................
|
||||
| 1776: 05 0d 02 04 01 02 04 01 02 04 02 03 69 6b 65 81 ............ike.
|
||||
| 1792: 0e 02 03 01 02 03 01 02 03 03 03 6d 69 74 16 02 ...........mit..
|
||||
| 1808: 05 01 02 05 01 02 05 5e 02 04 01 02 04 01 02 04 .......^........
|
||||
| 1824: 02 03 6f 61 64 81 2f 02 03 01 02 03 01 02 03 01 ..oad./.........
|
||||
| 1840: 06 6d 61 6c 6c 6f 63 76 02 02 01 02 02 01 02 02 .mallocv........
|
||||
| 1856: 3a 02 03 01 02 03 01 02 03 03 02 74 68 55 02 03 :..........thU..
|
||||
| 1872: 01 02 03 01 02 03 03 01 78 79 02 02 01 02 02 01 ........xy......
|
||||
| 1888: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1904: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1920: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1936: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1952: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1968: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1984: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 2000: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 2016: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 2032: 02 02 02 05 65 6d 6f 72 79 81 11 02 03 01 02 03 ....emory.......
|
||||
| 2048: 01 02 03 04 04 73 79 73 35 58 02 03 01 02 03 01 .....sys5X......
|
||||
| 2064: 02 03 02 03 6d 61 70 19 02 03 01 02 03 01 02 03 ....map.........
|
||||
| 2080: 79 02 03 01 02 03 01 02 03 02 04 75 74 65 78 81 y..........utex.
|
||||
| 2096: 2c 02 02 01 02 02 01 02 02 01 06 6e 6f 63 61 73 ,..........nocas
|
||||
| 2112: 65 02 06 01 02 02 03 06 01 02 02 03 06 01 02 02 e...............
|
||||
| 2128: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2144: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2160: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2176: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2192: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2208: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2224: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2240: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2256: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2272: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2288: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2304: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2320: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2336: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2352: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2368: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2384: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2400: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2416: 02 02 03 06 01 02 02 03 07 72 6d 61 6c 69 7a 65 .........rmalize
|
||||
| 2432: 5b 02 03 01 02 03 01 02 03 02 05 75 6d 62 65 72 [..........umber
|
||||
| 2448: 81 23 02 04 01 02 04 01 02 04 01 06 6f 66 66 73 .#..........offs
|
||||
| 2464: 65 74 5e 02 03 01 02 03 01 02 03 02 03 6d 69 74 et^..........mit
|
||||
| 2480: 81 2c 02 03 01 02 03 01 02 03 01 02 02 01 02 02 .,..............
|
||||
| 2496: 01 02 02 02 01 70 81 26 02 04 01 02 04 01 02 04 .....p.&........
|
||||
| 2512: 02 07 76 65 72 66 6c 6f 77 34 02 03 01 02 03 01 ..verflow4......
|
||||
| 2528: 02 03 01 04 70 61 67 65 1c 02 03 01 02 03 01 02 ....page........
|
||||
| 2544: 03 64 02 04 01 02 04 01 02 04 13 02 03 01 02 03 .d..............
|
||||
| 2560: 01 02 03 01 02 03 01 02 03 01 02 03 03 09 72 65 ..............re
|
||||
| 2576: 6e 74 68 65 73 69 73 49 02 04 01 02 04 01 02 04 nthesisI........
|
||||
| 2592: 03 05 74 74 65 72 6e 81 0e 02 04 01 02 04 01 02 ..ttern.........
|
||||
| 2608: 04 02 05 63 61 63 68 65 1f 02 03 01 02 03 01 02 ...cache........
|
||||
| 2624: 03 02 08 72 65 75 70 64 61 74 65 61 02 03 01 02 ...reupdatea....
|
||||
| 2640: 03 01 02 03 01 04 72 65 61 64 34 02 04 01 02 04 ......read4.....
|
||||
| 2656: 01 02 04 03 07 63 75 72 73 69 76 65 22 02 03 01 .....cursive....
|
||||
| 2672: 02 03 01 02 03 02 04 6f 77 69 64 01 02 03 01 02 .......owid.....
|
||||
| 2688: 03 01 02 03 02 04 74 72 65 65 64 02 03 01 02 03 ......treed.....
|
||||
| 2704: 01 02 03 04 02 69 6d 01 06 01 02 02 03 06 01 02 .....im.........
|
||||
| 2720: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2736: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2752: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2768: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2784: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2800: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2816: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2832: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2848: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2864: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2880: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2896: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2912: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2928: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2944: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2960: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2976: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2992: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 3008: 01 02 02 03 06 01 02 02 03 06 01 02 02 01 0a 73 ...............s
|
||||
| 3024: 63 61 6e 73 74 61 74 75 73 70 02 04 01 02 04 01 canstatusp......
|
||||
| 3040: 02 04 02 05 65 63 74 6f 72 25 02 03 01 02 03 01 ....ector%......
|
||||
| 3056: 02 03 03 04 6c 65 63 74 7f 02 04 01 02 04 01 02 ....lect........
|
||||
| 3072: 04 03 05 73 73 69 6f 6e 67 02 03 01 02 03 01 02 ...ssiong.......
|
||||
| 3088: 03 02 03 69 7a 65 10 02 04 01 02 04 01 02 04 04 ...ize..........
|
||||
| 3104: 02 04 01 02 04 01 02 04 01 02 04 01 02 04 01 02 ................
|
||||
| 3120: 04 01 02 04 01 02 04 01 02 04 07 02 04 01 02 04 ................
|
||||
| 3136: 01 02 04 5b 02 05 01 02 05 01 02 05 10 02 04 01 ...[............
|
||||
| 3152: 02 04 01 02 04 04 02 04 01 02 04 01 02 04 02 03 ................
|
||||
| 3168: 6f 66 74 76 02 03 01 02 03 01 02 03 02 02 71 6c oftv..........ql
|
||||
| 3184: 5e 02 04 01 02 04 01 02 04 13 02 04 01 02 04 01 ^...............
|
||||
| 3200: 02 04 28 02 03 01 02 03 01 02 03 02 04 74 61 74 ..(..........tat
|
||||
| 3216: 34 6a 02 03 01 02 03 01 02 03 03 02 6d 74 70 02 4j..........mtp.
|
||||
| 3232: 03 01 02 03 01 02 03 05 04 76 74 61 62 6d 02 03 .........vtabm..
|
||||
| 3248: 01 02 03 01 02 03 03 03 6f 72 65 81 35 02 03 01 ........ore.5...
|
||||
| 3264: 02 03 01 02 03 02 0a 79 6e 63 68 72 6f 6e 6f 75 .......ynchronou
|
||||
| 3280: 73 28 02 03 01 02 03 01 02 03 04 02 04 01 02 04 s(..............
|
||||
| 3296: 01 02 04 03 04 73 74 65 6d 81 32 02 02 01 02 02 .....stem.2.....
|
||||
| 3312: 01 02 02 01 04 74 65 6d 70 81 35 02 02 01 02 02 .....temp.5.....
|
||||
| 3328: 01 02 02 02 06 68 72 65 61 64 73 31 02 04 01 02 .....hreads1....
|
||||
| 3344: 04 01 02 04 76 02 04 01 02 04 01 02 04 08 03 61 ....v..........a
|
||||
| 3360: 66 65 81 38 02 02 01 02 02 01 02 02 02 06 72 69 fe.8..........ri
|
||||
| 3376: 67 67 65 72 81 20 02 03 01 02 03 01 02 03 08 01 gger. ..........
|
||||
| 3392: 73 22 02 04 01 02 04 01 02 04 01 07 75 6e 6b 6e s...........unkn
|
||||
| 3408: 6f 77 6e 73 02 03 01 02 03 01 02 03 01 08 76 61 owns..........va
|
||||
| 3424: 72 69 61 62 6c 65 81 23 02 03 01 02 03 01 02 03 riable.#........
|
||||
| 3440: 02 03 64 62 65 81 26 02 03 01 02 03 01 02 03 02 ..dbe.&.........
|
||||
| 3456: 03 69 65 77 01 02 05 01 02 05 01 02 05 02 03 74 .iew...........t
|
||||
| 3472: 61 62 37 02 04 01 02 04 01 02 04 04 02 04 01 02 ab7.............
|
||||
| 3488: 04 01 02 04 01 02 04 01 02 04 01 02 04 01 03 77 ...............w
|
||||
| 3504: 61 6c 2b 02 03 01 02 03 01 02 03 01 02 03 01 02 al+.............
|
||||
| 3520: 03 01 02 03 02 05 6f 72 6b 65 72 31 02 03 01 02 ......orker1....
|
||||
| 3536: 03 01 02 03 76 02 03 01 02 03 01 02 03 01 01 78 ....v..........x
|
||||
| 3552: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3568: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3584: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3600: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3616: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3632: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3648: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3664: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3680: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3696: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3712: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3728: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3744: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3760: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3776: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3792: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3808: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3824: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3840: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3856: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3872: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3888: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3904: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3920: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3936: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3952: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3968: 06 01 01 02 01 06 04 30 15 1e 0c 28 1b 0d 0c 15 .......0...(....
|
||||
| 3984: 0c 16 14 16 10 0c 17 0e 0e 0f 11 10 10 0e 10 11 ................
|
||||
| 4000: 18 11 82 3e 12 10 0f 10 11 10 0f 0f 10 11 0f 0f ...>............
|
||||
| 4016: 81 05 18 10 81 45 11 0d 13 0f 10 17 0c 0c 0e 18 .....E..........
|
||||
| 4032: 0c 12 10 0e 0d 0f 13 12 24 0f 17 0f 1a 0d 81 1c ........$.......
|
||||
| 4048: 11 0f 17 10 82 3e 12 11 11 18 0d 12 2a 14 11 10 .....>......*...
|
||||
| 4064: 13 0f 12 0f 0f 82 3a 15 10 0f 10 4d 0e 1f 0f 0d ......:....M....
|
||||
| 4080: 0f 0f 1e 10 10 1a 0f 12 0c 12 14 0f 0e 20 17 19 ............. ..
|
||||
| page 12 offset 45056
|
||||
| 0: 0d 00 00 00 01 0d f4 00 0d f4 00 00 00 00 00 00 ................
|
||||
| 3568: 00 00 00 00 84 04 84 80 80 80 80 02 04 00 88 0c ................
|
||||
| 3584: 00 07 02 00 01 01 02 56 06 01 01 02 01 06 01 01 .......V........
|
||||
| 3600: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3616: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3632: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3648: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3664: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3680: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3696: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3712: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3728: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3744: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3760: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3776: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3792: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3808: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3824: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3840: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3856: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3872: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3888: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3904: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3920: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3936: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3952: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3968: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3984: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 4000: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 4016: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 4032: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 4048: 52 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 R...............
|
||||
| 4064: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 4080: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| end c1a.txt.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 84.1 {
|
||||
SELECT * FROM t1('R*R*x') ORDER BY rowid DESC;
|
||||
} {1 {fts5: corruption found reading blob 137438953475 from table "t1"}}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
finish_test
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,53 +0,0 @@
|
||||
# 2025 October 13
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This test is focused on really large position lists. Those that require
|
||||
# 4 or 5 byte position-list size varints. Because of the amount of memory
|
||||
# required, these tests only run on 64-bit platforms.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5corruptbig
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
if { $tcl_platform(wordSize)<8 } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
if { $SQLITE_MAX_LENGTH!=0x7FFFFFFF } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
UPDATE t1_data SET block = zeroblob(2147483640) WHERE id=10;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT id, length(block) FROM t1_data
|
||||
} {1 0 10 2147483640}
|
||||
|
||||
do_catchsql_test 1.3 {
|
||||
SELECT * FROM t1('abc')
|
||||
} {1 {out of memory}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -379,6 +379,9 @@ do_execsql_test 12.2 {
|
||||
db close
|
||||
sqlite3 db test.db -readonly 1
|
||||
|
||||
explain_i {
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
do_execsql_test 12.3 {
|
||||
PRAGMA integrity_check
|
||||
} {ok}
|
||||
|
||||
@@ -64,21 +64,4 @@ foreach {tn sql} {
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Verify that https://sqlite.org/forum/forumpost/95413eb410 has been
|
||||
# fixed.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE f1 USING fts5(x);
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO f1(x) VALUES('abc def ghi');
|
||||
}
|
||||
do_test 2.1 {
|
||||
sqlite3_interrupt db
|
||||
} {}
|
||||
do_execsql_test 2.2 {
|
||||
ROLLBACK
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
# 2014 June 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.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5join
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE vt USING fts5(x);
|
||||
INSERT INTO vt VALUES('abc');
|
||||
INSERT INTO vt VALUES('xyz');
|
||||
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TIMESTAMP);
|
||||
INSERT INTO t1 VALUES(1, 1), (2, 2);
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
}
|
||||
|
||||
# set sqlite_where_trace [expr 0xFFF]
|
||||
|
||||
do_eqp_test 1.1 {
|
||||
SELECT * FROM vt, t1 WHERE vt.rowid = t1.rowid ORDER BY t1.rowid;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t1
|
||||
`--SCAN vt VIRTUAL TABLE INDEX 0:=
|
||||
}
|
||||
|
||||
do_eqp_test 1.2 {
|
||||
SELECT * FROM vt, t1 WHERE vt.rowid = t1.rowid AND b>? ORDER BY b LIMIT 10
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SEARCH t1 USING COVERING INDEX i1 (b>?)
|
||||
`--SCAN vt VIRTUAL TABLE INDEX 0:=
|
||||
}
|
||||
|
||||
do_eqp_test 1.3 {
|
||||
SELECT * FROM vt, t1 WHERE vt.rowid = t1.rowid AND b>?
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SEARCH t1 USING COVERING INDEX i1 (b>?)
|
||||
`--SCAN vt VIRTUAL TABLE INDEX 0:=
|
||||
}
|
||||
|
||||
do_eqp_test 1.4 {
|
||||
SELECT * FROM vt, t1 WHERE vt.rowid = t1.rowid ORDER BY b
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t1 USING COVERING INDEX i1
|
||||
`--SCAN vt VIRTUAL TABLE INDEX 0:=
|
||||
}
|
||||
|
||||
do_eqp_test 1.5 {
|
||||
SELECT * FROM vt, t1
|
||||
WHERE vt.rowid = t1.rowid AND vt MATCH ? AND b = ?
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN vt VIRTUAL TABLE INDEX 0:M1
|
||||
`--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -238,22 +238,6 @@ do_execsql_test 6.3 {
|
||||
INSERT INTO g1(g1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Check that passing -2147483648 as the parameter to a merge command
|
||||
# does not cause a signed integer overflow error.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE VIRTUAL TABLE f1 USING fts5(a);
|
||||
}
|
||||
do_execsql_test 7.1 {
|
||||
INSERT INTO f1 VALUES('one two three');
|
||||
INSERT INTO f1 VALUES('four five six');
|
||||
INSERT INTO f1 VALUES('seven eight nine');
|
||||
}
|
||||
do_execsql_test 7.2 {
|
||||
INSERT INTO f1(f1, rank) VALUES('merge', -2147483648);
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -685,17 +685,5 @@ do_execsql_test 26.1 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 27.0 {
|
||||
CREATE VIRTUAL TABLE ft1 USING fts5(a, b);
|
||||
INSERT INTO ft1(rowid, a, b) VALUES(3, '3', '3');
|
||||
}
|
||||
|
||||
do_execsql_test 27.1 {
|
||||
SELECT * FROM ft1 WHERE rowid=3 AND b MATCH 'hello';
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -38,15 +38,15 @@ foreach {tn sql uses} {
|
||||
1.2 { DELETE FROM ft WHERE rowid=? } 0
|
||||
1.3 { DELETE FROM ft WHERE rowid=? } 0
|
||||
1.4 { DELETE FROM ft WHERE ft MATCH '1' } 1
|
||||
1.5 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 0
|
||||
1.6 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 0
|
||||
1.5 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1
|
||||
1.6 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1
|
||||
|
||||
2.1 { UPDATE ft SET content='a b c' } 1
|
||||
2.2 { UPDATE ft SET content='a b c' WHERE rowid=? } 0
|
||||
2.3 { UPDATE ft SET content='a b c' WHERE rowid=? } 0
|
||||
2.4 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' } 1
|
||||
2.5 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 0
|
||||
2.6 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 0
|
||||
2.5 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1
|
||||
2.6 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1
|
||||
} {
|
||||
do_test 1.$tn { sql_uses_stmt db $sql } $uses
|
||||
}
|
||||
|
||||
@@ -305,28 +305,6 @@ do_catchsql_test 6.2 {
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b);
|
||||
CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, col);
|
||||
|
||||
INSERT INTO t1 VALUES('xx', 'xx');
|
||||
|
||||
CREATE TABLE x1(t);
|
||||
INSERT INTO x1 VALUES('xx');
|
||||
INSERT INTO x1 VALUES('xx');
|
||||
|
||||
SELECT term, col FROM v1;
|
||||
} {
|
||||
xx a xx b
|
||||
}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
SELECT * FROM x1 WHERE 'a'=(SELECT col FROM v1 WHERE term=t)
|
||||
} {xx xx}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
#
|
||||
# 2026 March 20
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#--------------------------------------------------------------------------
|
||||
#
|
||||
# This script extracts the documentation for the API used by fts5 auxiliary
|
||||
# functions from header file fts5.h. It outputs html text on stdout that
|
||||
# is included in the documentation on the web.
|
||||
#
|
||||
|
||||
|
||||
sqlite3 db fts5cost.db
|
||||
|
||||
# Create an IPK table with 1,000,000 entries. Short records.
|
||||
#
|
||||
set res [list [catch { db eval {SELECT count(*) FROM t1} } msg] $msg]
|
||||
if {$res!="0 1000000"} {
|
||||
db eval {
|
||||
PRAGMA mmap_size = 1000000000; -- 1GB
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
|
||||
)
|
||||
INSERT INTO t1 SELECT i, hex(randomblob(8)) FROM s;
|
||||
}
|
||||
}
|
||||
|
||||
# Create an FTS5 table with 1,000,000 entries. Each row contains a single
|
||||
# column containing a document of 100 terms chosen pseudo-randomly from
|
||||
# a vocabularly of 2000.
|
||||
set res [list [catch { db eval {SELECT count(*) FROM f1} } msg] $msg]
|
||||
if {$res!="0 1000000"} {
|
||||
set nVocab 2000
|
||||
set nTerm 100
|
||||
db eval {
|
||||
BEGIN;
|
||||
DROP TABLE IF EXISTS vocab1;
|
||||
CREATE TABLE vocab1(w);
|
||||
}
|
||||
for {set ii 0} {$ii<$nVocab} {incr ii} {
|
||||
set word [format %06x [expr {int(abs(rand()) * 0xFFFFFF)}]]
|
||||
db eval { INSERT INTO vocab1 VALUES($word) }
|
||||
lappend lVocab $word
|
||||
}
|
||||
db func doc doc
|
||||
proc doc {} {
|
||||
for {set ii 0} {$ii<$::nTerm} {incr ii} {
|
||||
lappend ret [lindex $::lVocab [expr int(abs(rand())*$::nVocab)]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS f1;
|
||||
CREATE VIRTUAL TABLE f1 USING fts5(x);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
|
||||
)
|
||||
INSERT INTO f1(rowid, x) SELECT i, doc() FROM s;
|
||||
COMMIT;
|
||||
}
|
||||
} else {
|
||||
set lVocab [db eval { SELECT * FROM vocab1 }]
|
||||
set nVocab [llength $lVocab]
|
||||
}
|
||||
|
||||
proc rowid_query {n} {
|
||||
set rowid 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
db eval { SELECT b FROM t1 WHERE a = $rowid }
|
||||
set rowid [expr {($rowid + 7717) % 1000000}]
|
||||
}
|
||||
}
|
||||
|
||||
proc rowid_query_fts {n} {
|
||||
set rowid 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
db eval { SELECT * FROM f1 WHERE rowid = $rowid }
|
||||
set rowid [expr {($rowid + 7717) % 1000000}]
|
||||
}
|
||||
}
|
||||
|
||||
proc match_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match [lrange $::lVocab $idx $idx+1]
|
||||
db eval { SELECT * FROM f1($match) }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc prefix_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]*"
|
||||
db eval { SELECT * FROM f1($match) }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc match_rowid_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]"
|
||||
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc prefix_rowid_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]*"
|
||||
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
proc mytime {cmd div} {
|
||||
set tm [time $cmd]
|
||||
expr {[lindex $tm 0] / $div}
|
||||
}
|
||||
|
||||
#set us [mytime { match_rowid_query_fts 1000 } 1000]
|
||||
#puts "1000 match/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
|
||||
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { match_query_fts 10 } 10]
|
||||
puts "10 match queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_query_fts 10 } 10]
|
||||
puts "10 prefix queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
|
||||
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { rowid_query 10000 } 10000]
|
||||
puts "10000 by-rowid queries on normal table: ${us} per query"
|
||||
|
||||
set us [mytime { rowid_query_fts 10000 } 10000]
|
||||
puts "10000 by-rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
|
||||
@@ -139,7 +139,6 @@ do_test 2.3 {
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
|
||||
db eval {
|
||||
PRAGMA writable_schema=on;
|
||||
DELETE FROM imp1 WHERE rowid=1;
|
||||
DELETE FROM imp2 WHERE rowid=2;
|
||||
}
|
||||
@@ -175,7 +174,6 @@ do_test 3.2 {
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
|
||||
db eval {
|
||||
PRAGMA writable_schema=on;
|
||||
DELETE FROM imp1 WHERE a=5;
|
||||
}
|
||||
execsql_pp {
|
||||
|
||||
@@ -29,7 +29,6 @@ do_execsql_test 1.0 {
|
||||
proc imposter_edit {obj create sql} {
|
||||
sqlite3 xdb test.db
|
||||
set pgno [xdb one {SELECT rootpage FROM sqlite_schema WHERE name=$obj}]
|
||||
xdb eval {PRAGMA Writable_schema=ON}
|
||||
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER xdb main 1 $pgno
|
||||
xdb eval $create
|
||||
|
||||
@@ -160,7 +160,6 @@ static char *intckMprintf(sqlite3_intck *p, const char *zFmt, ...){
|
||||
sqlite3_free(zRet);
|
||||
zRet = 0;
|
||||
}
|
||||
va_end(ap);
|
||||
return zRet;
|
||||
}
|
||||
|
||||
@@ -319,7 +318,7 @@ static int intckGetToken(const char *z){
|
||||
char c = z[0];
|
||||
int iRet = 1;
|
||||
if( c=='\'' || c=='"' || c=='`' ){
|
||||
while( z[iRet] ){
|
||||
while( 1 ){
|
||||
if( z[iRet]==c ){
|
||||
iRet++;
|
||||
if( z[iRet]!=c ) break;
|
||||
|
||||
+16
-19
@@ -13,14 +13,11 @@ Technical support is available in the forum:
|
||||
<https://sqlite.org/forum>
|
||||
|
||||
|
||||
> **FOREWARNING:** the JNI subproject is experimental and subject to
|
||||
any number of changes. This API is "feature-complete", with only a
|
||||
few difficult-to-reach corners of the C API not represented here,
|
||||
but it is not a supported deliverable of the project so does not
|
||||
have same backward compatibility guarantees which the C APIs
|
||||
do. That said: the [C-style API](#1to1ish) is especially resistent
|
||||
to compatibility breakage because it's designed to be as close to
|
||||
the C API as feasible.
|
||||
> **FOREWARNING:** this subproject is very much in development and
|
||||
subject to any number of changes. Please do not rely on any
|
||||
information about its API until this disclaimer is removed. The JNI
|
||||
bindings released with version 3.43 are a "tech preview." Once
|
||||
finalized, strong backward compatibility guarantees will apply.
|
||||
|
||||
Project goals/requirements:
|
||||
|
||||
@@ -165,13 +162,11 @@ or propagate exceptions and must return error information (if any) via
|
||||
result codes or `null`. The only cases where the C-style APIs may
|
||||
throw is through client-side misuse, e.g. passing in a null where it
|
||||
may cause a `NullPointerException`. The APIs clearly mark function
|
||||
parameters which should not be null, and it internally uses the
|
||||
`SQLITE_API_ARMOR` mechanism to help product against such misuse. Some
|
||||
C-style APIs explicitly accept `null` as a no-op for usability's sake,
|
||||
and some of the JNI APIs deliberately return an error code, instead of
|
||||
segfaulting, when passed a `null`. There are no known cases where it
|
||||
will misuse memory if passed a `null` or out-of-range value from
|
||||
client code.
|
||||
parameters which should not be null, but does not generally actively
|
||||
defend itself against such misuse. Some C-style APIs explicitly accept
|
||||
`null` as a no-op for usability's sake, and some of the JNI APIs
|
||||
deliberately return an error code, instead of segfaulting, when passed
|
||||
a `null`.
|
||||
|
||||
Client-defined callbacks _must never throw exceptions_ unless _very
|
||||
explicitly documented_ as being throw-safe. Exceptions are generally
|
||||
@@ -199,8 +194,7 @@ Some constructs, when modelled 1-to-1 from C to Java, are unduly
|
||||
clumsy to work with in Java because they try to shoehorn C's way of
|
||||
doing certain things into Java's wildly different ways. The following
|
||||
subsections cover those, starting with a verbose explanation and
|
||||
demonstration of where such changes are "really necessary" for
|
||||
usability's sake...
|
||||
demonstration of where such changes are "really necessary"...
|
||||
|
||||
### Custom Collations
|
||||
|
||||
@@ -292,9 +286,12 @@ binding. The Java API has only one core function-registration function:
|
||||
|
||||
```java
|
||||
int sqlite3_create_function(sqlite3 db, String funcName, int nArgs,
|
||||
int flags, SQLFunction func);
|
||||
int encoding, SQLFunction func);
|
||||
```
|
||||
|
||||
> Design question: does the encoding argument serve any purpose in
|
||||
Java? That's as-yet undetermined. If not, it will be removed.
|
||||
|
||||
`SQLFunction` is not used directly, but is instead instantiated via
|
||||
one of its three subclasses:
|
||||
|
||||
@@ -316,4 +313,4 @@ in-flux nature of this API.
|
||||
Various APIs which accept callbacks, e.g. `sqlite3_trace_v2()` and
|
||||
`sqlite3_update_hook()`, use interfaces similar to those shown above.
|
||||
Despite the changes in signature, the JNI layer makes every effort to
|
||||
provide the same semantics as the C API documentation describes.
|
||||
provide the same semantics as the C API documentation suggests.
|
||||
|
||||
+55
-64
@@ -133,9 +133,11 @@
|
||||
** Which sqlite3.c we're using needs to be configurable to enable
|
||||
** building against a custom copy, e.g. the SEE variant. We have to
|
||||
** include sqlite3.c, as opposed to sqlite3.h, in order to get access
|
||||
** to some internal details like SQLITE_MAX_... and friends, and keep
|
||||
** those consistent with this build. This increases the rebuild time
|
||||
** considerably, however.
|
||||
** to some internal details like SQLITE_MAX_... and friends. This
|
||||
** increases the rebuild time considerably but we need this in order
|
||||
** to access some internal functionality and keep the to-Java-exported
|
||||
** values of SQLITE_MAX_... and SQLITE_LIMIT_... in sync with the C
|
||||
** build.
|
||||
*/
|
||||
#ifndef SQLITE_C
|
||||
# define SQLITE_C sqlite3.c
|
||||
@@ -166,10 +168,6 @@
|
||||
** Creates a verbose JNI function name. Suffix must be
|
||||
** the JNI-mangled form of the function's name, minus the
|
||||
** prefix seen in this macro.
|
||||
**
|
||||
** If you get java.lang.UnsatisfiedLinkError when calling newly-added
|
||||
** native bindings, be sure that the mangled name is correct. It can
|
||||
** be found in the generated sqlite3-jni.h.
|
||||
*/
|
||||
#define JniFuncName(Suffix) \
|
||||
Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
|
||||
@@ -179,10 +177,10 @@
|
||||
JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
|
||||
|
||||
/*
|
||||
** S3JniApi's intent is that CFunc be the name(s) of the C API func(s)
|
||||
** the being-declared JNI function is wrapping, making it easier to
|
||||
** find those bindings' JNI-side entry points. The other args are for
|
||||
** JniDecl. See the many examples in this file.
|
||||
** S3JniApi's intent is that CFunc be the C API func(s) the
|
||||
** being-declared JNI function is wrapping, making it easier to find
|
||||
** that function's JNI-side entry point. The other args are for JniDecl.
|
||||
** See the many examples in this file.
|
||||
*/
|
||||
#define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
|
||||
|
||||
@@ -333,7 +331,7 @@ struct S3JniNphOp {
|
||||
const char * const zMember /* Name of member property */;
|
||||
const char * const zTypeSig /* JNI type signature of zMember */;
|
||||
/*
|
||||
** klazz is a global ref to the class represented by zName.
|
||||
** klazz is a global ref to the class represented by pRef.
|
||||
**
|
||||
** According to:
|
||||
**
|
||||
@@ -997,20 +995,19 @@ static S3JniEnv * S3JniEnv__get(JNIEnv * const env){
|
||||
** JNI bindings such as sqlite3_prepare_v2/v3(), and definitely not
|
||||
** from client code.
|
||||
**
|
||||
** Returns err_code _unless_ err_code is 0 and sqlite3_set_errmsg()
|
||||
** fails with OOM, in which case it may return SQLITE_OOM or fail
|
||||
** fatally.
|
||||
**
|
||||
** This function predates sqlite3_set_errmsg(), which is why it has a
|
||||
** slightly different interface. Before that function was introduced,
|
||||
** this code used the SQLite-internal APIs to do this.
|
||||
** Returns err_code.
|
||||
*/
|
||||
static int s3jni_db_error(JNIEnv * env, sqlite3* const db,
|
||||
int err_code, const char * const zMsg){
|
||||
static int s3jni_db_error(sqlite3* const db, int err_code,
|
||||
const char * const zMsg){
|
||||
if( db!=0 ){
|
||||
int const rc = sqlite3_set_errmsg(db, err_code, zMsg);
|
||||
s3jni_oom_fatal(0==rc);
|
||||
if( rc && !err_code ) err_code=rc;
|
||||
if( 0==zMsg ){
|
||||
sqlite3Error(db, err_code);
|
||||
}else{
|
||||
const int nMsg = sqlite3Strlen30(zMsg);
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
|
||||
sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
||||
}
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
@@ -1234,11 +1231,11 @@ static int s3jni__db_exception(JNIEnv * const env, sqlite3 * const pDb,
|
||||
char * zMsg;
|
||||
S3JniExceptionClear;
|
||||
zMsg = s3jni_exception_error_msg(env, ex);
|
||||
s3jni_db_error(env, pDb, errCode, zMsg ? zMsg : zDfltMsg);
|
||||
s3jni_db_error(pDb, errCode, zMsg ? zMsg : zDfltMsg);
|
||||
sqlite3_free(zMsg);
|
||||
S3JniUnrefLocal(ex);
|
||||
}else if( zDfltMsg ){
|
||||
s3jni_db_error(env, pDb, errCode, zDfltMsg);
|
||||
s3jni_db_error(pDb, errCode, zDfltMsg);
|
||||
}
|
||||
return errCode;
|
||||
}
|
||||
@@ -1955,6 +1952,15 @@ static void S3JniUdf_finalizer(void * s){
|
||||
S3JniUdf_free(s3jni_env(), (S3JniUdf*)s, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper for processing args to UDF handlers with signature
|
||||
** (sqlite3_context*,int,sqlite3_value**).
|
||||
*/
|
||||
typedef struct {
|
||||
jobject jcx /* sqlite3_context */;
|
||||
jobjectArray jargv /* sqlite3_value[] */;
|
||||
} udf_jargs;
|
||||
|
||||
/*
|
||||
** Converts the given (cx, argc, argv) into arguments for the given
|
||||
** UDF, writing the result (Java wrappers for cx and argv) in the
|
||||
@@ -1996,7 +2002,7 @@ error_oom:
|
||||
/*
|
||||
** Requires that jCx and jArgv are sqlite3_context
|
||||
** resp. array-of-sqlite3_value values initialized by udf_args(). The
|
||||
** (argc,argv) are (0,NULL) for UDF types with no arguments. This
|
||||
** latter will be 0-and-NULL for UDF types with no arguments. This
|
||||
** function zeroes out the nativePointer member of jCx and each entry
|
||||
** in jArgv. This is a safety-net precaution to avoid undefined
|
||||
** behavior if a Java-side UDF holds a reference to its context or one
|
||||
@@ -2089,19 +2095,19 @@ static int udf_xFSI(sqlite3_context* const pCx, int argc,
|
||||
sqlite3_value** const argv, S3JniUdf * const s,
|
||||
jmethodID xMethodID, const char * const zFuncType){
|
||||
S3JniDeclLocal_env;
|
||||
jobject jcx = 0 /* sqlite3_context */;
|
||||
jobjectArray jargv = 0 /* sqlite3_value[] */;
|
||||
int rc = udf_args(env, pCx, argc, argv, &jcx, &jargv);
|
||||
udf_jargs args = {0,0};
|
||||
int rc = udf_args(env, pCx, argc, argv, &args.jcx, &args.jargv);
|
||||
|
||||
if( 0 == rc ){
|
||||
(*env)->CallVoidMethod(env, s->jObj, xMethodID, jcx, jargv);
|
||||
(*env)->CallVoidMethod(env, s->jObj, xMethodID, args.jcx, args.jargv);
|
||||
S3JniIfThrew{
|
||||
rc = udf_report_exception(env, 'F'==zFuncType[1]/*xFunc*/, pCx,
|
||||
s->zFuncName, zFuncType);
|
||||
}
|
||||
udf_unargs(env, jcx, argc, jargv);
|
||||
udf_unargs(env, args.jcx, argc, args.jargv);
|
||||
}
|
||||
S3JniUnrefLocal(jcx);
|
||||
S3JniUnrefLocal(jargv);
|
||||
S3JniUnrefLocal(args.jcx);
|
||||
S3JniUnrefLocal(args.jargv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3290,7 +3296,7 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
|
||||
S3JniDb_mutex_enter;
|
||||
ps = S3JniDb_from_jlong(jpDb);
|
||||
if( !ps ){
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_MISUSE, 0);
|
||||
s3jni_db_error(ps->pDb, SQLITE_MISUSE, 0);
|
||||
S3JniDb_mutex_leave;
|
||||
return 0;
|
||||
}
|
||||
@@ -3310,14 +3316,13 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
|
||||
else sqlite3_rollback_hook(ps->pDb, 0, 0);
|
||||
}else{
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jHook);
|
||||
jmethodID const xCallback =
|
||||
(*env)->GetMethodID(env, klazz, "call",
|
||||
isCommit ? "()I" : "()V");
|
||||
jmethodID const xCallback = (*env)->GetMethodID(env, klazz, "call",
|
||||
isCommit ? "()I" : "()V");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionReport;
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching call() method in"
|
||||
"hook object.");
|
||||
}else{
|
||||
@@ -3597,7 +3602,7 @@ S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
|
||||
(*env)->GetMethodID(env, klazz, "call", "([B[B)I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew{
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Could not get call() method from "
|
||||
"CollationCallback object.");
|
||||
}else{
|
||||
@@ -3636,15 +3641,15 @@ S3JniApi(sqlite3_create_function() sqlite3_create_function_v2()
|
||||
|
||||
if( !pDb || !jFuncName ){
|
||||
return SQLITE_MISUSE;
|
||||
}else if( !encodingTypeIsValid(eTextRep & 0x0f) ){
|
||||
return s3jni_db_error(env, pDb, SQLITE_FORMAT,
|
||||
}else if( !encodingTypeIsValid(eTextRep) ){
|
||||
return s3jni_db_error(pDb, SQLITE_FORMAT,
|
||||
"Invalid function encoding option.");
|
||||
}
|
||||
s = S3JniUdf_alloc(env, jFunctor);
|
||||
if( !s ) return SQLITE_NOMEM;
|
||||
|
||||
if( UDF_UNKNOWN_TYPE==s->type ){
|
||||
rc = s3jni_db_error(env, pDb, SQLITE_MISUSE,
|
||||
rc = s3jni_db_error(pDb, SQLITE_MISUSE,
|
||||
"Cannot unambiguously determine function type.");
|
||||
S3JniUdf_free(env, s, 1);
|
||||
goto error_cleanup;
|
||||
@@ -3851,19 +3856,6 @@ S3JniApi(sqlite3_errmsg(),jstring,1errmsg)(
|
||||
effect should be identical to using errmsg16(), however. */;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_set_errmsg(),jint,1set_1errmsg)(
|
||||
JniArgsEnvClass, jobject jpDb, jint errCode, jstring msg
|
||||
){
|
||||
sqlite3 * const pDb = PtrGet_sqlite3(jpDb);
|
||||
const char *zUtf8;
|
||||
jint rc;
|
||||
if( !pDb ) return SQLITE_MISUSE;
|
||||
zUtf8 = msg ? s3jni_jstring_to_mutf8(msg) : NULL;
|
||||
rc = sqlite3_set_errmsg(pDb, (int)errCode, zUtf8);
|
||||
s3jni_mutf8_release(msg, zUtf8);
|
||||
return rc;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_errstr(),jstring,1errstr)(
|
||||
JniArgsEnvClass, jint rcCode
|
||||
){
|
||||
@@ -4003,7 +3995,7 @@ S3JniApi(sqlite3_jni_db_error(), jint, 1jni_1db_1error)(
|
||||
zStr = jStr
|
||||
? s3jni_jstring_to_utf8( jStr, 0)
|
||||
: NULL;
|
||||
rc = s3jni_db_error(env, ps->pDb, (int)jRc, zStr );
|
||||
rc = s3jni_db_error( ps->pDb, (int)jRc, zStr );
|
||||
sqlite3_free(zStr);
|
||||
}
|
||||
return rc;
|
||||
@@ -4312,7 +4304,7 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
|
||||
jTable = jDbName ? s3jni_utf8_to_jstring( zTable, -1) : 0;
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_NOMEM, 0);
|
||||
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
|
||||
}else{
|
||||
assert( hook.jObj );
|
||||
assert( hook.midCallback );
|
||||
@@ -4414,7 +4406,7 @@ static jobject s3jni_updatepre_hook(JNIEnv * env, int isPre, jlong jpDb, jobject
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching callback on "
|
||||
"(pre)update hook object.");
|
||||
}else{
|
||||
@@ -4523,7 +4515,7 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching xCallback() on "
|
||||
"ProgressHandler object.");
|
||||
}else{
|
||||
@@ -4897,9 +4889,8 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
|
||||
")I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
"Error setting up Java parts of "
|
||||
"authorizer hook.");
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Error setting up Java parts of authorizer hook.");
|
||||
}else{
|
||||
rc = sqlite3_set_authorizer(ps->pDb, s3jni_xAuth, ps);
|
||||
}
|
||||
@@ -5183,7 +5174,7 @@ S3JniApi(sqlite3_trace_v2(),jint,1trace_1v2)(
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching call() on "
|
||||
"TracerCallback object.");
|
||||
}else{
|
||||
|
||||
@@ -245,10 +245,8 @@ extern "C" {
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_CACHE_USED_SHARED 11L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_CACHE_SPILL
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_CACHE_SPILL 12L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_TEMPBUF_SPILL
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_TEMPBUF_SPILL 13L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_MAX
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_MAX 13L
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_DBSTATUS_MAX 12L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_UTF8
|
||||
#define org_sqlite_jni_capi_CApi_SQLITE_UTF8 1L
|
||||
#undef org_sqlite_jni_capi_CApi_SQLITE_UTF16LE
|
||||
@@ -1344,7 +1342,7 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1data_1count
|
||||
* Method: sqlite3_db_config
|
||||
* Signature: (Lorg/sqlite/jni/capi/sqlite3;IILorg/sqlite/jni/capi/OutputPointer/Int32;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1db_1config__Lorg_sqlite_jni_capi_sqlite3_2IILorg_sqlite_jni_capi_OutputPointer_Int32_2
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1db_1config__Lorg_sqlite_jni_capi_sqlite3_2IILorg_sqlite_jni_capi_OutputPointer_00024Int32_2
|
||||
(JNIEnv *, jclass, jobject, jint, jint, jobject);
|
||||
|
||||
/*
|
||||
@@ -1419,14 +1417,6 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1errcode
|
||||
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1errmsg
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_capi_CApi
|
||||
* Method: sqlite3_set_errmsg
|
||||
* Signature: (Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1set_1errmsg
|
||||
(JNIEnv *, jclass, jobject, jint, jstring);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_capi_CApi
|
||||
* Method: sqlite3_error_offset
|
||||
|
||||
@@ -115,9 +115,8 @@ public final class CApi {
|
||||
JNIEnv is not cached, else returns true, but this information is
|
||||
primarily for testing of the JNI bindings and is not information
|
||||
which client-level code can use to make any informed
|
||||
decisions. The semantics of its return type and value are not
|
||||
considered stable and may change at any time. i.e. act as if it
|
||||
returns null.
|
||||
decisions. Its return type and semantics are not considered
|
||||
stable and may change at any time.
|
||||
*/
|
||||
public static native boolean sqlite3_java_uncache_thread();
|
||||
|
||||
@@ -1198,15 +1197,10 @@ public final class CApi {
|
||||
|
||||
public static native String sqlite3_errmsg(@NotNull sqlite3 db);
|
||||
|
||||
/** Added in 3.51.0. */
|
||||
public static native int sqlite3_set_errmsg(@NotNull sqlite3 db,
|
||||
int resultCode,
|
||||
String msg);
|
||||
|
||||
private static native int sqlite3_error_offset(@NotNull long ptrToDb);
|
||||
|
||||
/**
|
||||
Caveat: the returned byte offset values assume UTF-8-encoded
|
||||
Note that the returned byte offset values assume UTF-8-encoded
|
||||
inputs, so won't always match character offsets in Java Strings.
|
||||
*/
|
||||
public static int sqlite3_error_offset(@NotNull sqlite3 db){
|
||||
@@ -2586,8 +2580,7 @@ public final class CApi {
|
||||
public static final int SQLITE_DBSTATUS_DEFERRED_FKS = 10;
|
||||
public static final int SQLITE_DBSTATUS_CACHE_USED_SHARED = 11;
|
||||
public static final int SQLITE_DBSTATUS_CACHE_SPILL = 12;
|
||||
public static final int SQLITE_DBSTATUS_TEMPBUF_SPILL = 13;
|
||||
public static final int SQLITE_DBSTATUS_MAX = 13;
|
||||
public static final int SQLITE_DBSTATUS_MAX = 12;
|
||||
|
||||
// encodings
|
||||
public static final int SQLITE_UTF8 = 1;
|
||||
|
||||
@@ -815,9 +815,7 @@ public class Tester1 implements Runnable {
|
||||
};
|
||||
|
||||
// Register and use the function...
|
||||
int rc = sqlite3_create_function(db, "myfunc", -1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS,
|
||||
func);
|
||||
int rc = sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func);
|
||||
affirm(0 == rc);
|
||||
affirm(0 == xFuncAccum.value);
|
||||
final sqlite3_stmt stmt = prepare(db, "SELECT myfunc(1,2,3)");
|
||||
@@ -1876,20 +1874,6 @@ public class Tester1 implements Runnable {
|
||||
sqlite3_close_v2(db);
|
||||
}
|
||||
|
||||
private void testSetErrmsg(){
|
||||
final sqlite3 db = createNewDb();
|
||||
|
||||
int rc = sqlite3_set_errmsg(db, SQLITE_RANGE, "nope");
|
||||
affirm( 0==rc );
|
||||
affirm( SQLITE_MISUSE == sqlite3_set_errmsg(null, 0, null) );
|
||||
affirm( "nope".equals(sqlite3_errmsg(db)) );
|
||||
affirm( SQLITE_RANGE == sqlite3_errcode(db) );
|
||||
rc = sqlite3_set_errmsg(db, 0, null);
|
||||
affirm( "not an error".equals(sqlite3_errmsg(db)) );
|
||||
affirm( 0 == sqlite3_errcode(db) );
|
||||
sqlite3_close_v2(db);
|
||||
}
|
||||
|
||||
/* Copy/paste/rename this to add new tests. */
|
||||
private void _testTemplate(){
|
||||
final sqlite3 db = createNewDb();
|
||||
|
||||
@@ -171,7 +171,6 @@ public final class Sqlite implements AutoCloseable {
|
||||
public static final int DBSTATUS_DEFERRED_FKS = CApi.SQLITE_DBSTATUS_DEFERRED_FKS;
|
||||
public static final int DBSTATUS_CACHE_USED_SHARED = CApi.SQLITE_DBSTATUS_CACHE_USED_SHARED;
|
||||
public static final int DBSTATUS_CACHE_SPILL = CApi.SQLITE_DBSTATUS_CACHE_SPILL;
|
||||
public static final int DBSTATUS_TEMPBUF_SPILL = CApi.SQLITE_DBSTATUS_TEMPBUF_SPILL;
|
||||
|
||||
// Limits
|
||||
public static final int LIMIT_LENGTH = CApi.SQLITE_LIMIT_LENGTH;
|
||||
|
||||
@@ -9,6 +9,11 @@ Each source file contains a description in its header comment. See the
|
||||
header comments for details about each extension. Additional notes are
|
||||
as follows:
|
||||
|
||||
* **carray.c** — This module implements the
|
||||
[carray](https://sqlite.org/carray.html) table-valued function.
|
||||
It is a good example of how to go about implementing a custom
|
||||
[table-valued function](https://sqlite.org/vtab.html#tabfunc2).
|
||||
|
||||
* **csv.c** — A [virtual table](https://sqlite.org/vtab.html)
|
||||
for reading
|
||||
[Comma-Separated-Value (CSV) files](https://en.wikipedia.org/wiki/Comma-separated_values).
|
||||
@@ -23,6 +28,11 @@ as follows:
|
||||
[SQLite amalgamation](https://sqlite.org/amalgamation.html). See
|
||||
<https://sqlite.org/json1.html> for additional information.
|
||||
|
||||
* **memvfs.c** — This file implements a custom
|
||||
[VFS](https://sqlite.org/vfs.html) that stores an entire database
|
||||
file in a single block of RAM. It serves as a good example of how
|
||||
to implement a simple custom VFS.
|
||||
|
||||
* **rot13.c** — This file implements the very simple rot13()
|
||||
substitution function. This file makes a good template for implementing
|
||||
new custom SQL functions for SQLite.
|
||||
|
||||
+7
-7
@@ -514,7 +514,7 @@ struct amatch_cursor {
|
||||
sqlite3_int64 iRowid; /* The rowid of the current word */
|
||||
amatch_langid iLang; /* Use this language ID */
|
||||
amatch_cost rLimit; /* Maximum cost of any term */
|
||||
sqlite3_int64 nBuf; /* Space allocated for zBuf */
|
||||
int nBuf; /* Space allocated for zBuf */
|
||||
int oomErr; /* True following an OOM error */
|
||||
int nWord; /* Number of amatch_word objects */
|
||||
char *zBuf; /* Temp-use buffer space */
|
||||
@@ -847,7 +847,7 @@ static int amatchConnect(
|
||||
|
||||
(void)pAux;
|
||||
*ppVtab = 0;
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
rc = SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -928,7 +928,7 @@ amatchConnectError:
|
||||
static int amatchOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
amatch_vtab *p = (amatch_vtab*)pVTab;
|
||||
amatch_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->pVtab = p;
|
||||
@@ -1039,7 +1039,7 @@ static void amatchAddWord(
|
||||
nTail = (int)strlen(zWordTail);
|
||||
if( nBase+nTail+3>pCur->nBuf ){
|
||||
pCur->nBuf = nBase+nTail+100;
|
||||
pCur->zBuf = sqlite3_realloc64(pCur->zBuf, pCur->nBuf);
|
||||
pCur->zBuf = sqlite3_realloc(pCur->zBuf, pCur->nBuf);
|
||||
if( pCur->zBuf==0 ){
|
||||
pCur->nBuf = 0;
|
||||
return;
|
||||
@@ -1105,13 +1105,13 @@ static int amatchNext(sqlite3_vtab_cursor *cur){
|
||||
amatch_avl *pNode;
|
||||
int isMatch = 0;
|
||||
amatch_vtab *p = pCur->pVtab;
|
||||
sqlite3_int64 nWord;
|
||||
int nWord;
|
||||
int rc;
|
||||
int i;
|
||||
const char *zW;
|
||||
amatch_rule *pRule;
|
||||
char *zBuf = 0;
|
||||
sqlite3_int64 nBuf = 0;
|
||||
char nBuf = 0;
|
||||
char zNext[8];
|
||||
char zNextIn[8];
|
||||
int nNextIn;
|
||||
@@ -1158,7 +1158,7 @@ static int amatchNext(sqlite3_vtab_cursor *cur){
|
||||
nWord = (int)strlen(pWord->zWord+2);
|
||||
if( nWord+20>nBuf ){
|
||||
nBuf = (char)(nWord+100);
|
||||
zBuf = sqlite3_realloc64(zBuf, nBuf);
|
||||
zBuf = sqlite3_realloc(zBuf, nBuf);
|
||||
if( zBuf==0 ) return SQLITE_NOMEM;
|
||||
}
|
||||
amatchStrcpy(zBuf, pWord->zWord+2);
|
||||
|
||||
@@ -1,827 +0,0 @@
|
||||
/*
|
||||
** 2026-04-13
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** Partial reimplement of the sqlite3_analyzer utility program as
|
||||
** loadable SQL function.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
** State information for the analysis
|
||||
*/
|
||||
typedef struct Analysis Analysis;
|
||||
struct Analysis {
|
||||
sqlite3 *db; /* Database connection */
|
||||
sqlite3_context *context; /* SQL function context */
|
||||
sqlite3_str *pOut; /* Write output here */
|
||||
char *zSU; /* Name of the temp.space_used table */
|
||||
const char *zSchema; /* Schema to be analyzed */
|
||||
};
|
||||
|
||||
/*
|
||||
** Free all resources that the Analysis object references and
|
||||
** reset the Analysis object.
|
||||
**
|
||||
** Call this routine multiple times on the same Analysis object
|
||||
** is a harmless no-op, as long as the memory for the object itself
|
||||
** has not been freed.
|
||||
*/
|
||||
static void analysisReset(Analysis *p){
|
||||
if( p->zSU ){
|
||||
char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU);
|
||||
if( zSql ){
|
||||
sqlite3_exec(p->db, zSql, 0, 0, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
}
|
||||
sqlite3_str_free(p->pOut);
|
||||
sqlite3_free(p->zSU);
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
|
||||
/*
|
||||
** Report an error using formatted text. If zFormat==NULL then report
|
||||
** an OOM error.
|
||||
*/
|
||||
static void analysisError(Analysis *p, const char *zFormat, ...){
|
||||
char *zErr;
|
||||
if( zFormat ){
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zErr = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
}else{
|
||||
zErr = 0;
|
||||
}
|
||||
if( zErr==0 ){
|
||||
sqlite3_result_error_nomem(p->context);
|
||||
}else{
|
||||
sqlite3_result_error(p->context, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
analysisReset(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare and return an SQL statement.
|
||||
*/
|
||||
static sqlite3_stmt *analysisVPrep(Analysis *p, const char *zFmt, va_list ap){
|
||||
char *zSql;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
zSql = sqlite3_vmprintf(zFmt, ap);
|
||||
if( zSql==0 ){ analysisError(p,0); return 0; }
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
analysisError(p, "SQL parse error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), zSql);
|
||||
sqlite3_finalize(pStmt);
|
||||
analysisReset(p);
|
||||
pStmt = 0;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return pStmt;
|
||||
}
|
||||
static sqlite3_stmt *analysisPrepare(Analysis *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** If rc is something other than SQLITE_DONE or SQLITE_OK, then report
|
||||
** an error and return true.
|
||||
**
|
||||
** If rc is SQLITE_DONE or SQLITE_OK, then return false.
|
||||
**
|
||||
** The prepared statement is closed in either case.
|
||||
*/
|
||||
static int analysisStmtFinish(Analysis *p, int rc, sqlite3_stmt *pStmt){
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run SQL. Return the number of errors.
|
||||
*/
|
||||
static int analysisSql(Analysis *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
if( pStmt==0 ) return 1;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){}
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run an SQL query that returns an integer. Write that integer
|
||||
** into *piRes. Return the number of errors.
|
||||
*/
|
||||
static int analysisSqlInt(
|
||||
Analysis *p,
|
||||
sqlite3_int64 *piRes,
|
||||
const char *zFormat, ...
|
||||
){
|
||||
va_list ap;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
if( pStmt==0 ) return 1;
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
*piRes = sqlite3_column_int64(pStmt, 0);
|
||||
rc = SQLITE_OK;
|
||||
}else if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
if( p->db ){
|
||||
/* p->db is NULL if there was some prior error */
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
}
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add to the output a title line that contains the text determined
|
||||
** by the format string. If the output is initially empty, begin
|
||||
** the title line with "/" so that it forms the beginning of a C-style
|
||||
** comment. Otherwise begin with a new-line. Always finish with a
|
||||
** newline.
|
||||
*/
|
||||
static void analysisTitle(Analysis *p, const char *zFormat, ...){
|
||||
char *zFirst;
|
||||
char *zTitle;
|
||||
size_t nTitle;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zTitle = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zTitle==0 ){
|
||||
analysisError(p, 0);
|
||||
return;
|
||||
}
|
||||
zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*";
|
||||
nTitle = strlen(zTitle);
|
||||
if( nTitle>=75 ){
|
||||
sqlite3_str_appendf(p->pOut, "%s** %z\n\n", zFirst, zTitle);
|
||||
}else{
|
||||
int nExtra = 74 - (int)nTitle;
|
||||
sqlite3_str_appendf(p->pOut, "%s** %z %.*c\n\n", zFirst, zTitle,
|
||||
nExtra, '*');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an output line that begins with the zDesc text extended out to
|
||||
** 50 columns with "." characters, and followed by whatever text is
|
||||
** described by zFormat.
|
||||
*/
|
||||
static void analysisLine(
|
||||
Analysis *p, /* Analysis context */
|
||||
const char *zDesc, /* Description */
|
||||
const char *zFormat, /* Argument to the description */
|
||||
...
|
||||
){
|
||||
char *zTxt;
|
||||
size_t nDesc;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zTxt = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zTxt==0 ){
|
||||
analysisError(p, 0);
|
||||
return;
|
||||
}
|
||||
nDesc = strlen(zDesc);
|
||||
if( nDesc>=50 ){
|
||||
sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt);
|
||||
}else{
|
||||
int nExtra = 50 - (int)nDesc;
|
||||
sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Write a percentage into the output. The number written should show
|
||||
** two or three significant digits, with the decimal point being the fourth
|
||||
** character.
|
||||
*/
|
||||
static void analysisPercent(Analysis *p, double r){
|
||||
char zNum[100];
|
||||
char *zDP;
|
||||
int nLeadingDigit;
|
||||
int sz;
|
||||
sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r);
|
||||
sz = (int)strlen(zNum);
|
||||
zDP = strchr(zNum, '.');
|
||||
if( zDP==0 ){
|
||||
memcpy(zNum+sz,".0",3);
|
||||
nLeadingDigit = sz;
|
||||
sz += 2;
|
||||
}else{
|
||||
nLeadingDigit = (int)(zDP - zNum);
|
||||
}
|
||||
if( nLeadingDigit<3 ){
|
||||
sqlite3_str_appendchar(p->pOut, 3-nLeadingDigit, ' ');
|
||||
}
|
||||
sqlite3_str_append(p->pOut, zNum, sz);
|
||||
sqlite3_str_append(p->pOut, "%\n", 2);
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a subreport on a subset of tables and/or indexes.
|
||||
**
|
||||
** The title if the subreport is given by zTitle. zWhere is
|
||||
** a boolean expression that can go in the WHERE clause to select
|
||||
** the relevant rows of the s.zSU table.
|
||||
*/
|
||||
static int analysisSubreport(
|
||||
Analysis *p, /* Analysis context */
|
||||
char *zTitle, /* Title for this subreport */
|
||||
char *zWhere, /* WHERE clause for this subreport */
|
||||
sqlite3_int64 pgsz, /* Database page size */
|
||||
sqlite3_int64 nPage /* Number of pages in entire database */
|
||||
){
|
||||
sqlite3_stmt *pStmt; /* Statement to query p->zSU */
|
||||
sqlite3_int64 nentry; /* Number of btree entires */
|
||||
sqlite3_int64 payload; /* Payload in bytes */
|
||||
sqlite3_int64 ovfl_payload; /* overflow payload in bytes */
|
||||
sqlite3_int64 mx_payload; /* largest individual payload */
|
||||
sqlite3_int64 ovfl_cnt; /* Number entries using overflow */
|
||||
sqlite3_int64 leaf_pages; /* Leaf pages */
|
||||
sqlite3_int64 int_pages; /* internal pages */
|
||||
sqlite3_int64 ovfl_pages; /* overflow pages */
|
||||
sqlite3_int64 leaf_unused; /* unused bytes on leaf pages */
|
||||
sqlite3_int64 int_unused; /* unused bytes on internal pages */
|
||||
sqlite3_int64 ovfl_unused; /* unused bytes on overflow pages */
|
||||
sqlite3_int64 int_cell; /* B-tree entries on internal pages */
|
||||
sqlite3_int64 depth; /* btree depth */
|
||||
sqlite3_int64 cnt; /* Number of s.zSU entries that match */
|
||||
sqlite3_int64 storage; /* Total bytes */
|
||||
sqlite3_int64 total_pages; /* Total page count */
|
||||
sqlite3_int64 total_unused; /* Total unused bytes */
|
||||
sqlite3_int64 total_meta; /* Total metadata */
|
||||
int rc;
|
||||
|
||||
if( zTitle==0 || zWhere==0 ){
|
||||
analysisError(p, 0);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pStmt = analysisPrepare(p,
|
||||
"SELECT\n"
|
||||
" sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */
|
||||
" sum(payload),\n" /* 1 */
|
||||
" sum(ovfl_payload),\n" /* 2 */
|
||||
" max(mx_payload),\n" /* 3 */
|
||||
" sum(ovfl_cnt),\n" /* 4 */
|
||||
" sum(leaf_pages),\n" /* 5 */
|
||||
" sum(int_pages),\n" /* 6 */
|
||||
" sum(ovfl_pages),\n" /* 7 */
|
||||
" sum(leaf_unused),\n" /* 8 */
|
||||
" sum(int_unused),\n" /* 9 */
|
||||
" sum(ovfl_unused),\n" /* 10 */
|
||||
" max(depth),\n" /* 11 */
|
||||
" count(*),\n" /* 12 */
|
||||
" sum(int_entries)\n" /* 13 */
|
||||
" FROM temp.%s WHERE %s",
|
||||
p->zSU, zWhere);
|
||||
if( pStmt==0 ) return 1;
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
analysisTitle(p, zTitle);
|
||||
|
||||
nentry = sqlite3_column_int64(pStmt, 0);
|
||||
payload = sqlite3_column_int64(pStmt, 1);
|
||||
ovfl_payload = sqlite3_column_int64(pStmt, 2);
|
||||
mx_payload = sqlite3_column_int64(pStmt, 3);
|
||||
ovfl_cnt = sqlite3_column_int64(pStmt, 4);
|
||||
leaf_pages = sqlite3_column_int64(pStmt, 5);
|
||||
int_pages = sqlite3_column_int64(pStmt, 6);
|
||||
ovfl_pages = sqlite3_column_int64(pStmt, 7);
|
||||
leaf_unused = sqlite3_column_int64(pStmt, 8);
|
||||
int_unused = sqlite3_column_int64(pStmt, 9);
|
||||
ovfl_unused = sqlite3_column_int64(pStmt, 10);
|
||||
depth = sqlite3_column_int64(pStmt, 11);
|
||||
cnt = sqlite3_column_int64(pStmt, 12);
|
||||
int_cell = sqlite3_column_int64(pStmt, 13);
|
||||
rc = SQLITE_DONE;
|
||||
|
||||
total_pages = leaf_pages + int_pages + ovfl_pages;
|
||||
analysisLine(p, "Percentage of total database", "%.3g%%\n",
|
||||
(total_pages*100.0)/(double)nPage);
|
||||
analysisLine(p, "Number of entries", "%lld\n", nentry);
|
||||
storage = total_pages*pgsz;
|
||||
analysisLine(p, "Bytes of storage consumed", "%lld\n", storage);
|
||||
analysisLine(p, "Bytes of payload", "%-11lld ", payload);
|
||||
analysisPercent(p, payload*100.0/(double)storage);
|
||||
if( ovfl_cnt>0 ){
|
||||
analysisLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload);
|
||||
analysisPercent(p, ovfl_payload*100.0/(double)payload);
|
||||
}
|
||||
total_unused = leaf_unused + int_unused + ovfl_unused;
|
||||
total_meta = storage - payload - total_unused;
|
||||
analysisLine(p, "Bytes of metadata","%-11lld ", total_meta);
|
||||
analysisPercent(p, total_meta*100.0/(double)storage);
|
||||
if( cnt==1 ){
|
||||
analysisLine(p, "B-tree depth", "%lld\n", depth);
|
||||
if( int_cell>1 ){
|
||||
analysisLine(p, "Average fanout", "%.1f\n",
|
||||
(double)(int_cell+int_pages)/(double)int_pages);
|
||||
}
|
||||
}
|
||||
if( nentry>0 ){
|
||||
analysisLine(p, "Average payload per entry", "%.1f\n",
|
||||
(double)payload/(double)nentry);
|
||||
analysisLine(p, "Average unused bytes per entry", "%.1f\n",
|
||||
(double)total_unused/(double)nentry);
|
||||
analysisLine(p, "Average metadata per entry", "%.1f\n",
|
||||
(double)total_meta/(double)nentry);
|
||||
}
|
||||
analysisLine(p, "Maximum single-entry payload", "%lld\n", mx_payload);
|
||||
if( nentry>0 ){
|
||||
analysisLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt);
|
||||
analysisPercent(p, ovfl_cnt*100.0/(double)nentry);
|
||||
}
|
||||
if( int_pages>0 ){
|
||||
analysisLine(p, "Index pages used", "%lld\n", int_pages);
|
||||
}
|
||||
analysisLine(p, "Primary pages used", "%lld\n", leaf_pages);
|
||||
if( ovfl_cnt ){
|
||||
analysisLine(p, "Overflow pages used", "%lld\n", ovfl_pages);
|
||||
}
|
||||
analysisLine(p, "Total pages used", "%lld\n", total_pages);
|
||||
if( int_pages>0 ){
|
||||
analysisLine(p, "Unused bytes on index pages", "%lld\n", int_unused);
|
||||
}
|
||||
analysisLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused);
|
||||
if( ovfl_cnt ){
|
||||
analysisLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused);
|
||||
}
|
||||
analysisLine(p, "Unused bytes on all pages", "%-11lld ", total_unused);
|
||||
analysisPercent(p, total_unused*100.0/(double)storage);
|
||||
}
|
||||
return analysisStmtFinish(p, rc, pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL Function: analyze(SCHEMA)
|
||||
**
|
||||
** Analyze the database schema named in the argument. Return text
|
||||
** containing the analysis.
|
||||
*/
|
||||
static void analyzeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int n;
|
||||
sqlite3_int64 i64;
|
||||
sqlite3_int64 pgsz;
|
||||
sqlite3_int64 nPage;
|
||||
sqlite3_int64 nPageInUse;
|
||||
sqlite3_int64 nFreeList;
|
||||
sqlite3_int64 nIndex;
|
||||
sqlite3_int64 nWORowid;
|
||||
Analysis s;
|
||||
sqlite3_uint64 r[2];
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.db = sqlite3_context_db_handle(context);
|
||||
s.context = context;
|
||||
s.pOut = sqlite3_str_new(0);
|
||||
if( s.pOut==0 ){ analysisError(&s, 0); return; }
|
||||
s.zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( s.zSchema==0 ){
|
||||
s.zSchema = "main";
|
||||
}else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){
|
||||
/* Attempt to analyze "temp" returns NULL */
|
||||
analysisReset(&s);
|
||||
return;
|
||||
}
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s,&i64,"SELECT 1 FROM pragma_database_list"
|
||||
" WHERE name=%Q COLLATE nocase",s.zSchema);
|
||||
if( rc || i64==0 ){
|
||||
/* Return NULL the named schema does not exist */
|
||||
analysisReset(&s);
|
||||
return;
|
||||
}
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
s.zSU = sqlite3_mprintf("analysis%016llx%016llx", r[0], r[1]);
|
||||
if( s.zSU==0 ){ analysisError(&s, 0); return; }
|
||||
|
||||
/* The s.zSU table contains the data used for the analysis.
|
||||
** The table name contains 128-bits of randomness to avoid
|
||||
** collisions with preexisting tables in temp.
|
||||
*/
|
||||
rc = analysisSql(&s,
|
||||
"CREATE TABLE temp.%s(\n"
|
||||
" name text, -- A table or index\n"
|
||||
" tblname text, -- Table that owns name\n"
|
||||
" is_index boolean, -- TRUE if it is an index\n"
|
||||
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n"
|
||||
" nentry int, -- Number of entries in the BTree\n"
|
||||
" leaf_entries int, -- Number of leaf entries\n"
|
||||
" depth int, -- Depth of the b-tree\n"
|
||||
" payload int, -- Total data stored in this table/index\n"
|
||||
" ovfl_payload int, -- Total data stored on overflow pages\n"
|
||||
" ovfl_cnt int, -- Number of entries that use overflow\n"
|
||||
" mx_payload int, -- Maximum payload size\n"
|
||||
" int_pages int, -- Interior pages used\n"
|
||||
" leaf_pages int, -- Leaf pages used\n"
|
||||
" ovfl_pages int, -- Overflow pages used\n"
|
||||
" int_unused int, -- Unused bytes on interior pages\n"
|
||||
" leaf_unused int, -- Unused bytes on primary pages\n"
|
||||
" ovfl_unused int, -- Unused bytes on overflow pages\n"
|
||||
" int_entries int -- Btree cells on internal pages\n"
|
||||
");",
|
||||
s.zSU
|
||||
);
|
||||
if( rc ) return;
|
||||
|
||||
/* Populate the s.zSU table
|
||||
*/
|
||||
rc = analysisSql(&s,
|
||||
"WITH\n"
|
||||
" allidx(idxname) AS (\n"
|
||||
" SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n"
|
||||
" ),\n"
|
||||
" allobj(allname,tblname,isidx,isworowid) AS (\n"
|
||||
" SELECT 'sqlite_schema',\n"
|
||||
" 'sqlite_schema',\n"
|
||||
" 0,\n"
|
||||
" 0\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT name,\n"
|
||||
" tbl_name,\n"
|
||||
" type='index',\n"
|
||||
" EXISTS(SELECT 1\n"
|
||||
" FROM pragma_index_list(sqlite_schema.name,%Q)\n"
|
||||
" WHERE pragma_index_list.origin='pk'\n"
|
||||
" AND pragma_index_list.name NOT IN allidx)\n"
|
||||
" FROM \"%w\".sqlite_schema\n"
|
||||
" )\n"
|
||||
"INSERT INTO temp.%s\n"
|
||||
" SELECT\n"
|
||||
" allname,\n"
|
||||
" tblname,\n"
|
||||
" isidx,\n"
|
||||
" isworowid,\n"
|
||||
" sum(ncell),\n"
|
||||
" sum((pagetype='leaf')*ncell),\n"
|
||||
" max((length(if(path GLOB '*+*','',path))+3)/4),\n"
|
||||
" sum(payload),\n"
|
||||
" sum((pagetype='overflow')*payload),\n"
|
||||
" sum(path GLOB '*+000000'),\n"
|
||||
" max(mx_payload),\n"
|
||||
" sum(pagetype='internal'),\n"
|
||||
" sum(pagetype='leaf'),\n"
|
||||
" sum(pagetype='overflow'),\n"
|
||||
" sum((pagetype='internal')*unused),\n"
|
||||
" sum((pagetype='leaf')*unused),\n"
|
||||
" sum((pagetype='overflow')*unused),\n"
|
||||
" sum(if(pagetype='internal',ncell))\n"
|
||||
" FROM allobj CROSS JOIN dbstat(%Q) \n"
|
||||
" WHERE dbstat.name=allobj.allname\n"
|
||||
" GROUP BY allname;\n",
|
||||
s.zSchema, /* %w.sqlite_schema -- in allidx */
|
||||
s.zSchema, /* pragma_index_list(...,%Q) */
|
||||
s.zSchema, /* %w.sqlite_schema */
|
||||
s.zSU, /* INTO temp.%s */
|
||||
s.zSchema /* JOIN dbstat(%Q) */
|
||||
);
|
||||
if( rc ) return;
|
||||
|
||||
/* Begin generating the report */
|
||||
analysisTitle(&s, "Database storage utilization report");
|
||||
pgsz = 0;
|
||||
rc = analysisSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Page size in bytes","%lld\n",pgsz);
|
||||
|
||||
nPage = 0;
|
||||
rc = analysisSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages in the database", "%lld\n", nPage);
|
||||
if( nPage<=0 ) nPage = 1;
|
||||
|
||||
nPageInUse = 0;
|
||||
rc = analysisSqlInt(&s, &nPageInUse,
|
||||
"SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages that store data", "%-11lld ", nPageInUse);
|
||||
analysisPercent(&s, (nPageInUse*100.0)/(double)nPage);
|
||||
|
||||
nFreeList = 0;
|
||||
rc = analysisSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList);
|
||||
analysisPercent(&s, (nFreeList*100.0)/(double)nPage);
|
||||
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64, "PRAGMA \"%w\".auto_vacuum", s.zSchema);
|
||||
if( rc ) return;
|
||||
if( i64==0 || nPage<=1 ){
|
||||
i64 = 0;
|
||||
}else{
|
||||
double rPtrsPerPage = pgsz/5;
|
||||
double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0);
|
||||
i64 = (sqlite3_int64)ceil(rAvPage);
|
||||
}
|
||||
analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", i64);
|
||||
analysisPercent(&s, (i64*100.0)/(double)nPage);
|
||||
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of tables", "%lld\n", i64);
|
||||
nWORowid = 0;
|
||||
rc = analysisSqlInt(&s, &nWORowid,
|
||||
"SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
if( nWORowid>0 ){
|
||||
analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid);
|
||||
analysisLine(&s, "Number of rowid tables", "%lld\n", i64 - nWORowid);
|
||||
}
|
||||
nIndex = 0;
|
||||
rc = analysisSqlInt(&s, &nIndex,
|
||||
"SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of indexes", "%lld\n", nIndex);
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT count(*) FROM \"%w\".sqlite_schema"
|
||||
" WHERE name GLOB 'sqlite_autoindex_*' AND type='index'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - i64);
|
||||
analysisLine(&s, "Number of implied indexes", "%lld\n", i64);
|
||||
analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage);
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT sum(payload) FROM temp.%s"
|
||||
" WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'",
|
||||
s.zSU);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Bytes of payload", "%-11lld ", i64);
|
||||
analysisPercent(&s, i64*100.0/(double)(pgsz*nPage));
|
||||
|
||||
analysisTitle(&s, "Page counts for all tables with their indexes");
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(tblname),\n"
|
||||
" sum(int_pages+leaf_pages+ovfl_pages)\n"
|
||||
" FROM temp.%s\n"
|
||||
" GROUP BY 1\n"
|
||||
" ORDER BY 2 DESC, 1;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
sqlite3_int64 n = sqlite3_column_int64(pStmt,1);
|
||||
analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", n);
|
||||
analysisPercent(&s, (n*100.0)/(double)nPage);
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
analysisTitle(&s, "Page counts for all tables and indexes separately");
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(name),\n"
|
||||
" sum(int_pages+leaf_pages+ovfl_pages)\n"
|
||||
" FROM temp.%s\n"
|
||||
" GROUP BY 1\n"
|
||||
" ORDER BY 2 DESC, 1;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
sqlite3_int64 n = sqlite3_column_int64(pStmt,1);
|
||||
analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", n);
|
||||
analysisPercent(&s, (n*100.0)/(double)nPage);
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
rc = analysisSubreport(&s, "All tables and indexes", "1", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
rc = analysisSubreport(&s, "All tables", "NOT is_index", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
if( nWORowid>0 ){
|
||||
rc = analysisSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid",
|
||||
pgsz, nPage);
|
||||
if( rc ) return;
|
||||
rc = analysisSubreport(&s, "All rowid tables",
|
||||
"NOT is_without_rowid AND NOT is_index",
|
||||
pgsz, nPage);
|
||||
if( rc ) return;
|
||||
}
|
||||
rc = analysisSubreport(&s, "All indexes", "is_index", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s"
|
||||
" GROUP BY 1 ORDER BY 1",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
const char *zUpper = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
|
||||
int nSubIndex = sqlite3_column_int(pStmt, 2);
|
||||
if( nSubIndex==0 ){
|
||||
char *zTitle = sqlite3_mprintf("Table %s", zUpper);
|
||||
char *zWhere = sqlite3_mprintf("name=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}else{
|
||||
sqlite3_stmt *pS2;
|
||||
char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper);
|
||||
char *zWhere = sqlite3_mprintf("tblname=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper);
|
||||
zWhere = sqlite3_mprintf("name=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
if( nSubIndex>1 ){
|
||||
zTitle = sqlite3_mprintf("All indexes of table %s", zUpper);
|
||||
zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}
|
||||
pS2 = analysisPrepare(&s,
|
||||
"SELECT name, upper(name) FROM temp.%s"
|
||||
" WHERE is_index AND tblname=%Q",
|
||||
s.zSU, zName);
|
||||
if( pS2==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
}
|
||||
while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){
|
||||
const char *zU = (const char*)sqlite3_column_text(pS2, 1);
|
||||
const char *zN = (const char*)sqlite3_column_text(pS2, 0);
|
||||
zTitle = sqlite3_mprintf("Index %s", zU);
|
||||
zWhere = sqlite3_mprintf("name=%Q", zN);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}
|
||||
rc = analysisStmtFinish(&s, rc, pS2);
|
||||
if( rc ) break;
|
||||
}
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
/* Append SQL statements that will recreate the raw data used for
|
||||
** the analysis.
|
||||
*/
|
||||
analysisTitle(&s, "Raw data used to generate this report");
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
"The following SQL will create a table named \"space_used\" which\n"
|
||||
"contains most of the information used to generate the report above.\n"
|
||||
"*/\n"
|
||||
);
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
"BEGIN;\n"
|
||||
"CREATE TABLE space_used(\n"
|
||||
" name text, -- A table or index\n" /* 0 */
|
||||
" tblname text, -- Table that owns name\n" /* 1 */
|
||||
" is_index boolean, -- TRUE if it is an index\n" /* 2 */
|
||||
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" /* 3 */
|
||||
" nentry int, -- Number of entries in the BTree\n" /* 4 */
|
||||
" leaf_entries int, -- Number of leaf entries\n" /* 5 */
|
||||
" depth int, -- Depth of the b-tree\n" /* 6 */
|
||||
" payload int, -- Total data in this table/index\n" /* 7 */
|
||||
" ovfl_payload int, -- Total data on overflow pages\n" /* 8 */
|
||||
" ovfl_cnt int, -- Entries that use overflow\n" /* 9 */
|
||||
" mx_payload int, -- Maximum payload size\n" /* 10 */
|
||||
" int_pages int, -- Interior pages used\n" /* 11 */
|
||||
" leaf_pages int, -- Leaf pages used\n" /* 12 */
|
||||
" ovfl_pages int, -- Overflow pages used\n" /* 13 */
|
||||
" int_unused int, -- Unused bytes on interior pages\n" /* 14 */
|
||||
" leaf_unused int, -- Unused bytes on primary pages\n" /* 15 */
|
||||
" ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */
|
||||
" int_entries int -- B-tree entries on internal pages\n"/* 17 */
|
||||
");\n"
|
||||
"INSERT INTO space_used VALUES\n"
|
||||
);
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT quote(name), quote(tblname),\n" /* 0..1 */
|
||||
" is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */
|
||||
" depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */
|
||||
" int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */
|
||||
" leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */
|
||||
" FROM temp.%s;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
n = 0;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
if( n++ ) sqlite3_str_appendf(s.pOut,",\n");
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
" (%s,%s,%lld,%lld,%lld,%lld,%lld,%lld,%lld,"
|
||||
"%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld)",
|
||||
sqlite3_column_text(pStmt, 0),
|
||||
sqlite3_column_text(pStmt, 1),
|
||||
sqlite3_column_int64(pStmt, 2),
|
||||
sqlite3_column_int64(pStmt, 3),
|
||||
sqlite3_column_int64(pStmt, 4),
|
||||
sqlite3_column_int64(pStmt, 5),
|
||||
sqlite3_column_int64(pStmt, 6),
|
||||
sqlite3_column_int64(pStmt, 7),
|
||||
sqlite3_column_int64(pStmt, 8),
|
||||
sqlite3_column_int64(pStmt, 9),
|
||||
sqlite3_column_int64(pStmt, 10),
|
||||
sqlite3_column_int64(pStmt, 11),
|
||||
sqlite3_column_int64(pStmt, 12),
|
||||
sqlite3_column_int64(pStmt, 13),
|
||||
sqlite3_column_int64(pStmt, 14),
|
||||
sqlite3_column_int64(pStmt, 15),
|
||||
sqlite3_column_int64(pStmt, 16),
|
||||
sqlite3_column_int64(pStmt, 17));
|
||||
}
|
||||
if( rc!=SQLITE_DONE ){
|
||||
analysisError(&s, "SQL run-time error: %s\nSQL: %s",
|
||||
sqlite3_errmsg(s.db), sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
return;
|
||||
}
|
||||
sqlite3_str_appendf(s.pOut,";\nCOMMIT;");
|
||||
sqlite3_finalize(pStmt);
|
||||
|
||||
if( sqlite3_str_length(s.pOut) ){
|
||||
sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1,
|
||||
sqlite3_free);
|
||||
s.pOut = 0;
|
||||
}
|
||||
analysisReset(&s);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_analyze_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, "analyze", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS,
|
||||
0, analyzeFunc, 0, 0);
|
||||
return rc;
|
||||
}
|
||||
+5
-7
@@ -207,9 +207,7 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
|
||||
|
||||
/* This function does the work for the SQLite base64(x) UDF. */
|
||||
static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
sqlite3_int64 nb;
|
||||
sqlite3_int64 nv = sqlite3_value_bytes(av[0]);
|
||||
sqlite3_int64 nc;
|
||||
int nb, nc, nv = sqlite3_value_bytes(av[0]);
|
||||
int nvMax = sqlite3_limit(sqlite3_context_db_handle(context),
|
||||
SQLITE_LIMIT_LENGTH, -1);
|
||||
char *cBuf;
|
||||
@@ -218,7 +216,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
switch( sqlite3_value_type(av[0]) ){
|
||||
case SQLITE_BLOB:
|
||||
nb = nv;
|
||||
nc = 4*((nv+2)/3); /* quads needed */
|
||||
nc = 4*(nv+2/3); /* quads needed */
|
||||
nc += (nc+(B64_DARK_MAX-1))/B64_DARK_MAX + 1; /* LFs and a 0-terminator */
|
||||
if( nvMax < nc ){
|
||||
sqlite3_result_error(context, "blob expanded to base64 too big", -1);
|
||||
@@ -232,7 +230,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
sqlite3_result_text(context,"",-1,SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
cBuf = sqlite3_malloc64(nc);
|
||||
cBuf = sqlite3_malloc(nc);
|
||||
if( !cBuf ) goto memFail;
|
||||
nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf);
|
||||
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
|
||||
@@ -254,7 +252,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
sqlite3_result_zeroblob(context, 0);
|
||||
break;
|
||||
}
|
||||
bBuf = sqlite3_malloc64(nb);
|
||||
bBuf = sqlite3_malloc(nb);
|
||||
if( !bBuf ) goto memFail;
|
||||
nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf);
|
||||
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
|
||||
@@ -275,7 +273,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_base64_init
|
||||
int sqlite3_base_init
|
||||
#else
|
||||
static int sqlite3_base64_init
|
||||
#endif
|
||||
|
||||
+10
-10
@@ -262,7 +262,7 @@ static int allBase85( char *p, int len ){
|
||||
|
||||
#ifndef BASE85_STANDALONE
|
||||
|
||||
#ifndef OMIT_BASE85_CHECKER
|
||||
# ifndef OMIT_BASE85_CHECKER
|
||||
/* This function does the work for the SQLite is_base85(t) UDF. */
|
||||
static void is_base85(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
assert(na==1);
|
||||
@@ -282,11 +282,11 @@ static void is_base85(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
/* This function does the work for the SQLite base85(x) UDF. */
|
||||
static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
sqlite3_int64 nb, nc, nv = sqlite3_value_bytes(av[0]);
|
||||
int nb, nc, nv = sqlite3_value_bytes(av[0]);
|
||||
int nvMax = sqlite3_limit(sqlite3_context_db_handle(context),
|
||||
SQLITE_LIMIT_LENGTH, -1);
|
||||
char *cBuf;
|
||||
@@ -309,7 +309,7 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
sqlite3_result_text(context,"",-1,SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
cBuf = sqlite3_malloc64(nc);
|
||||
cBuf = sqlite3_malloc(nc);
|
||||
if( !cBuf ) goto memFail;
|
||||
nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf);
|
||||
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
|
||||
@@ -331,7 +331,7 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
sqlite3_result_zeroblob(context, 0);
|
||||
break;
|
||||
}
|
||||
bBuf = sqlite3_malloc64(nb);
|
||||
bBuf = sqlite3_malloc(nb);
|
||||
if( !bBuf ) goto memFail;
|
||||
nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf);
|
||||
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
|
||||
@@ -352,14 +352,14 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_base85_init
|
||||
int sqlite3_base_init
|
||||
#else
|
||||
static int sqlite3_base85_init
|
||||
#endif
|
||||
(sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErr;
|
||||
#ifndef OMIT_BASE85_CHECKER
|
||||
# ifndef OMIT_BASE85_CHECKER
|
||||
{
|
||||
int rc = sqlite3_create_function
|
||||
(db, "is_base85", 1,
|
||||
@@ -367,7 +367,7 @@ static int sqlite3_base85_init
|
||||
0, is_base85, 0, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
return sqlite3_create_function
|
||||
(db, "base85", 1,
|
||||
SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8,
|
||||
@@ -432,9 +432,9 @@ int main(int na, char *av[]){
|
||||
int nc = strlen(cBuf);
|
||||
size_t nbo = fromBase85( cBuf, nc, bBuf ) - bBuf;
|
||||
if( 1 != fwrite(bBuf, nbo, 1, fb) ) rc = 1;
|
||||
#ifndef OMIT_BASE85_CHECKER
|
||||
# ifndef OMIT_BASE85_CHECKER
|
||||
b85Clean &= allBase85( cBuf, nc );
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -306,10 +306,6 @@ static int binfoCompute(sqlite3 *db, int pgno, BinfoCursor *pCsr){
|
||||
nEntry *= (nCell+1);
|
||||
if( aData[0]==10 || aData[0]==13 ) break;
|
||||
nPage *= (nCell+1);
|
||||
if( 14+2*(nCell/2)>=pgsz ){
|
||||
rc = SQLITE_CORRUPT;
|
||||
break;
|
||||
}
|
||||
if( nCell<=1 ){
|
||||
pgno = get_uint32(aData+8);
|
||||
}else{
|
||||
@@ -343,7 +339,7 @@ static int binfoColumn(
|
||||
sqlite3 *db = sqlite3_context_db_handle(ctx);
|
||||
int rc = binfoCompute(db, pgno, pCsr);
|
||||
if( rc ){
|
||||
pCursor->pVtab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc));
|
||||
pCursor->pVtab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file implements a table-valued-function that
|
||||
** This file demonstrates how to create a table-valued-function that
|
||||
** returns the values in a C-language array.
|
||||
** Examples:
|
||||
**
|
||||
@@ -52,9 +52,11 @@
|
||||
** as the number of elements in the array. The virtual table steps through
|
||||
** the array, element by element.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_CARRAY)
|
||||
#include "sqliteInt.h"
|
||||
#if defined(_WIN32) || defined(__RTP__) || defined(_WRS_KERNEL)
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
struct iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
@@ -62,13 +64,33 @@
|
||||
#else
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
|
||||
** Must exactly match the definitions in carray.h.
|
||||
*/
|
||||
#ifndef CARRAY_INT32
|
||||
# define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
# define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
# define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
# define CARRAY_TEXT 3 /* Data is char* */
|
||||
# define CARRAY_BLOB 4 /* Data is struct iovec* */
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_API
|
||||
# ifdef _WIN32
|
||||
# define SQLITE_API __declspec(dllexport)
|
||||
# else
|
||||
# define SQLITE_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Names of allowed datatypes
|
||||
*/
|
||||
static const char *azCarrayType[] = {
|
||||
"int32", "int64", "double", "char*", "struct iovec"
|
||||
};
|
||||
static const char *azType[] = { "int32", "int64", "double", "char*",
|
||||
"struct iovec" };
|
||||
|
||||
/*
|
||||
** Structure used to hold the sqlite3_carray_bind() information
|
||||
@@ -79,7 +101,6 @@ struct carray_bind {
|
||||
int nData; /* Number of elements */
|
||||
int mFlags; /* Control flags */
|
||||
void (*xDel)(void*); /* Destructor for aData */
|
||||
void *pDel; /* Alternative argument to xDel() */
|
||||
};
|
||||
|
||||
|
||||
@@ -188,7 +209,7 @@ static int carrayColumn(
|
||||
case CARRAY_COLUMN_POINTER: return SQLITE_OK;
|
||||
case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break;
|
||||
case CARRAY_COLUMN_CTYPE: {
|
||||
sqlite3_result_text(ctx, azCarrayType[pCur->eType], -1, SQLITE_STATIC);
|
||||
sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
default: {
|
||||
@@ -213,11 +234,10 @@ static int carrayColumn(
|
||||
sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
default: {
|
||||
case CARRAY_BLOB: {
|
||||
const struct iovec *p = (struct iovec*)pCur->pPtr;
|
||||
assert( pCur->eType==CARRAY_BLOB );
|
||||
sqlite3_result_blob(ctx, p[pCur->iRowid-1].iov_base,
|
||||
(int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT);
|
||||
(int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
@@ -276,10 +296,10 @@ static int carrayFilter(
|
||||
}else{
|
||||
unsigned char i;
|
||||
const char *zType = (const char*)sqlite3_value_text(argv[2]);
|
||||
for(i=0; i<sizeof(azCarrayType)/sizeof(azCarrayType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azCarrayType[i])==0 ) break;
|
||||
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
|
||||
}
|
||||
if( i>=sizeof(azCarrayType)/sizeof(azCarrayType[0]) ){
|
||||
if( i>=sizeof(azType)/sizeof(azType[0]) ){
|
||||
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||
"unknown datatype: %Q", zType);
|
||||
return SQLITE_ERROR;
|
||||
@@ -322,14 +342,12 @@ static int carrayBestIndex(
|
||||
int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */
|
||||
int cntIdx = -1; /* Index of the count= constraint, or -1 if none */
|
||||
int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */
|
||||
unsigned seen = 0; /* Bitmask of == constrainted columns */
|
||||
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
if( pConstraint->iColumn>=0 ) seen |= 1 << pConstraint->iColumn;
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
switch( pConstraint->iColumn ){
|
||||
case CARRAY_COLUMN_POINTER:
|
||||
ptrIdx = i;
|
||||
@@ -356,15 +374,7 @@ static int carrayBestIndex(
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 3;
|
||||
}else if( seen & (1<<CARRAY_COLUMN_CTYPE) ){
|
||||
/* In a three-argument carray(), we need to know the value of all
|
||||
** three arguments */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
}else if( seen & (1<<CARRAY_COLUMN_COUNT) ){
|
||||
/* In a two-argument carray(), we need to know the value of both
|
||||
** arguments */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
}else{
|
||||
pIdxInfo->estimatedCost = (double)2147483647;
|
||||
@@ -412,7 +422,7 @@ static sqlite3_module carrayModule = {
|
||||
static void carrayBindDel(void *pPtr){
|
||||
carray_bind *p = (carray_bind*)pPtr;
|
||||
if( p->xDel!=SQLITE_STATIC ){
|
||||
p->xDel(p->pDel);
|
||||
p->xDel(p->aData);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
}
|
||||
@@ -420,74 +430,51 @@ static void carrayBindDel(void *pPtr){
|
||||
/*
|
||||
** Invoke this interface in order to bind to the single-argument
|
||||
** version of CARRAY().
|
||||
**
|
||||
** pStmt The prepared statement to which to bind
|
||||
** idx The index of the parameter of pStmt to which to bind
|
||||
** aData The data to be bound
|
||||
** nData The number of elements in aData
|
||||
** mFlags One of SQLITE_CARRAY_xxxx indicating datatype of aData
|
||||
** xDestroy Destructor for pDestroy or aData if pDestroy==NULL.
|
||||
** pDestroy Invoke xDestroy on this pointer if not NULL
|
||||
**
|
||||
** The destructor is called pDestroy if pDestroy!=NULL, or against
|
||||
** aData if pDestroy==NULL.
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind_v2(
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt,
|
||||
int idx,
|
||||
void *aData,
|
||||
int nData,
|
||||
int mFlags,
|
||||
void (*xDestroy)(void*),
|
||||
void *pDestroy
|
||||
void (*xDestroy)(void*)
|
||||
){
|
||||
carray_bind *pNew = 0;
|
||||
carray_bind *pNew;
|
||||
int i;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
/* Ensure that the mFlags value is acceptable. */
|
||||
assert( CARRAY_INT32==0 && CARRAY_INT64==1 && CARRAY_DOUBLE==2 );
|
||||
assert( CARRAY_TEXT==3 && CARRAY_BLOB==4 );
|
||||
if( mFlags<CARRAY_INT32 || mFlags>CARRAY_BLOB ){
|
||||
rc = SQLITE_ERROR;
|
||||
goto carray_bind_error;
|
||||
}
|
||||
|
||||
pNew = sqlite3_malloc64(sizeof(*pNew));
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto carray_bind_error;
|
||||
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
|
||||
xDestroy(aData);
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
pNew->nData = nData;
|
||||
pNew->mFlags = mFlags;
|
||||
if( xDestroy==SQLITE_TRANSIENT ){
|
||||
sqlite3_int64 sz = nData;
|
||||
switch( mFlags ){
|
||||
switch( mFlags & 0x07 ){
|
||||
case CARRAY_INT32: sz *= 4; break;
|
||||
case CARRAY_INT64: sz *= 8; break;
|
||||
case CARRAY_DOUBLE: sz *= 8; break;
|
||||
case CARRAY_TEXT: sz *= sizeof(char*); break;
|
||||
default: sz *= sizeof(struct iovec); break;
|
||||
case CARRAY_BLOB: sz *= sizeof(struct iovec); break;
|
||||
}
|
||||
if( mFlags==CARRAY_TEXT ){
|
||||
if( (mFlags & 0x07)==CARRAY_TEXT ){
|
||||
for(i=0; i<nData; i++){
|
||||
const char *z = ((char**)aData)[i];
|
||||
if( z ) sz += strlen(z) + 1;
|
||||
}
|
||||
}else if( mFlags==CARRAY_BLOB ){
|
||||
}else if( (mFlags & 0x07)==CARRAY_BLOB ){
|
||||
for(i=0; i<nData; i++){
|
||||
sz += ((struct iovec*)aData)[i].iov_len;
|
||||
}
|
||||
}
|
||||
|
||||
pNew->aData = sqlite3_malloc64( sz );
|
||||
if( pNew->aData==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto carray_bind_error;
|
||||
sqlite3_free(pNew);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
if( mFlags==CARRAY_TEXT ){
|
||||
if( (mFlags & 0x07)==CARRAY_TEXT ){
|
||||
char **az = (char**)pNew->aData;
|
||||
char *z = (char*)&az[nData];
|
||||
for(i=0; i<nData; i++){
|
||||
@@ -502,7 +489,7 @@ SQLITE_API int sqlite3_carray_bind_v2(
|
||||
memcpy(z, zData, n+1);
|
||||
z += n+1;
|
||||
}
|
||||
}else if( mFlags==CARRAY_BLOB ){
|
||||
}else if( (mFlags & 0x07)==CARRAY_BLOB ){
|
||||
struct iovec *p = (struct iovec*)pNew->aData;
|
||||
unsigned char *z = (unsigned char*)&p[nData];
|
||||
for(i=0; i<nData; i++){
|
||||
@@ -516,43 +503,59 @@ SQLITE_API int sqlite3_carray_bind_v2(
|
||||
memcpy(pNew->aData, aData, sz);
|
||||
}
|
||||
pNew->xDel = sqlite3_free;
|
||||
pNew->pDel = pNew->aData;
|
||||
}else{
|
||||
pNew->aData = aData;
|
||||
pNew->xDel = xDestroy;
|
||||
pNew->pDel = pDestroy;
|
||||
}
|
||||
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
|
||||
|
||||
carray_bind_error:
|
||||
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
|
||||
xDestroy(pDestroy);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** For testing purpose in the TCL test harness, we need a method for
|
||||
** setting the pointer value. The inttoptr(X) SQL function accomplishes
|
||||
** this. Tcl script will bind an integer to X and the inttoptr() SQL
|
||||
** function will use sqlite3_result_pointer() to convert that integer into
|
||||
** a pointer.
|
||||
**
|
||||
** This is for testing on TCL only.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
static void inttoptrFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
void *p;
|
||||
sqlite3_int64 i64;
|
||||
i64 = sqlite3_value_int64(argv[0]);
|
||||
if( sizeof(i64)==sizeof(p) ){
|
||||
memcpy(&p, &i64, sizeof(p));
|
||||
}else{
|
||||
int i32 = i64 & 0xffffffff;
|
||||
memcpy(&p, &i32, sizeof(p));
|
||||
}
|
||||
sqlite3_free(pNew);
|
||||
sqlite3_result_pointer(context, p, "carray", 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
SQLITE_API int sqlite3_carray_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
|
||||
#ifdef SQLITE_TEST
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
|
||||
inttoptrFunc, 0, 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this interface in order to bind to the single-argument
|
||||
** version of CARRAY(). Same as sqlite3_carray_bind_v2() with the
|
||||
** pDestroy parameter set to NULL.
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt,
|
||||
int idx,
|
||||
void *aData,
|
||||
int nData,
|
||||
int mFlags,
|
||||
void (*xDestroy)(void*)
|
||||
){
|
||||
return sqlite3_carray_bind_v2(pStmt,idx,aData,nData,mFlags,xDestroy,aData);
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this routine to register the carray() function.
|
||||
*/
|
||||
Module *sqlite3CarrayRegister(sqlite3 *db){
|
||||
return sqlite3VtabCreateModule(db, "carray", &carrayModule, 0, 0);
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_CARRAY) */
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
** 2020-11-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.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** Interface definitions for the CARRAY table-valued function
|
||||
** extension.
|
||||
*/
|
||||
|
||||
#ifndef _CARRAY_H
|
||||
#define _CARRAY_H
|
||||
|
||||
#include "sqlite3.h" /* Required for error code definitions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Use this interface to bind an array to the single-argument version
|
||||
** of CARRAY().
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt, /* Statement to be bound */
|
||||
int i, /* Parameter index */
|
||||
void *aData, /* Pointer to array data */
|
||||
int nData, /* Number of data elements */
|
||||
int mFlags, /* CARRAY flags */
|
||||
void (*xDel)(void*) /* Destructgor for aData*/
|
||||
);
|
||||
|
||||
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
|
||||
*/
|
||||
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
#define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
#define CARRAY_TEXT 3 /* Data is char* */
|
||||
#define CARRAY_BLOB 4 /* Data is struct iovec */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#endif /* ifndef _CARRAY_H */
|
||||
+3
-3
@@ -516,7 +516,7 @@ static int closureConnect(
|
||||
|
||||
(void)pAux;
|
||||
*ppVtab = 0;
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
rc = SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -579,7 +579,7 @@ closureConnectError:
|
||||
static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
closure_vtab *p = (closure_vtab*)pVTab;
|
||||
closure_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->pVtab = p;
|
||||
@@ -638,7 +638,7 @@ static int closureInsertNode(
|
||||
sqlite3_int64 id, /* The node ID */
|
||||
int iGeneration /* The generation number for this node */
|
||||
){
|
||||
closure_avl *pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
closure_avl *pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->id = id;
|
||||
|
||||
+15
-30
@@ -132,7 +132,7 @@ static int completionConnect(
|
||||
" phase INT HIDDEN" /* Used for debugging only */
|
||||
")");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -154,7 +154,7 @@ static int completionDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
completion_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->db = ((completion_vtab*)p)->db;
|
||||
@@ -199,7 +199,6 @@ static int completionNext(sqlite3_vtab_cursor *cur){
|
||||
completion_cursor *pCur = (completion_cursor*)cur;
|
||||
int eNextPhase = 0; /* Next phase to try if current phase reaches end */
|
||||
int iCol = -1; /* If >=0, step pCur->pStmt and use the i-th column */
|
||||
int rc;
|
||||
pCur->iRowid++;
|
||||
while( pCur->ePhase!=COMPLETION_EOF ){
|
||||
switch( pCur->ePhase ){
|
||||
@@ -225,27 +224,22 @@ static int completionNext(sqlite3_vtab_cursor *cur){
|
||||
case COMPLETION_TABLES: {
|
||||
if( pCur->pStmt==0 ){
|
||||
sqlite3_stmt *pS2;
|
||||
sqlite3_str* pStr = sqlite3_str_new(pCur->db);
|
||||
char *zSql = 0;
|
||||
const char *zSep = "";
|
||||
sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
|
||||
while( sqlite3_step(pS2)==SQLITE_ROW ){
|
||||
const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
|
||||
sqlite3_str_appendf(pStr,
|
||||
"%s"
|
||||
zSql = sqlite3_mprintf(
|
||||
"%z%s"
|
||||
"SELECT name FROM \"%w\".sqlite_schema",
|
||||
zSep, zDb
|
||||
zSql, zSep, zDb
|
||||
);
|
||||
if( zSql==0 ) return SQLITE_NOMEM;
|
||||
zSep = " UNION ";
|
||||
}
|
||||
rc = sqlite3_finalize(pS2);
|
||||
zSql = sqlite3_str_finish(pStr);
|
||||
if( zSql==0 ) return SQLITE_NOMEM;
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
|
||||
}
|
||||
sqlite3_finalize(pS2);
|
||||
sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
iCol = 0;
|
||||
eNextPhase = COMPLETION_COLUMNS;
|
||||
@@ -254,29 +248,24 @@ static int completionNext(sqlite3_vtab_cursor *cur){
|
||||
case COMPLETION_COLUMNS: {
|
||||
if( pCur->pStmt==0 ){
|
||||
sqlite3_stmt *pS2;
|
||||
sqlite3_str *pStr = sqlite3_str_new(pCur->db);
|
||||
char *zSql = 0;
|
||||
const char *zSep = "";
|
||||
sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
|
||||
while( sqlite3_step(pS2)==SQLITE_ROW ){
|
||||
const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
|
||||
sqlite3_str_appendf(pStr,
|
||||
"%s"
|
||||
zSql = sqlite3_mprintf(
|
||||
"%z%s"
|
||||
"SELECT pti.name FROM \"%w\".sqlite_schema AS sm"
|
||||
" JOIN pragma_table_xinfo(sm.name,%Q) AS pti"
|
||||
" WHERE sm.type='table'",
|
||||
zSep, zDb, zDb
|
||||
zSql, zSep, zDb, zDb
|
||||
);
|
||||
if( zSql==0 ) return SQLITE_NOMEM;
|
||||
zSep = " UNION ";
|
||||
}
|
||||
rc = sqlite3_finalize(pS2);
|
||||
zSql = sqlite3_str_finish(pStr);
|
||||
if( zSql==0 ) return SQLITE_NOMEM;
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
|
||||
}
|
||||
sqlite3_finalize(pS2);
|
||||
sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
iCol = 0;
|
||||
eNextPhase = COMPLETION_EOF;
|
||||
@@ -293,10 +282,9 @@ static int completionNext(sqlite3_vtab_cursor *cur){
|
||||
pCur->szRow = sqlite3_column_bytes(pCur->pStmt, iCol);
|
||||
}else{
|
||||
/* When all rows are finished, advance to the next phase */
|
||||
rc = sqlite3_finalize(pCur->pStmt);
|
||||
sqlite3_finalize(pCur->pStmt);
|
||||
pCur->pStmt = 0;
|
||||
pCur->ePhase = eNextPhase;
|
||||
if( rc ) return rc;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -382,7 +370,6 @@ static int completionFilter(
|
||||
if( pCur->nPrefix>0 ){
|
||||
pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
|
||||
if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
|
||||
pCur->nPrefix = (int)strlen(pCur->zPrefix);
|
||||
}
|
||||
iArg = 1;
|
||||
}
|
||||
@@ -391,7 +378,6 @@ static int completionFilter(
|
||||
if( pCur->nLine>0 ){
|
||||
pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
|
||||
if( pCur->zLine==0 ) return SQLITE_NOMEM;
|
||||
pCur->nLine = (int)strlen(pCur->zLine);
|
||||
}
|
||||
}
|
||||
if( pCur->zLine!=0 && pCur->zPrefix==0 ){
|
||||
@@ -403,7 +389,6 @@ static int completionFilter(
|
||||
if( pCur->nPrefix>0 ){
|
||||
pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i);
|
||||
if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
|
||||
pCur->nPrefix = (int)strlen(pCur->zPrefix);
|
||||
}
|
||||
}
|
||||
pCur->iRowid = 0;
|
||||
|
||||
+2
-2
@@ -59,7 +59,7 @@ static void compressFunc(
|
||||
pIn = sqlite3_value_blob(argv[0]);
|
||||
nIn = sqlite3_value_bytes(argv[0]);
|
||||
nOut = 13 + nIn + (nIn+999)/1000;
|
||||
pOut = sqlite3_malloc64( nOut+5 );
|
||||
pOut = sqlite3_malloc( nOut+5 );
|
||||
for(i=4; i>=0; i--){
|
||||
x[i] = (nIn >> (7*(4-i)))&0x7f;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ static void uncompressFunc(
|
||||
nOut = (nOut<<7) | (pIn[i]&0x7f);
|
||||
if( (pIn[i]&0x80)!=0 ){ i++; break; }
|
||||
}
|
||||
pOut = sqlite3_malloc64( nOut+1 );
|
||||
pOut = sqlite3_malloc( nOut+1 );
|
||||
rc = uncompress(pOut, &nOut, &pIn[i], nIn-i);
|
||||
if( rc==Z_OK ){
|
||||
sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
|
||||
|
||||
+15
-18
@@ -24,8 +24,8 @@
|
||||
** schema= parameter, like this:
|
||||
**
|
||||
** CREATE VIRTUAL TABLE temp.csv2 USING csv(
|
||||
** filename = '../http.log',
|
||||
** schema = 'CREATE TABLE x(date,ipaddr,url,referrer,userAgent)'
|
||||
** filename = "../http.log",
|
||||
** schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)"
|
||||
** );
|
||||
**
|
||||
** Instead of specifying a file, the text of the CSV can be loaded using
|
||||
@@ -62,10 +62,6 @@ SQLITE_EXTENSION_INIT1
|
||||
# define CSV_NOINLINE
|
||||
#endif
|
||||
|
||||
#ifndef SQLITEINT_H
|
||||
typedef sqlite3_int64 i64;
|
||||
typedef sqlite3_uint64 u64;
|
||||
#endif
|
||||
|
||||
/* Max size of the error message in a CsvReader */
|
||||
#define CSV_MXERR 200
|
||||
@@ -78,9 +74,9 @@ typedef struct CsvReader CsvReader;
|
||||
struct CsvReader {
|
||||
FILE *in; /* Read the CSV text from this input stream */
|
||||
char *z; /* Accumulated text for a field */
|
||||
i64 n; /* Number of bytes in z */
|
||||
i64 nAlloc; /* Space allocated for z[] */
|
||||
i64 nLine; /* Current line number */
|
||||
int n; /* Number of bytes in z */
|
||||
int nAlloc; /* Space allocated for z[] */
|
||||
int nLine; /* Current line number */
|
||||
int bNotFirst; /* True if prior text has been seen */
|
||||
int cTerm; /* Character that terminated the most recent field */
|
||||
size_t iIn; /* Next unread character in the input buffer */
|
||||
@@ -129,7 +125,7 @@ static int csv_reader_open(
|
||||
const char *zData /* ... or use this data */
|
||||
){
|
||||
if( zFilename ){
|
||||
p->zIn = sqlite3_malloc64( CSV_INBUFSZ );
|
||||
p->zIn = sqlite3_malloc( CSV_INBUFSZ );
|
||||
if( p->zIn==0 ){
|
||||
csv_errmsg(p, "out of memory");
|
||||
return 1;
|
||||
@@ -178,7 +174,7 @@ static int csv_getc(CsvReader *p){
|
||||
** Return 0 on success and non-zero if there is an OOM error */
|
||||
static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){
|
||||
char *zNew;
|
||||
i64 nNew = p->nAlloc*2 + 100;
|
||||
int nNew = p->nAlloc*2 + 100;
|
||||
zNew = sqlite3_realloc64(p->z, nNew);
|
||||
if( zNew ){
|
||||
p->z = zNew;
|
||||
@@ -222,7 +218,7 @@ static char *csv_read_one_field(CsvReader *p){
|
||||
}
|
||||
if( c=='"' ){
|
||||
int pc, ppc;
|
||||
i64 startLine = p->nLine;
|
||||
int startLine = p->nLine;
|
||||
pc = ppc = 0;
|
||||
while( 1 ){
|
||||
c = csv_getc(p);
|
||||
@@ -326,7 +322,7 @@ typedef struct CsvCursor {
|
||||
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
||||
CsvReader rdr; /* The CsvReader object */
|
||||
char **azVal; /* Value of the current row */
|
||||
i64 *aLen; /* Length of each entry */
|
||||
int *aLen; /* Length of each entry */
|
||||
sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */
|
||||
} CsvCursor;
|
||||
|
||||
@@ -498,7 +494,7 @@ static int csvtabConnect(
|
||||
CsvTable *pNew = 0; /* The CsvTable object to construct */
|
||||
int bHeader = -1; /* header= flags. -1 means not seen yet */
|
||||
int rc = SQLITE_OK; /* Result code from this routine */
|
||||
u64 i, j; /* Loop counters */
|
||||
int i, j; /* Loop counters */
|
||||
#ifdef SQLITE_TEST
|
||||
int tstFlags = 0; /* Value for testflags=N parameter */
|
||||
#endif
|
||||
@@ -514,10 +510,11 @@ static int csvtabConnect(
|
||||
# define CSV_DATA (azPValue[1])
|
||||
# define CSV_SCHEMA (azPValue[2])
|
||||
|
||||
|
||||
assert( sizeof(azPValue)==sizeof(azParam) );
|
||||
memset(&sRdr, 0, sizeof(sRdr));
|
||||
memset(azPValue, 0, sizeof(azPValue));
|
||||
for(i=3; i<(u64)argc; i++){
|
||||
for(i=3; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
const char *zValue;
|
||||
for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){
|
||||
@@ -564,7 +561,7 @@ static int csvtabConnect(
|
||||
){
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) goto csvtab_connect_oom;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -710,12 +707,12 @@ static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
CsvTable *pTab = (CsvTable*)p;
|
||||
CsvCursor *pCur;
|
||||
size_t nByte;
|
||||
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(i64))*pTab->nCol;
|
||||
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol;
|
||||
pCur = sqlite3_malloc64( nByte );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, nByte);
|
||||
pCur->azVal = (char**)&pCur[1];
|
||||
pCur->aLen = (i64*)&pCur->azVal[pTab->nCol];
|
||||
pCur->aLen = (int*)&pCur->azVal[pTab->nCol];
|
||||
*ppCursor = &pCur->base;
|
||||
if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){
|
||||
csv_xfer_error(pTab, &pCur->rdr);
|
||||
|
||||
+6
-6
@@ -67,9 +67,9 @@ struct DState {
|
||||
*/
|
||||
typedef struct DText DText;
|
||||
struct DText {
|
||||
char *z; /* The text */
|
||||
sqlite3_int64 n; /* Number of bytes of content in z[] */
|
||||
sqlite3_int64 nAlloc; /* Number of bytes allocated to z[] */
|
||||
char *z; /* The text */
|
||||
int n; /* Number of bytes of content in z[] */
|
||||
int nAlloc; /* Number of bytes allocated to z[] */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -107,7 +107,7 @@ static void appendText(DText *p, char const *zAppend, char quote){
|
||||
if( p->n+len>=p->nAlloc ){
|
||||
char *zNew;
|
||||
p->nAlloc = p->nAlloc*2 + len + 20;
|
||||
zNew = sqlite3_realloc64(p->z, p->nAlloc);
|
||||
zNew = sqlite3_realloc(p->z, p->nAlloc);
|
||||
if( zNew==0 ){
|
||||
freeText(p);
|
||||
return;
|
||||
@@ -179,8 +179,8 @@ static char **tableColumnList(DState *p, const char *zTab){
|
||||
char **azCol = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char *zSql;
|
||||
sqlite3_int64 nCol = 0;
|
||||
sqlite3_int64 nAlloc = 0;
|
||||
int nCol = 0;
|
||||
int nAlloc = 0;
|
||||
int nPK = 0; /* Number of PRIMARY KEY columns seen */
|
||||
int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
|
||||
int preserveRowid = 1;
|
||||
|
||||
+19
-84
@@ -31,10 +31,6 @@ SQLITE_EXTENSION_INIT1
|
||||
#define IsSpace(X) isspace((unsigned char)X)
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_DECIMAL_MAX_DIGIT
|
||||
# define SQLITE_DECIMAL_MAX_DIGIT 10000000
|
||||
#endif
|
||||
|
||||
/* A decimal object */
|
||||
typedef struct Decimal Decimal;
|
||||
struct Decimal {
|
||||
@@ -73,8 +69,7 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
|
||||
int i;
|
||||
int iExp = 0;
|
||||
|
||||
if( zIn==0 ) goto new_from_text_failed;
|
||||
p = sqlite3_malloc64( sizeof(*p) );
|
||||
p = sqlite3_malloc( sizeof(*p) );
|
||||
if( p==0 ) goto new_from_text_failed;
|
||||
p->sign = 0;
|
||||
p->oom = 0;
|
||||
@@ -133,10 +128,8 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
|
||||
}
|
||||
}
|
||||
if( iExp>0 ){
|
||||
signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit
|
||||
+ (sqlite3_int64)iExp + 1 );
|
||||
if( a==0 ) goto new_from_text_failed;
|
||||
p->a = a;
|
||||
p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
|
||||
if( p->a==0 ) goto new_from_text_failed;
|
||||
memset(p->a+p->nDigit, 0, iExp);
|
||||
p->nDigit += iExp;
|
||||
}
|
||||
@@ -154,21 +147,14 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
|
||||
}
|
||||
}
|
||||
if( iExp>0 ){
|
||||
signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit
|
||||
+ (sqlite3_int64)iExp + 1 );
|
||||
if( a==0 ) goto new_from_text_failed;
|
||||
p->a = a;
|
||||
p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
|
||||
if( p->a==0 ) goto new_from_text_failed;
|
||||
memmove(p->a+iExp, p->a, p->nDigit);
|
||||
memset(p->a, 0, iExp);
|
||||
p->nDigit += iExp;
|
||||
p->nFrac += iExp;
|
||||
}
|
||||
}
|
||||
if( p->sign ){
|
||||
for(i=0; i<p->nDigit && p->a[i]==0; i++){}
|
||||
if( i>=p->nDigit ) p->sign = 0;
|
||||
}
|
||||
if( p->nDigit>SQLITE_DECIMAL_MAX_DIGIT ) goto new_from_text_failed;
|
||||
return p;
|
||||
|
||||
new_from_text_failed:
|
||||
@@ -261,7 +247,7 @@ static void decimal_result(sqlite3_context *pCtx, Decimal *p){
|
||||
sqlite3_result_null(pCtx);
|
||||
return;
|
||||
}
|
||||
z = sqlite3_malloc64( (sqlite3_int64)p->nDigit+4 );
|
||||
z = sqlite3_malloc( p->nDigit+4 );
|
||||
if( z==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return;
|
||||
@@ -299,38 +285,12 @@ static void decimal_result(sqlite3_context *pCtx, Decimal *p){
|
||||
sqlite3_result_text(pCtx, z, i, sqlite3_free);
|
||||
}
|
||||
|
||||
/*
|
||||
** Round a decimal value to N significant digits. N must be positive.
|
||||
*/
|
||||
static void decimal_round(Decimal *p, int N){
|
||||
int i;
|
||||
int nZero;
|
||||
if( N<1 ) return;
|
||||
if( p==0 ) return;
|
||||
if( p->nDigit<=N ) return;
|
||||
for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){}
|
||||
N += nZero;
|
||||
if( p->nDigit<=N ) return;
|
||||
if( p->a[N]>4 ){
|
||||
p->a[N-1]++;
|
||||
for(i=N-1; i>0 && p->a[i]>9; i--){
|
||||
p->a[i] = 0;
|
||||
p->a[i-1]++;
|
||||
}
|
||||
if( p->a[0]>9 ){
|
||||
p->a[0] = 1;
|
||||
p->nFrac--;
|
||||
}
|
||||
}
|
||||
memset(&p->a[N], 0, p->nDigit - N);
|
||||
}
|
||||
|
||||
/*
|
||||
** Make the given Decimal the result in an format similar to '%+#e'.
|
||||
** In other words, show exponential notation with leading and trailing
|
||||
** zeros omitted.
|
||||
*/
|
||||
static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){
|
||||
static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p){
|
||||
char *z; /* The output buffer */
|
||||
int i; /* Loop counter */
|
||||
int nZero; /* Number of leading zeros */
|
||||
@@ -348,12 +308,11 @@ static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){
|
||||
sqlite3_result_null(pCtx);
|
||||
return;
|
||||
}
|
||||
if( N<1 ) N = 0;
|
||||
for(nDigit=p->nDigit; nDigit>N && p->a[nDigit-1]==0; nDigit--){}
|
||||
for(nDigit=p->nDigit; nDigit>0 && p->a[nDigit-1]==0; nDigit--){}
|
||||
for(nZero=0; nZero<nDigit && p->a[nZero]==0; nZero++){}
|
||||
nFrac = p->nFrac + (nDigit - p->nDigit);
|
||||
nDigit -= nZero;
|
||||
z = sqlite3_malloc64( (sqlite3_int64)nDigit+20 );
|
||||
z = sqlite3_malloc( nDigit+20 );
|
||||
if( z==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return;
|
||||
@@ -398,21 +357,13 @@ static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){
|
||||
** pB!=0
|
||||
** pB->isNull==0
|
||||
*/
|
||||
static int decimal_cmp(Decimal *pA, Decimal *pB){
|
||||
static int decimal_cmp(const Decimal *pA, const Decimal *pB){
|
||||
int nASig, nBSig, rc, n;
|
||||
while( pA->nFrac>0 && pA->a[pA->nDigit-1]==0 ){
|
||||
pA->nDigit--;
|
||||
pA->nFrac--;
|
||||
}
|
||||
while( pB->nFrac>0 && pB->a[pB->nDigit-1]==0 ){
|
||||
pB->nDigit--;
|
||||
pB->nFrac--;
|
||||
}
|
||||
if( pA->sign!=pB->sign ){
|
||||
return pA->sign ? -1 : +1;
|
||||
}
|
||||
if( pA->sign ){
|
||||
Decimal *pTemp = pA;
|
||||
const Decimal *pTemp = pA;
|
||||
pA = pB;
|
||||
pB = pTemp;
|
||||
}
|
||||
@@ -465,18 +416,15 @@ cmp_done:
|
||||
static void decimal_expand(Decimal *p, int nDigit, int nFrac){
|
||||
int nAddSig;
|
||||
int nAddFrac;
|
||||
signed char *a;
|
||||
if( p==0 ) return;
|
||||
nAddFrac = nFrac - p->nFrac;
|
||||
nAddSig = (nDigit - p->nDigit) - nAddFrac;
|
||||
if( nAddFrac==0 && nAddSig==0 ) return;
|
||||
if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; }
|
||||
a = sqlite3_realloc64(p->a, nDigit+1);
|
||||
if( a==0 ){
|
||||
p->a = sqlite3_realloc64(p->a, nDigit+1);
|
||||
if( p->a==0 ){
|
||||
p->oom = 1;
|
||||
return;
|
||||
}
|
||||
p->a = a;
|
||||
if( nAddSig ){
|
||||
memmove(p->a+nAddSig, p->a, p->nDigit);
|
||||
memset(p->a, 0, nAddSig);
|
||||
@@ -571,18 +519,13 @@ static void decimalMul(Decimal *pA, Decimal *pB){
|
||||
signed char *acc = 0;
|
||||
int i, j, k;
|
||||
int minFrac;
|
||||
sqlite3_int64 sumDigit;
|
||||
|
||||
if( pA==0 || pA->oom || pA->isNull
|
||||
|| pB==0 || pB->oom || pB->isNull
|
||||
){
|
||||
goto mul_end;
|
||||
}
|
||||
sumDigit = pA->nDigit;
|
||||
sumDigit += pB->nDigit;
|
||||
sumDigit += 2;
|
||||
if( sumDigit>SQLITE_DECIMAL_MAX_DIGIT ){ pA->oom = 1; return; }
|
||||
acc = sqlite3_malloc64( sumDigit );
|
||||
acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 );
|
||||
if( acc==0 ){
|
||||
pA->oom = 1;
|
||||
goto mul_end;
|
||||
@@ -669,7 +612,7 @@ static Decimal *decimalFromDouble(double r){
|
||||
isNeg = 0;
|
||||
}
|
||||
memcpy(&a,&r,sizeof(a));
|
||||
if( a==0 || a==(sqlite3_int64)0x8000000000000000LL){
|
||||
if( a==0 ){
|
||||
e = 0;
|
||||
m = 0;
|
||||
}else{
|
||||
@@ -719,16 +662,10 @@ static void decimalFunc(
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Decimal *p = decimal_new(context, argv[0], 0);
|
||||
int N;
|
||||
if( argc==2 ){
|
||||
N = sqlite3_value_int(argv[1]);
|
||||
if( N>0 ) decimal_round(p, N);
|
||||
}else{
|
||||
N = 0;
|
||||
}
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( p ){
|
||||
if( sqlite3_user_data(context)!=0 ){
|
||||
decimal_result_sci(context, p, N);
|
||||
decimal_result_sci(context, p);
|
||||
}else{
|
||||
decimal_result(context, p);
|
||||
}
|
||||
@@ -814,7 +751,7 @@ static void decimalSumStep(
|
||||
if( p==0 ) return;
|
||||
if( !p->isInit ){
|
||||
p->isInit = 1;
|
||||
p->a = sqlite3_malloc64(2);
|
||||
p->a = sqlite3_malloc(2);
|
||||
if( p->a==0 ){
|
||||
p->oom = 1;
|
||||
}else{
|
||||
@@ -898,7 +835,7 @@ static void decimalPow2Func(
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
|
||||
Decimal *pA = decimalPow2(sqlite3_value_int(argv[0]));
|
||||
decimal_result_sci(context, pA, 0);
|
||||
decimal_result_sci(context, pA);
|
||||
decimal_free(pA);
|
||||
}
|
||||
}
|
||||
@@ -919,9 +856,7 @@ int sqlite3_decimal_init(
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} aFunc[] = {
|
||||
{ "decimal", 1, 0, decimalFunc },
|
||||
{ "decimal", 2, 0, decimalFunc },
|
||||
{ "decimal_exp", 1, 1, decimalFunc },
|
||||
{ "decimal_exp", 2, 1, decimalFunc },
|
||||
{ "decimal_cmp", 2, 0, decimalCmpFunc },
|
||||
{ "decimal_add", 2, 0, decimalAddFunc },
|
||||
{ "decimal_sub", 2, 0, decimalSubFunc },
|
||||
|
||||
+2
-2
@@ -92,7 +92,7 @@ static int explainConnect(
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(addr,opcode,p1,p2,p3,p4,p5,comment,sql HIDDEN)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -114,7 +114,7 @@ static int explainDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int explainOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
explain_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->db = ((explain_vtab*)p)->db;
|
||||
|
||||
+75
-177
@@ -73,6 +73,11 @@
|
||||
** $path is a relative path, then $path is interpreted relative to $dir.
|
||||
** And the paths returned in the "name" column of the table are also
|
||||
** relative to directory $dir.
|
||||
**
|
||||
** Notes on building this extension for Windows:
|
||||
** Unless linked statically with the SQLite library, a preprocessor
|
||||
** symbol, FILEIO_WIN32_DLL, must be #define'd to create a stand-alone
|
||||
** DLL form of this extension for WIN32. See its use below for details.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
@@ -89,16 +94,12 @@ SQLITE_EXTENSION_INIT1
|
||||
# include <utime.h>
|
||||
# include <sys/time.h>
|
||||
# define STRUCT_STAT struct stat
|
||||
# include <limits.h>
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "windirent.h"
|
||||
# include <direct.h>
|
||||
# define STRUCT_STAT struct _stat
|
||||
# define chmod(path,mode) fileio_chmod(path,mode)
|
||||
# define mkdir(path,mode) fileio_mkdir(path)
|
||||
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
|
||||
extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
@@ -130,9 +131,12 @@ SQLITE_EXTENSION_INIT1
|
||||
*/
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
static int fileio_chmod(const char *zPath, int pmode){
|
||||
sqlite3_int64 sz = strlen(zPath);
|
||||
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
|
||||
int rc;
|
||||
wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath);
|
||||
if( b1==0 ) return -1;
|
||||
sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
|
||||
b1[sz] = 0;
|
||||
rc = _wchmod(b1, pmode);
|
||||
sqlite3_free(b1);
|
||||
return rc;
|
||||
@@ -144,9 +148,12 @@ static int fileio_chmod(const char *zPath, int pmode){
|
||||
*/
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
static int fileio_mkdir(const char *zPath){
|
||||
sqlite3_int64 sz = strlen(zPath);
|
||||
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
|
||||
int rc;
|
||||
wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath);
|
||||
if( b1==0 ) return -1;
|
||||
sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
|
||||
b1[sz] = 0;
|
||||
rc = _wmkdir(b1);
|
||||
sqlite3_free(b1);
|
||||
return rc;
|
||||
@@ -259,7 +266,50 @@ static sqlite3_uint64 fileTimeToUnixTime(
|
||||
|
||||
return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
|
||||
#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
|
||||
# /* To allow a standalone DLL, use this next replacement function: */
|
||||
# undef sqlite3_win32_utf8_to_unicode
|
||||
# define sqlite3_win32_utf8_to_unicode utf8_to_utf16
|
||||
#
|
||||
LPWSTR utf8_to_utf16(const char *z){
|
||||
int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0);
|
||||
LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR));
|
||||
if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) )
|
||||
return rv;
|
||||
sqlite3_free(rv);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function attempts to normalize the time values found in the stat()
|
||||
** buffer to UTC. This is necessary on Win32, where the runtime library
|
||||
** appears to return these values as local times.
|
||||
*/
|
||||
static void statTimesToUtc(
|
||||
const char *zPath,
|
||||
STRUCT_STAT *pStatBuf
|
||||
){
|
||||
HANDLE hFindFile;
|
||||
WIN32_FIND_DATAW fd;
|
||||
LPWSTR zUnicodeName;
|
||||
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
|
||||
zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath);
|
||||
if( zUnicodeName ){
|
||||
memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
|
||||
hFindFile = FindFirstFileW(zUnicodeName, &fd);
|
||||
if( hFindFile!=NULL ){
|
||||
pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
|
||||
pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime);
|
||||
pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime);
|
||||
FindClose(hFindFile);
|
||||
}
|
||||
sqlite3_free(zUnicodeName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function is used in place of stat(). On Windows, special handling
|
||||
@@ -271,23 +321,14 @@ static int fileStat(
|
||||
STRUCT_STAT *pStatBuf
|
||||
){
|
||||
#if defined(_WIN32)
|
||||
sqlite3_int64 sz = strlen(zPath);
|
||||
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
|
||||
int rc;
|
||||
wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath);
|
||||
if( b1==0 ) return 1;
|
||||
sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
|
||||
b1[sz] = 0;
|
||||
rc = _wstat(b1, pStatBuf);
|
||||
if( rc==0 ){
|
||||
HANDLE hFindFile;
|
||||
WIN32_FIND_DATAW fd;
|
||||
memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
|
||||
hFindFile = FindFirstFileW(b1, &fd);
|
||||
if( hFindFile!=NULL ){
|
||||
pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
|
||||
pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime);
|
||||
pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime);
|
||||
FindClose(hFindFile);
|
||||
}
|
||||
}
|
||||
sqlite3_free(b1);
|
||||
if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
|
||||
return rc;
|
||||
#else
|
||||
return stat(zPath, pStatBuf);
|
||||
@@ -418,6 +459,7 @@ static int writeFile(
|
||||
|
||||
if( mtime>=0 ){
|
||||
#if defined(_WIN32)
|
||||
#if !SQLITE_OS_WINRT
|
||||
/* Windows */
|
||||
FILETIME lastAccess;
|
||||
FILETIME lastWrite;
|
||||
@@ -448,6 +490,7 @@ static int writeFile(
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
|
||||
/* Recent unix */
|
||||
struct timespec times[2];
|
||||
@@ -613,7 +656,7 @@ static int fsdirConnect(
|
||||
(void)pzErr;
|
||||
rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = (fsdir_tab*)sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
@@ -636,7 +679,7 @@ static int fsdirDisconnect(sqlite3_vtab *pVtab){
|
||||
static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
fsdir_cursor *pCur;
|
||||
(void)p;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->iLvl = -1;
|
||||
@@ -717,7 +760,7 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){
|
||||
pCur->zPath = 0;
|
||||
pLvl->pDir = opendir(pLvl->zDir);
|
||||
if( pLvl->pDir==0 ){
|
||||
fsdirSetErrmsg(pCur, "cannot read directory: %s", pLvl->zDir);
|
||||
fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -1051,154 +1094,6 @@ static int fsdirRegister(sqlite3 *db){
|
||||
# define fsdirRegister(x) SQLITE_OK
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This version of realpath() works on any system. The string
|
||||
** returned is held in memory allocated using sqlite3_malloc64().
|
||||
** The caller is responsible for calling sqlite3_free().
|
||||
*/
|
||||
static char *portable_realpath(const char *zPath){
|
||||
#if !defined(_WIN32) /* BEGIN unix */
|
||||
|
||||
char *zOut = 0; /* Result */
|
||||
char *z; /* Temporary buffer */
|
||||
#if defined(PATH_MAX)
|
||||
char zBuf[PATH_MAX+1]; /* Space for the temporary buffer */
|
||||
#endif
|
||||
|
||||
if( zPath==0 ) return 0;
|
||||
#if defined(PATH_MAX)
|
||||
z = realpath(zPath, zBuf);
|
||||
if( z ){
|
||||
zOut = sqlite3_mprintf("%s", zBuf);
|
||||
}
|
||||
#endif /* defined(PATH_MAX) */
|
||||
if( zOut==0 ){
|
||||
/* Try POSIX.1-2008 malloc behavior */
|
||||
z = realpath(zPath, NULL);
|
||||
if( z ){
|
||||
zOut = sqlite3_mprintf("%s", z);
|
||||
free(z);
|
||||
}
|
||||
}
|
||||
return zOut;
|
||||
|
||||
#else /* End UNIX, Begin WINDOWS */
|
||||
|
||||
wchar_t *zPath16; /* UTF16 translation of zPath */
|
||||
char *zOut = 0; /* Result */
|
||||
wchar_t *z = 0; /* Temporary buffer */
|
||||
|
||||
if( zPath==0 ) return 0;
|
||||
|
||||
zPath16 = sqlite3_win32_utf8_to_unicode(zPath);
|
||||
if( zPath16==0 ) return 0;
|
||||
z = _wfullpath(NULL, zPath16, 0);
|
||||
sqlite3_free(zPath16);
|
||||
if( z ){
|
||||
zOut = sqlite3_win32_unicode_to_utf8(z);
|
||||
free(z);
|
||||
}
|
||||
return zOut;
|
||||
|
||||
#endif /* End WINDOWS, Begin common code */
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: realpath(X)
|
||||
**
|
||||
** Try to convert file or pathname X into its real, absolute pathname.
|
||||
** Return NULL if unable.
|
||||
**
|
||||
** The file or directory X is not required to exist. The answer is formed
|
||||
** by calling system realpath() on the prefix of X that does exist and
|
||||
** appending the tail of X that does not (yet) exist.
|
||||
*/
|
||||
static void realpathFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zPath; /* Original input path */
|
||||
char *zCopy; /* An editable copy of zPath */
|
||||
char *zOut; /* The result */
|
||||
char cSep = 0; /* Separator turned into \000 */
|
||||
size_t len; /* Prefix length before cSep */
|
||||
#ifdef _WIN32
|
||||
const int isWin = 1;
|
||||
#else
|
||||
const int isWin = 0;
|
||||
#endif
|
||||
|
||||
(void)argc;
|
||||
zPath = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zPath==0 ) return;
|
||||
if( zPath[0]==0 ) zPath = ".";
|
||||
zCopy = sqlite3_mprintf("%s",zPath);
|
||||
len = strlen(zCopy);
|
||||
while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){
|
||||
len--;
|
||||
}
|
||||
zCopy[len] = 0;
|
||||
while( 1 /*exit-by-break*/ ){
|
||||
zOut = portable_realpath(zCopy);
|
||||
zCopy[len] = cSep;
|
||||
if( zOut ){
|
||||
if( cSep ){
|
||||
zOut = sqlite3_mprintf("%z%s",zOut,&zCopy[len]);
|
||||
}
|
||||
break;
|
||||
}else{
|
||||
size_t i = len-1;
|
||||
while( i>0 ){
|
||||
if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ) break;
|
||||
i--;
|
||||
}
|
||||
if( i<=0 ){
|
||||
if( zCopy[0]=='/' ){
|
||||
zOut = zCopy;
|
||||
zCopy = 0;
|
||||
}else if( (zOut = portable_realpath("."))!=0 ){
|
||||
zOut = sqlite3_mprintf("%z/%s", zOut, zCopy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
cSep = zCopy[i];
|
||||
zCopy[i] = 0;
|
||||
len = i;
|
||||
}
|
||||
}
|
||||
sqlite3_free(zCopy);
|
||||
if( zOut ){
|
||||
/* Simplify any "/./" or "/../" that might have snuck into the
|
||||
** pathname due to appending of zCopy. We only have to consider
|
||||
** unix "/" separators, because the _wfilepath() system call on
|
||||
** Windows will have already done this simplification for us. */
|
||||
size_t i, j, n;
|
||||
n = strlen(zOut);
|
||||
for(i=j=0; i<n; i++){
|
||||
if( zOut[i]=='/' ){
|
||||
if( zOut[i+1]=='/' ) continue;
|
||||
if( zOut[i+1]=='.' && i+2<n && zOut[i+2]=='/' ){
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if( zOut[i+1]=='.' && i+3<n && zOut[i+2]=='.' && zOut[i+3]=='/' ){
|
||||
while( j>0 && zOut[j-1]!='/' ){ j--; }
|
||||
if( j>0 ){ j--; }
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
zOut[j++] = zOut[i];
|
||||
}
|
||||
zOut[j] = 0;
|
||||
|
||||
/* Return the result */
|
||||
sqlite3_result_text(context, zOut, -1, sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
@@ -1225,10 +1120,13 @@ int sqlite3_fileio_init(
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fsdirRegister(db);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "realpath", 1,
|
||||
SQLITE_UTF8, 0,
|
||||
realpathFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
|
||||
/* To allow a standalone DLL, make test_windirent.c use the same
|
||||
* redefined SQLite API calls as the above extension code does.
|
||||
* Just pull in this .c to accomplish this. As a beneficial side
|
||||
* effect, this extension becomes a single translation unit. */
|
||||
# include "test_windirent.c"
|
||||
#endif
|
||||
|
||||
+14
-30
@@ -27,7 +27,7 @@
|
||||
** This delta format is used by the RBU extension, which is the main
|
||||
** reason that these routines are included in the extension library.
|
||||
** RBU does not use this extension directly. Rather, this extension is
|
||||
** provided as a convenience to developers who want to analyze RBU files
|
||||
** provided as a convenience to developers who want to analyze RBU files
|
||||
** that contain deltas.
|
||||
*/
|
||||
#include <string.h>
|
||||
@@ -38,11 +38,9 @@ SQLITE_EXTENSION_INIT1
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
/*
|
||||
** The "u32" type must be an unsigned 32-bit integer. "u64" is
|
||||
** an unsigned 64-bit integer.
|
||||
** The "u32" type must be an unsigned 32-bit integer. Adjust this
|
||||
*/
|
||||
typedef unsigned int u32;
|
||||
typedef sqlite3_uint64 u64;
|
||||
|
||||
/*
|
||||
** Must be a 16-bit value
|
||||
@@ -543,8 +541,8 @@ static int delta_apply(
|
||||
int lenDelta, /* Length of the delta */
|
||||
char *zOut /* Write the output into this preallocated buffer */
|
||||
){
|
||||
sqlite3_uint64 limit;
|
||||
sqlite3_uint64 total = 0;
|
||||
unsigned int limit;
|
||||
unsigned int total = 0;
|
||||
#ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST
|
||||
char *zOrigOut = zOut;
|
||||
#endif
|
||||
@@ -572,7 +570,7 @@ static int delta_apply(
|
||||
/* ERROR: copy exceeds output file size */
|
||||
return -1;
|
||||
}
|
||||
if( (u64)ofst+(u64)cnt > (u64)lenSrc ){
|
||||
if( ofst+cnt > lenSrc ){
|
||||
/* ERROR: copy extends past end of input */
|
||||
return -1;
|
||||
}
|
||||
@@ -843,7 +841,7 @@ static int deltaparsevtabDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int deltaparsevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
deltaparsevtab_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
@@ -870,21 +868,11 @@ static int deltaparsevtabNext(sqlite3_vtab_cursor *cur){
|
||||
int i = 0;
|
||||
|
||||
pCur->iCursor = pCur->iNext;
|
||||
if( pCur->iCursor >= pCur->nDelta ){
|
||||
pCur->eOp = DELTAPARSE_OP_ERROR;
|
||||
pCur->iNext = pCur->nDelta;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
z = pCur->aDelta + pCur->iCursor;
|
||||
pCur->a1 = deltaGetInt(&z, &i);
|
||||
switch( z[0] ){
|
||||
case '@': {
|
||||
z++;
|
||||
if( pCur->iNext>=pCur->nDelta ){
|
||||
pCur->eOp = DELTAPARSE_OP_ERROR;
|
||||
pCur->iNext = pCur->nDelta;
|
||||
break;
|
||||
}
|
||||
pCur->a2 = deltaGetInt(&z, &i);
|
||||
pCur->eOp = DELTAPARSE_OP_COPY;
|
||||
pCur->iNext = (int)(&z[1] - pCur->aDelta);
|
||||
@@ -938,12 +926,8 @@ static int deltaparsevtabColumn(
|
||||
if( pCur->eOp==DELTAPARSE_OP_COPY ){
|
||||
sqlite3_result_int(ctx, pCur->a2);
|
||||
}else if( pCur->eOp==DELTAPARSE_OP_INSERT ){
|
||||
if( pCur->a2 + pCur->a1 > pCur->nDelta ){
|
||||
sqlite3_result_zeroblob(ctx, pCur->a1);
|
||||
}else{
|
||||
sqlite3_result_blob(ctx, pCur->aDelta+pCur->a2, pCur->a1,
|
||||
SQLITE_TRANSIENT);
|
||||
}
|
||||
sqlite3_result_blob(ctx, pCur->aDelta+pCur->a2, pCur->a1,
|
||||
SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -971,17 +955,17 @@ static int deltaparsevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
*/
|
||||
static int deltaparsevtabEof(sqlite3_vtab_cursor *cur){
|
||||
deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur;
|
||||
return pCur->eOp==DELTAPARSE_OP_EOF || pCur->iCursor>=pCur->nDelta;
|
||||
return pCur->eOp==DELTAPARSE_OP_EOF;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the deltaparsevtab_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
** once prior to any call to deltaparsevtabColumn() or deltaparsevtabRowid() or
|
||||
** once prior to any call to deltaparsevtabColumn() or deltaparsevtabRowid() or
|
||||
** deltaparsevtabEof().
|
||||
*/
|
||||
static int deltaparsevtabFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
@@ -1047,7 +1031,7 @@ static int deltaparsevtabBestIndex(
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** This following structure defines all the methods for the
|
||||
** virtual table.
|
||||
*/
|
||||
static sqlite3_module deltaparsevtabModule = {
|
||||
@@ -1084,8 +1068,8 @@ static sqlite3_module deltaparsevtabModule = {
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_fossildelta_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
static const int enc = SQLITE_UTF8|SQLITE_INNOCUOUS;
|
||||
|
||||
+3
-3
@@ -556,7 +556,7 @@ static int fuzzerConnect(
|
||||
static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
|
||||
fuzzer_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->pVtab = p;
|
||||
@@ -617,12 +617,12 @@ static int fuzzerRender(
|
||||
int *pnBuf /* Size of the buffer */
|
||||
){
|
||||
const fuzzer_rule *pRule = pStem->pRule;
|
||||
sqlite3_int64 n; /* Size of output term without nul-term */
|
||||
int n; /* Size of output term without nul-term */
|
||||
char *z; /* Buffer to assemble output term in */
|
||||
|
||||
n = pStem->nBasis + pRule->nTo - pRule->nFrom;
|
||||
if( (*pnBuf)<n+1 ){
|
||||
(*pzBuf) = sqlite3_realloc64((*pzBuf), n+100);
|
||||
(*pzBuf) = sqlite3_realloc((*pzBuf), n+100);
|
||||
if( (*pzBuf)==0 ) return SQLITE_NOMEM;
|
||||
(*pnBuf) = n+100;
|
||||
}
|
||||
|
||||
+1
-38
@@ -134,9 +134,6 @@ static void ieee754func(
|
||||
if( a==0 ){
|
||||
e = 0;
|
||||
m = 0;
|
||||
}else if( a==(sqlite3_int64)0x8000000000000000LL ){
|
||||
e = -1996;
|
||||
m = -1;
|
||||
}else{
|
||||
e = a>>52;
|
||||
m = a & ((((sqlite3_int64)1)<<52)-1);
|
||||
@@ -179,9 +176,9 @@ static void ieee754func(
|
||||
}
|
||||
|
||||
if( m<0 ){
|
||||
if( m<(-9223372036854775807LL) ) return;
|
||||
isNeg = 1;
|
||||
m = -m;
|
||||
if( m<0 ) return;
|
||||
}else if( m==0 && e>-1000 && e<1000 ){
|
||||
sqlite3_result_double(context, 0.0);
|
||||
return;
|
||||
@@ -259,38 +256,6 @@ static void ieee754func_to_blob(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Functions to convert between 64-bit integers and floats.
|
||||
**
|
||||
** The bit patterns are copied. The numeric values are different.
|
||||
*/
|
||||
static void ieee754func_from_int(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
|
||||
double r;
|
||||
sqlite3_int64 v = sqlite3_value_int64(argv[0]);
|
||||
memcpy(&r, &v, sizeof(r));
|
||||
sqlite3_result_double(context, r);
|
||||
}
|
||||
}
|
||||
static void ieee754func_to_int(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_FLOAT ){
|
||||
double r = sqlite3_value_double(argv[0]);
|
||||
sqlite3_uint64 v;
|
||||
memcpy(&v, &r, sizeof(v));
|
||||
sqlite3_result_int64(context, v);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL Function: ieee754_inc(r,N)
|
||||
**
|
||||
@@ -343,8 +308,6 @@ int sqlite3_ieee_init(
|
||||
{ "ieee754_exponent", 1, 2, ieee754func },
|
||||
{ "ieee754_to_blob", 1, 0, ieee754func_to_blob },
|
||||
{ "ieee754_from_blob", 1, 0, ieee754func_from_blob },
|
||||
{ "ieee754_to_int", 1, 0, ieee754func_to_int },
|
||||
{ "ieee754_from_int", 1, 0, ieee754func_from_int },
|
||||
{ "ieee754_inc", 2, 0, ieee754inc },
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ static int memstatConnect(
|
||||
|
||||
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -107,7 +107,7 @@ static int memstatDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
memstat_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->db = ((memstat_vtab*)p)->db;
|
||||
|
||||
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
** 2016-09-07
|
||||
**
|
||||
** 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 is an in-memory VFS implementation. The application supplies
|
||||
** a chunk of memory to hold the database file.
|
||||
**
|
||||
** 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&max=65536", &db,
|
||||
** SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI,
|
||||
** "memvfs");
|
||||
**
|
||||
** 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
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
/*
|
||||
** Forward declaration of objects used by this utility
|
||||
*/
|
||||
typedef struct sqlite3_vfs MemVfs;
|
||||
typedef struct MemFile MemFile;
|
||||
|
||||
/* Access to a lower-level VFS that (might) implement dynamic loading,
|
||||
** access to randomness, etc.
|
||||
*/
|
||||
#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
|
||||
|
||||
/* An open file */
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
** Methods for MemFile
|
||||
*/
|
||||
static int memClose(sqlite3_file*);
|
||||
static int memRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int memWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
|
||||
static int memTruncate(sqlite3_file*, sqlite3_int64 size);
|
||||
static int memSync(sqlite3_file*, int flags);
|
||||
static int memFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
||||
static int memLock(sqlite3_file*, int);
|
||||
static int memUnlock(sqlite3_file*, int);
|
||||
static int memCheckReservedLock(sqlite3_file*, int *pResOut);
|
||||
static int memFileControl(sqlite3_file*, int op, void *pArg);
|
||||
static int memSectorSize(sqlite3_file*);
|
||||
static int memDeviceCharacteristics(sqlite3_file*);
|
||||
static int memShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
|
||||
static int memShmLock(sqlite3_file*, int offset, int n, int flags);
|
||||
static void memShmBarrier(sqlite3_file*);
|
||||
static int memShmUnmap(sqlite3_file*, int deleteFlag);
|
||||
static int memFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
|
||||
static int memUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
|
||||
|
||||
/*
|
||||
** Methods for MemVfs
|
||||
*/
|
||||
static int memOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
||||
static int memDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
||||
static int memAccess(sqlite3_vfs*, const char *zName, int flags, int *);
|
||||
static int memFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
|
||||
static void *memDlOpen(sqlite3_vfs*, const char *zFilename);
|
||||
static void memDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
|
||||
static void (*memDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
|
||||
static void memDlClose(sqlite3_vfs*, void*);
|
||||
static int memRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
||||
static int memSleep(sqlite3_vfs*, int microseconds);
|
||||
static int memCurrentTime(sqlite3_vfs*, double*);
|
||||
static int memGetLastError(sqlite3_vfs*, int, char *);
|
||||
static int memCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
||||
|
||||
static sqlite3_vfs mem_vfs = {
|
||||
2, /* iVersion */
|
||||
0, /* szOsFile (set when registered) */
|
||||
1024, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"memvfs", /* zName */
|
||||
0, /* pAppData (set when registered) */
|
||||
memOpen, /* xOpen */
|
||||
memDelete, /* xDelete */
|
||||
memAccess, /* xAccess */
|
||||
memFullPathname, /* xFullPathname */
|
||||
memDlOpen, /* xDlOpen */
|
||||
memDlError, /* xDlError */
|
||||
memDlSym, /* xDlSym */
|
||||
memDlClose, /* xDlClose */
|
||||
memRandomness, /* xRandomness */
|
||||
memSleep, /* xSleep */
|
||||
memCurrentTime, /* xCurrentTime */
|
||||
memGetLastError, /* xGetLastError */
|
||||
memCurrentTimeInt64 /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
static const sqlite3_io_methods mem_io_methods = {
|
||||
3, /* iVersion */
|
||||
memClose, /* xClose */
|
||||
memRead, /* xRead */
|
||||
memWrite, /* xWrite */
|
||||
memTruncate, /* xTruncate */
|
||||
memSync, /* xSync */
|
||||
memFileSize, /* xFileSize */
|
||||
memLock, /* xLock */
|
||||
memUnlock, /* xUnlock */
|
||||
memCheckReservedLock, /* xCheckReservedLock */
|
||||
memFileControl, /* xFileControl */
|
||||
memSectorSize, /* xSectorSize */
|
||||
memDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
memShmMap, /* xShmMap */
|
||||
memShmLock, /* xShmLock */
|
||||
memShmBarrier, /* xShmBarrier */
|
||||
memShmUnmap, /* xShmUnmap */
|
||||
memFetch, /* xFetch */
|
||||
memUnfetch /* xUnfetch */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Close an mem-file.
|
||||
**
|
||||
** The pData pointer is owned by the application, so there is nothing
|
||||
** to free.
|
||||
*/
|
||||
static int memClose(sqlite3_file *pFile){
|
||||
MemFile *p = (MemFile *)pFile;
|
||||
if( p->bFreeOnClose ) sqlite3_free(p->aData);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from an mem-file.
|
||||
*/
|
||||
static int memRead(
|
||||
sqlite3_file *pFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
MemFile *p = (MemFile *)pFile;
|
||||
memcpy(zBuf, p->aData+iOfst, iAmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to an mem-file.
|
||||
*/
|
||||
static int memWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *z,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
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){
|
||||
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_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current file-size of an mem-file.
|
||||
*/
|
||||
static int memFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
MemFile *p = (MemFile *)pFile;
|
||||
*pSize = p->sz;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock an mem-file.
|
||||
*/
|
||||
static int memLock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock an mem-file.
|
||||
*/
|
||||
static int memUnlock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if another file-handle holds a RESERVED lock on an mem-file.
|
||||
*/
|
||||
static int memCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
*pResOut = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** File control method. For custom operations on an mem-file.
|
||||
*/
|
||||
static int memFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
MemFile *p = (MemFile *)pFile;
|
||||
int rc = SQLITE_NOTFOUND;
|
||||
if( op==SQLITE_FCNTL_VFSNAME ){
|
||||
*(char**)pArg = sqlite3_mprintf("mem(%p,%lld)", p->aData, p->sz);
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector-size in bytes for an mem-file.
|
||||
*/
|
||||
static int memSectorSize(sqlite3_file *pFile){
|
||||
return 1024;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the device characteristic flags supported by an mem-file.
|
||||
*/
|
||||
static int memDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return SQLITE_IOCAP_ATOMIC |
|
||||
SQLITE_IOCAP_POWERSAFE_OVERWRITE |
|
||||
SQLITE_IOCAP_SAFE_APPEND |
|
||||
SQLITE_IOCAP_SEQUENTIAL;
|
||||
}
|
||||
|
||||
/* Create a shared memory file mapping */
|
||||
static int memShmMap(
|
||||
sqlite3_file *pFile,
|
||||
int iPg,
|
||||
int pgsz,
|
||||
int bExtend,
|
||||
void volatile **pp
|
||||
){
|
||||
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_IOERR_SHMLOCK;
|
||||
}
|
||||
|
||||
/* Memory barrier operation on shared memory */
|
||||
static void memShmBarrier(sqlite3_file *pFile){
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unmap a shared memory segment */
|
||||
static int memShmUnmap(sqlite3_file *pFile, int deleteFlag){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Fetch a page of a memory-mapped file */
|
||||
static int memFetch(
|
||||
sqlite3_file *pFile,
|
||||
sqlite3_int64 iOfst,
|
||||
int iAmt,
|
||||
void **pp
|
||||
){
|
||||
MemFile *p = (MemFile *)pFile;
|
||||
*pp = (void*)(p->aData + iOfst);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Release a memory-mapped page */
|
||||
static int memUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open an mem file handle.
|
||||
*/
|
||||
static int memOpen(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_file *pFile,
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
MemFile *p = (MemFile*)pFile;
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( (flags & SQLITE_OPEN_MAIN_DB)==0 ) return SQLITE_CANTOPEN;
|
||||
p->aData = (unsigned char*)sqlite3_uri_int64(zName,"ptr",0);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the file located at zPath. If the dirSync argument is true,
|
||||
** ensure the file-system modifications are synced to disk before
|
||||
** returning.
|
||||
*/
|
||||
static int memDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
return SQLITE_IOERR_DELETE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Test for access permissions. Return true if the requested permission
|
||||
** is available, or false otherwise.
|
||||
*/
|
||||
static int memAccess(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int flags,
|
||||
int *pResOut
|
||||
){
|
||||
*pResOut = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate buffer zOut with the full canonical pathname corresponding
|
||||
** to the pathname in zPath. zOut is guaranteed to point to a buffer
|
||||
** of at least (INST_MAX_PATHNAME+1) bytes.
|
||||
*/
|
||||
static int memFullPathname(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int nOut,
|
||||
char *zOut
|
||||
){
|
||||
sqlite3_snprintf(nOut, zOut, "%s", zPath);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open the dynamic library located at zPath and return a handle.
|
||||
*/
|
||||
static void *memDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
||||
return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
|
||||
** utf-8 string describing the most recent error encountered associated
|
||||
** with dynamic libraries.
|
||||
*/
|
||||
static void memDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
||||
ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
|
||||
*/
|
||||
static void (*memDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
|
||||
return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the dynamic library handle pHandle.
|
||||
*/
|
||||
static void memDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate the buffer pointed to by zBufOut with nByte bytes of
|
||||
** random data.
|
||||
*/
|
||||
static int memRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Sleep for nMicro microseconds. Return the number of microseconds
|
||||
** actually slept.
|
||||
*/
|
||||
static int memSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current time as a Julian Day number in *pTimeOut.
|
||||
*/
|
||||
static int memCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
|
||||
}
|
||||
|
||||
static int memGetLastError(sqlite3_vfs *pVfs, int a, char *b){
|
||||
return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
|
||||
}
|
||||
static int memCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
|
||||
return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
|
||||
}
|
||||
|
||||
#ifdef MEMVFS_TEST
|
||||
/*
|
||||
** 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 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 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 *zUri;
|
||||
|
||||
if( zFilename==0 ) return;
|
||||
in = fopen(zFilename, "rb");
|
||||
if( in==0 ) return;
|
||||
fseek(in, 0, SEEK_END);
|
||||
szMax = sz = ftell(in);
|
||||
rewind(in);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
fread(p, sz, 1, in);
|
||||
fclose(in);
|
||||
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,
|
||||
char **pzErrMsg,
|
||||
const struct sqlite3_api_routines *pThunk
|
||||
){
|
||||
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 */
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
/*
|
||||
** This routine is called when the extension is loaded.
|
||||
** Register the new VFS.
|
||||
*/
|
||||
int sqlite3_memvfs_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
mem_vfs.pAppData = sqlite3_vfs_find(0);
|
||||
if( mem_vfs.pAppData==0 ) return SQLITE_ERROR;
|
||||
mem_vfs.szOsFile = sizeof(MemFile);
|
||||
rc = sqlite3_vfs_register(&mem_vfs, 1);
|
||||
#ifdef MEMVFS_TEST
|
||||
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;
|
||||
}
|
||||
@@ -297,9 +297,8 @@ static const unsigned char sqlite3CtypeMap[256] = {
|
||||
** Return the length (in bytes) of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
*/
|
||||
static sqlite3_int64 sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
sqlite3_int64 i;
|
||||
int c;
|
||||
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. */
|
||||
@@ -560,7 +559,7 @@ char *sqlite3_normalize(const char *zSql){
|
||||
int i; /* Next character to read from zSql[] */
|
||||
int j; /* Next slot to fill in on z[] */
|
||||
int tokenType; /* Type of the next token */
|
||||
sqlite3_int64 n; /* Size of the next token */
|
||||
int n; /* Size of the next token */
|
||||
int k; /* Loop counter */
|
||||
|
||||
nSql = strlen(zSql);
|
||||
|
||||
+2
-2
@@ -75,7 +75,7 @@ static int prefixesConnect(
|
||||
"CREATE TABLE prefixes(prefix TEXT, original_string TEXT HIDDEN)"
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -98,7 +98,7 @@ static int prefixesDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int prefixesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
prefixes_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
|
||||
+2
-2
@@ -152,7 +152,7 @@ static int qpvtabConnect(
|
||||
#define QPVTAB_FLAGS 11
|
||||
#define QPVTAB_NONE 12
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -174,7 +174,7 @@ static int qpvtabDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int qpvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
qpvtab_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
|
||||
+47
-93
@@ -32,7 +32,7 @@
|
||||
** ^X X occurring at the beginning of the string
|
||||
** X$ X occurring at the end of the string
|
||||
** . Match any single character
|
||||
** \c Character c where c is one of \{}()[]|*+?-.
|
||||
** \c Character c where c is one of \{}()[]|*+?.
|
||||
** \c C-language escapes for c in afnrtv. ex: \t or \n
|
||||
** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
|
||||
** \xXX Where XX is exactly 2 hex digits, unicode value XX
|
||||
@@ -55,8 +55,6 @@
|
||||
** to p copies of X following by q-p copies of X? and that the size of the
|
||||
** regular expression in the O(N*M) performance bound is computed after
|
||||
** this expansion.
|
||||
**
|
||||
** To help prevent DoS attacks, the maximum size of the NFA is restricted.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -98,6 +96,32 @@ SQLITE_EXTENSION_INIT1
|
||||
#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */
|
||||
#define RE_OP_ATSTART 18 /* Currently at the start of the string */
|
||||
|
||||
#if defined(SQLITE_DEBUG)
|
||||
/* Opcode names used for symbolic debugging */
|
||||
static const char *ReOpName[] = {
|
||||
"EOF",
|
||||
"MATCH",
|
||||
"ANY",
|
||||
"ANYSTAR",
|
||||
"FORK",
|
||||
"GOTO",
|
||||
"ACCEPT",
|
||||
"CC_INC",
|
||||
"CC_EXC",
|
||||
"CC_VALUE",
|
||||
"CC_RANGE",
|
||||
"WORD",
|
||||
"NOTWORD",
|
||||
"DIGIT",
|
||||
"NOTDIGIT",
|
||||
"SPACE",
|
||||
"NOTSPACE",
|
||||
"BOUNDARY",
|
||||
"ATSTART",
|
||||
};
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
|
||||
/* Each opcode is a "state" in the NFA */
|
||||
typedef unsigned short ReStateNumber;
|
||||
|
||||
@@ -134,7 +158,6 @@ struct ReCompiled {
|
||||
int nInit; /* Number of bytes in zInit */
|
||||
unsigned nState; /* Number of entries in aOp[] and aArg[] */
|
||||
unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
|
||||
unsigned mxAlloc; /* Complexity limit */
|
||||
};
|
||||
|
||||
/* Add a state to the given state set if it is not already there */
|
||||
@@ -349,15 +372,14 @@ re_match_end:
|
||||
|
||||
/* Resize the opcode and argument arrays for an RE under construction.
|
||||
*/
|
||||
static int re_resize(ReCompiled *p, unsigned int N){
|
||||
static int re_resize(ReCompiled *p, int N){
|
||||
char *aOp;
|
||||
int *aArg;
|
||||
if( N>p->mxAlloc ){ p->zErr = "REGEXP pattern too big"; return 1; }
|
||||
aOp = sqlite3_realloc64(p->aOp, N*sizeof(p->aOp[0]));
|
||||
if( aOp==0 ){ p->zErr = "out of memory"; return 1; }
|
||||
if( aOp==0 ) return 1;
|
||||
p->aOp = aOp;
|
||||
aArg = sqlite3_realloc64(p->aArg, N*sizeof(p->aArg[0]));
|
||||
if( aArg==0 ){ p->zErr = "out of memory"; return 1; }
|
||||
if( aArg==0 ) return 1;
|
||||
p->aArg = aArg;
|
||||
p->nAlloc = N;
|
||||
return 0;
|
||||
@@ -388,7 +410,7 @@ static int re_append(ReCompiled *p, int op, int arg){
|
||||
/* Make a copy of N opcodes starting at iStart onto the end of the RE
|
||||
** under construction.
|
||||
*/
|
||||
static void re_copy(ReCompiled *p, int iStart, unsigned int N){
|
||||
static void re_copy(ReCompiled *p, int iStart, int N){
|
||||
if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return;
|
||||
memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0]));
|
||||
memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0]));
|
||||
@@ -417,7 +439,7 @@ static int re_hex(int c, int *pV){
|
||||
** return its interpretation.
|
||||
*/
|
||||
static unsigned re_esc_char(ReCompiled *p){
|
||||
static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]-";
|
||||
static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
|
||||
static const char zTrans[] = "\a\f\n\r\t\v";
|
||||
int i, v = 0;
|
||||
char c;
|
||||
@@ -541,26 +563,18 @@ static const char *re_subcompile_string(ReCompiled *p){
|
||||
break;
|
||||
}
|
||||
case '{': {
|
||||
unsigned int m = 0, n = 0;
|
||||
unsigned int sz, j;
|
||||
int m = 0, n = 0;
|
||||
int sz, j;
|
||||
if( iPrev<0 ) return "'{m,n}' without operand";
|
||||
while( (c=rePeek(p))>='0' && c<='9' ){
|
||||
m = m*10 + c - '0';
|
||||
if( m*2>p->mxAlloc ) return "REGEXP pattern too big";
|
||||
p->sIn.i++;
|
||||
}
|
||||
while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; }
|
||||
n = m;
|
||||
if( c==',' ){
|
||||
p->sIn.i++;
|
||||
n = 0;
|
||||
while( (c=rePeek(p))>='0' && c<='9' ){
|
||||
n = n*10 + c-'0';
|
||||
if( n*2>p->mxAlloc ) return "REGEXP pattern too big";
|
||||
p->sIn.i++;
|
||||
}
|
||||
while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; }
|
||||
}
|
||||
if( c!='}' ) return "unmatched '{'";
|
||||
if( n<m ) return "n less than m in '{m,n}'";
|
||||
if( n>0 && n<m ) return "n less than m in '{m,n}'";
|
||||
p->sIn.i++;
|
||||
sz = p->nState - iPrev;
|
||||
if( m==0 ){
|
||||
@@ -576,7 +590,7 @@ static const char *re_subcompile_string(ReCompiled *p){
|
||||
re_copy(p, iPrev, sz);
|
||||
}
|
||||
if( n==0 && m>0 ){
|
||||
re_append(p, RE_OP_FORK, -(int)sz);
|
||||
re_append(p, RE_OP_FORK, -sz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -642,7 +656,8 @@ static const char *re_subcompile_string(ReCompiled *p){
|
||||
** regular expression. Applications should invoke this routine once
|
||||
** for every call to re_compile() to avoid memory leaks.
|
||||
*/
|
||||
static void re_free(ReCompiled *pRe){
|
||||
static void re_free(void *p){
|
||||
ReCompiled *pRe = (ReCompiled*)p;
|
||||
if( pRe ){
|
||||
sqlite3_free(pRe->aOp);
|
||||
sqlite3_free(pRe->aArg);
|
||||
@@ -650,43 +665,27 @@ static void re_free(ReCompiled *pRe){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Version of re_free() that accepts a pointer of type (void*). Required
|
||||
** to satisfy sanitizers when the re_free() function is called via a
|
||||
** function pointer.
|
||||
*/
|
||||
static void re_free_voidptr(void *p){
|
||||
re_free((ReCompiled*)p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compile a textual regular expression in zIn[] into a compiled regular
|
||||
** expression suitable for us by re_match() and return a pointer to the
|
||||
** compiled regular expression in *ppRe. Return NULL on success or an
|
||||
** error message if something goes wrong.
|
||||
*/
|
||||
static const char *re_compile(
|
||||
ReCompiled **ppRe, /* OUT: write compiled NFA here */
|
||||
const char *zIn, /* Input regular expression */
|
||||
int mxRe, /* Complexity limit */
|
||||
int noCase /* True for caseless comparisons */
|
||||
){
|
||||
static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
|
||||
ReCompiled *pRe;
|
||||
const char *zErr;
|
||||
int i, j;
|
||||
|
||||
*ppRe = 0;
|
||||
pRe = sqlite3_malloc64( sizeof(*pRe) );
|
||||
pRe = sqlite3_malloc( sizeof(*pRe) );
|
||||
if( pRe==0 ){
|
||||
return "out of memory";
|
||||
}
|
||||
memset(pRe, 0, sizeof(*pRe));
|
||||
pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char;
|
||||
pRe->mxAlloc = mxRe;
|
||||
if( re_resize(pRe, 30) ){
|
||||
zErr = pRe->zErr;
|
||||
re_free(pRe);
|
||||
return zErr;
|
||||
return "out of memory";
|
||||
}
|
||||
if( zIn[0]=='^' ){
|
||||
zIn++;
|
||||
@@ -739,21 +738,6 @@ static const char *re_compile(
|
||||
return pRe->zErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** The value of LIMIT_MAX_PATTERN_LENGTH.
|
||||
*/
|
||||
static int re_maxlen(sqlite3_context *context){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
return sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH,-1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Maximum NFA size given a maximum pattern length.
|
||||
*/
|
||||
static int re_maxnfa(int mxlen){
|
||||
return 75+mxlen/2;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the regexp() SQL function. This function implements
|
||||
** the build-in REGEXP operator. The first argument to the function is the
|
||||
@@ -777,17 +761,9 @@ static void re_sql_func(
|
||||
(void)argc; /* Unused */
|
||||
pRe = sqlite3_get_auxdata(context, 0);
|
||||
if( pRe==0 ){
|
||||
int mxLen = re_maxlen(context);
|
||||
int nPattern;
|
||||
zPattern = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zPattern==0 ) return;
|
||||
nPattern = sqlite3_value_bytes(argv[0]);
|
||||
if( nPattern>mxLen ){
|
||||
zErr = "REGEXP pattern too big";
|
||||
}else{
|
||||
zErr = re_compile(&pRe, zPattern, re_maxnfa(mxLen),
|
||||
sqlite3_user_data(context)!=0);
|
||||
}
|
||||
zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0);
|
||||
if( zErr ){
|
||||
re_free(pRe);
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
@@ -804,7 +780,7 @@ static void re_sql_func(
|
||||
sqlite3_result_int(context, re_match(pRe, zStr, -1));
|
||||
}
|
||||
if( setAux ){
|
||||
sqlite3_set_auxdata(context, 0, pRe, re_free_voidptr);
|
||||
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,33 +804,11 @@ static void re_bytecode_func(
|
||||
int i;
|
||||
int n;
|
||||
char *z;
|
||||
static const char *ReOpName[] = {
|
||||
"EOF",
|
||||
"MATCH",
|
||||
"ANY",
|
||||
"ANYSTAR",
|
||||
"FORK",
|
||||
"GOTO",
|
||||
"ACCEPT",
|
||||
"CC_INC",
|
||||
"CC_EXC",
|
||||
"CC_VALUE",
|
||||
"CC_RANGE",
|
||||
"WORD",
|
||||
"NOTWORD",
|
||||
"DIGIT",
|
||||
"NOTDIGIT",
|
||||
"SPACE",
|
||||
"NOTSPACE",
|
||||
"BOUNDARY",
|
||||
"ATSTART",
|
||||
};
|
||||
|
||||
(void)argc;
|
||||
|
||||
zPattern = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zPattern==0 ) return;
|
||||
zErr = re_compile(&pRe, zPattern, re_maxnfa(re_maxlen(context)),
|
||||
sqlite3_user_data(context)!=0);
|
||||
zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0);
|
||||
if( zErr ){
|
||||
re_free(pRe);
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ static void scrubBackupErr(ScrubState *p, const char *zFormat, ...){
|
||||
static u8 *scrubBackupAllocPage(ScrubState *p){
|
||||
u8 *pPage;
|
||||
if( p->rcErr ) return 0;
|
||||
pPage = sqlite3_malloc64( p->szPage );
|
||||
pPage = sqlite3_malloc( p->szPage );
|
||||
if( pPage==0 ) p->rcErr = SQLITE_NOMEM;
|
||||
return pPage;
|
||||
}
|
||||
|
||||
+232
-301
@@ -30,20 +30,19 @@
|
||||
** SELECT * FROM generate_series(0,100,5);
|
||||
**
|
||||
** The query above returns integers from 0 through 100 counting by steps
|
||||
** of 5. In other words, 0, 5, 10, 15, ..., 90, 95, 100. There are a total
|
||||
** of 21 rows.
|
||||
** of 5.
|
||||
**
|
||||
** SELECT * FROM generate_series(0,100);
|
||||
**
|
||||
** Integers from 0 through 100 with a step size of 1. 101 rows.
|
||||
** Integers from 0 through 100 with a step size of 1.
|
||||
**
|
||||
** SELECT * FROM generate_series(20) LIMIT 10;
|
||||
**
|
||||
** Integers 20 through 29. 10 rows.
|
||||
** Integers 20 through 29.
|
||||
**
|
||||
** SELECT * FROM generate_series(0,-100,-5);
|
||||
**
|
||||
** Integers 0 -5 -10 ... -100. 21 rows.
|
||||
** Integers 0 -5 -10 ... -100.
|
||||
**
|
||||
** SELECT * FROM generate_series(0,-1);
|
||||
**
|
||||
@@ -119,89 +118,140 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <math.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Return that member of a generate_series(...) sequence whose 0-based
|
||||
** index is ix. The 0th member is given by smBase. The sequence members
|
||||
** progress per ix increment by smStep.
|
||||
*/
|
||||
static sqlite3_int64 genSeqMember(
|
||||
sqlite3_int64 smBase,
|
||||
sqlite3_int64 smStep,
|
||||
sqlite3_uint64 ix
|
||||
){
|
||||
static const sqlite3_uint64 mxI64 =
|
||||
((sqlite3_uint64)0x7fffffff)<<32 | 0xffffffff;
|
||||
if( ix>=mxI64 ){
|
||||
/* Get ix into signed i64 range. */
|
||||
ix -= mxI64;
|
||||
/* With 2's complement ALU, this next can be 1 step, but is split into
|
||||
* 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */
|
||||
smBase += (mxI64/2) * smStep;
|
||||
smBase += (mxI64 - mxI64/2) * smStep;
|
||||
}
|
||||
/* Under UBSAN (or on 1's complement machines), must do this last term
|
||||
* in steps to avoid the dreaded (and harmless) signed multiply overflow. */
|
||||
if( ix>=2 ){
|
||||
sqlite3_int64 ix2 = (sqlite3_int64)ix/2;
|
||||
smBase += ix2*smStep;
|
||||
ix -= ix2;
|
||||
}
|
||||
return smBase + ((sqlite3_int64)ix)*smStep;
|
||||
}
|
||||
|
||||
typedef unsigned char u8;
|
||||
|
||||
typedef struct SequenceSpec {
|
||||
sqlite3_int64 iOBase; /* Original starting value ("start") */
|
||||
sqlite3_int64 iOTerm; /* Original terminal value ("stop") */
|
||||
sqlite3_int64 iBase; /* Starting value to actually use */
|
||||
sqlite3_int64 iTerm; /* Terminal value to actually use */
|
||||
sqlite3_int64 iStep; /* Increment ("step") */
|
||||
sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
|
||||
sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
|
||||
sqlite3_int64 iValueNow; /* Current value during generation */
|
||||
u8 isNotEOF; /* Sequence generation not exhausted */
|
||||
u8 isReversing; /* Sequence is being reverse generated */
|
||||
} SequenceSpec;
|
||||
|
||||
/*
|
||||
** Prepare a SequenceSpec for use in generating an integer series
|
||||
** given initialized iBase, iTerm and iStep values. Sequence is
|
||||
** initialized per given isReversing. Other members are computed.
|
||||
*/
|
||||
static void setupSequence( SequenceSpec *pss ){
|
||||
int bSameSigns;
|
||||
pss->uSeqIndexMax = 0;
|
||||
pss->isNotEOF = 0;
|
||||
bSameSigns = (pss->iBase < 0)==(pss->iTerm < 0);
|
||||
if( pss->iTerm < pss->iBase ){
|
||||
sqlite3_uint64 nuspan = 0;
|
||||
if( bSameSigns ){
|
||||
nuspan = (sqlite3_uint64)(pss->iBase - pss->iTerm);
|
||||
}else{
|
||||
/* Under UBSAN (or on 1's complement machines), must do this in steps.
|
||||
* In this clause, iBase>=0 and iTerm<0 . */
|
||||
nuspan = 1;
|
||||
nuspan += pss->iBase;
|
||||
nuspan += -(pss->iTerm+1);
|
||||
}
|
||||
if( pss->iStep<0 ){
|
||||
pss->isNotEOF = 1;
|
||||
if( nuspan==ULONG_MAX ){
|
||||
pss->uSeqIndexMax = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1;
|
||||
}else if( pss->iStep>LLONG_MIN ){
|
||||
pss->uSeqIndexMax = nuspan/-pss->iStep;
|
||||
}
|
||||
}
|
||||
}else if( pss->iTerm > pss->iBase ){
|
||||
sqlite3_uint64 puspan = 0;
|
||||
if( bSameSigns ){
|
||||
puspan = (sqlite3_uint64)(pss->iTerm - pss->iBase);
|
||||
}else{
|
||||
/* Under UBSAN (or on 1's complement machines), must do this in steps.
|
||||
* In this clause, iTerm>=0 and iBase<0 . */
|
||||
puspan = 1;
|
||||
puspan += pss->iTerm;
|
||||
puspan += -(pss->iBase+1);
|
||||
}
|
||||
if( pss->iStep>0 ){
|
||||
pss->isNotEOF = 1;
|
||||
pss->uSeqIndexMax = puspan/pss->iStep;
|
||||
}
|
||||
}else if( pss->iTerm == pss->iBase ){
|
||||
pss->isNotEOF = 1;
|
||||
pss->uSeqIndexMax = 0;
|
||||
}
|
||||
pss->uSeqIndexNow = (pss->isReversing)? pss->uSeqIndexMax : 0;
|
||||
pss->iValueNow = (pss->isReversing)
|
||||
? genSeqMember(pss->iBase, pss->iStep, pss->uSeqIndexMax)
|
||||
: pss->iBase;
|
||||
}
|
||||
|
||||
/*
|
||||
** Progress sequence generator to yield next value, if any.
|
||||
** Leave its state to either yield next value or be at EOF.
|
||||
** Return whether there is a next value, or 0 at EOF.
|
||||
*/
|
||||
static int progressSequence( SequenceSpec *pss ){
|
||||
if( !pss->isNotEOF ) return 0;
|
||||
if( pss->isReversing ){
|
||||
if( pss->uSeqIndexNow > 0 ){
|
||||
pss->uSeqIndexNow--;
|
||||
pss->iValueNow -= pss->iStep;
|
||||
}else{
|
||||
pss->isNotEOF = 0;
|
||||
}
|
||||
}else{
|
||||
if( pss->uSeqIndexNow < pss->uSeqIndexMax ){
|
||||
pss->uSeqIndexNow++;
|
||||
pss->iValueNow += pss->iStep;
|
||||
}else{
|
||||
pss->isNotEOF = 0;
|
||||
}
|
||||
}
|
||||
return pss->isNotEOF;
|
||||
}
|
||||
|
||||
/* series_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result.
|
||||
**
|
||||
** iOBase, iOTerm, and iOStep are the original values of the
|
||||
** start=, stop=, and step= constraints on the query. These are
|
||||
** the values reported by the start, stop, and step columns of the
|
||||
** virtual table.
|
||||
**
|
||||
** iBase, iTerm, iStep, and bDescp are the actual values used to generate
|
||||
** the sequence. These might be different from the iOxxxx values.
|
||||
** For example in
|
||||
**
|
||||
** SELECT value FROM generate_series(1,11,2)
|
||||
** WHERE value BETWEEN 4 AND 8;
|
||||
**
|
||||
** The iOBase is 1, but the iBase is 5. iOTerm is 11 but iTerm is 7.
|
||||
** Another example:
|
||||
**
|
||||
** SELECT value FROM generate_series(1,15,3) ORDER BY value DESC;
|
||||
**
|
||||
** The cursor initialization for the above query is:
|
||||
**
|
||||
** iOBase = 1 iBase = 13
|
||||
** iOTerm = 15 iTerm = 1
|
||||
** iOStep = 3 iStep = 3 bDesc = 1
|
||||
**
|
||||
** The actual step size is unsigned so that can have a value of
|
||||
** +9223372036854775808 which is needed for querys like this:
|
||||
**
|
||||
** SELECT value
|
||||
** FROM generate_series(9223372036854775807,
|
||||
** -9223372036854775808,
|
||||
** -9223372036854775808)
|
||||
** ORDER BY value ASC;
|
||||
**
|
||||
** The setup for the previous query will be:
|
||||
**
|
||||
** iOBase = 9223372036854775807 iBase = -1
|
||||
** iOTerm = -9223372036854775808 iTerm = 9223372036854775807
|
||||
** iOStep = -9223372036854775808 iStep = 9223372036854775808 bDesc = 0
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef unsigned char u8;
|
||||
typedef struct series_cursor series_cursor;
|
||||
struct series_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_int64 iOBase; /* Original starting value ("start") */
|
||||
sqlite3_int64 iOTerm; /* Original terminal value ("stop") */
|
||||
sqlite3_int64 iOStep; /* Original step value */
|
||||
sqlite3_int64 iBase; /* Starting value to actually use */
|
||||
sqlite3_int64 iTerm; /* Terminal value to actually use */
|
||||
sqlite3_uint64 iStep; /* The step size */
|
||||
sqlite3_int64 iValue; /* Current value */
|
||||
u8 bDesc; /* iStep is really negative */
|
||||
u8 bDone; /* True if stepped past last element */
|
||||
SequenceSpec ss; /* (this) Derived class data */
|
||||
};
|
||||
|
||||
/*
|
||||
** Computed the difference between two 64-bit signed integers using a
|
||||
** convoluted computation designed to work around the silly restriction
|
||||
** against signed integer overflow in C.
|
||||
*/
|
||||
static sqlite3_uint64 span64(sqlite3_int64 a, sqlite3_int64 b){
|
||||
assert( a>=b );
|
||||
return (*(sqlite3_uint64*)&a) - (*(sqlite3_uint64*)&b);
|
||||
}
|
||||
|
||||
/*
|
||||
** Add or substract an unsigned 64-bit integer from a signed 64-bit integer
|
||||
** and return the new signed 64-bit integer.
|
||||
*/
|
||||
static sqlite3_int64 add64(sqlite3_int64 a, sqlite3_uint64 b){
|
||||
sqlite3_uint64 x = *(sqlite3_uint64*)&a;
|
||||
x += b;
|
||||
return *(sqlite3_int64*)&x;
|
||||
}
|
||||
static sqlite3_int64 sub64(sqlite3_int64 a, sqlite3_uint64 b){
|
||||
sqlite3_uint64 x = *(sqlite3_uint64*)&a;
|
||||
x -= b;
|
||||
return *(sqlite3_int64*)&x;
|
||||
}
|
||||
|
||||
/*
|
||||
** The seriesConnect() method is invoked to create a new
|
||||
** series_vtab that describes the generate_series virtual table.
|
||||
@@ -239,7 +289,7 @@ static int seriesConnect(
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
@@ -261,7 +311,7 @@ static int seriesDisconnect(sqlite3_vtab *pVtab){
|
||||
static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){
|
||||
series_cursor *pCur;
|
||||
(void)pUnused;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
@@ -282,15 +332,7 @@ static int seriesClose(sqlite3_vtab_cursor *cur){
|
||||
*/
|
||||
static int seriesNext(sqlite3_vtab_cursor *cur){
|
||||
series_cursor *pCur = (series_cursor*)cur;
|
||||
if( pCur->iValue==pCur->iTerm ){
|
||||
pCur->bDone = 1;
|
||||
}else if( pCur->bDesc ){
|
||||
pCur->iValue = sub64(pCur->iValue, pCur->iStep);
|
||||
assert( pCur->iValue>=pCur->iTerm );
|
||||
}else{
|
||||
pCur->iValue = add64(pCur->iValue, pCur->iStep);
|
||||
assert( pCur->iValue<=pCur->iTerm );
|
||||
}
|
||||
progressSequence( & pCur->ss );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -306,19 +348,19 @@ static int seriesColumn(
|
||||
series_cursor *pCur = (series_cursor*)cur;
|
||||
sqlite3_int64 x = 0;
|
||||
switch( i ){
|
||||
case SERIES_COLUMN_START: x = pCur->iOBase; break;
|
||||
case SERIES_COLUMN_STOP: x = pCur->iOTerm; break;
|
||||
case SERIES_COLUMN_STEP: x = pCur->iOStep; break;
|
||||
default: x = pCur->iValue; break;
|
||||
case SERIES_COLUMN_START: x = pCur->ss.iOBase; break;
|
||||
case SERIES_COLUMN_STOP: x = pCur->ss.iOTerm; break;
|
||||
case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
|
||||
default: x = pCur->ss.iValueNow; break;
|
||||
}
|
||||
sqlite3_result_int64(ctx, x);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef LARGEST_UINT64
|
||||
#define LARGEST_INT64 ((sqlite3_int64)0x7fffffffffffffffLL)
|
||||
#define LARGEST_UINT64 ((sqlite3_uint64)0xffffffffffffffffULL)
|
||||
#define SMALLEST_INT64 ((sqlite3_int64)0x8000000000000000LL)
|
||||
#define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
|
||||
#define LARGEST_UINT64 (0xffffffff|(((sqlite3_uint64)0xffffffff)<<32))
|
||||
#define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -326,7 +368,7 @@ static int seriesColumn(
|
||||
*/
|
||||
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
series_cursor *pCur = (series_cursor*)cur;
|
||||
*pRowid = pCur->iValue;
|
||||
*pRowid = pCur->ss.iValueNow;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -336,7 +378,7 @@ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
*/
|
||||
static int seriesEof(sqlite3_vtab_cursor *cur){
|
||||
series_cursor *pCur = (series_cursor*)cur;
|
||||
return pCur->bDone;
|
||||
return !pCur->ss.isNotEOF;
|
||||
}
|
||||
|
||||
/* True to cause run-time checking of the start=, stop=, and/or step=
|
||||
@@ -347,59 +389,6 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
|
||||
# define SQLITE_SERIES_CONSTRAINT_VERIFY 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the number of steps between pCur->iBase and pCur->iTerm if
|
||||
** the step width is pCur->iStep.
|
||||
*/
|
||||
static sqlite3_uint64 seriesSteps(series_cursor *pCur){
|
||||
if( pCur->bDesc ){
|
||||
assert( pCur->iBase >= pCur->iTerm );
|
||||
return span64(pCur->iBase, pCur->iTerm)/pCur->iStep;
|
||||
}else{
|
||||
assert( pCur->iBase <= pCur->iTerm );
|
||||
return span64(pCur->iTerm, pCur->iBase)/pCur->iStep;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_MATH_FUNCTIONS) || defined(_WIN32)
|
||||
/*
|
||||
** Case 1 (the most common case):
|
||||
** The standard math library is available so use ceil() and floor() from there.
|
||||
*/
|
||||
static double seriesCeil(double r){ return ceil(r); }
|
||||
static double seriesFloor(double r){ return floor(r); }
|
||||
#elif defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
/*
|
||||
** Case 2 (2nd most common): Use GCC/Clang builtins
|
||||
*/
|
||||
static double seriesCeil(double r){ return __builtin_ceil(r); }
|
||||
static double seriesFloor(double r){ return __builtin_floor(r); }
|
||||
#else
|
||||
/*
|
||||
** Case 3 (rarely happens): Use home-grown ceil() and floor() routines.
|
||||
*/
|
||||
static double seriesCeil(double r){
|
||||
sqlite3_int64 x;
|
||||
if( r!=r ) return r;
|
||||
if( r<=(-4503599627370496.0) ) return r;
|
||||
if( r>=(+4503599627370496.0) ) return r;
|
||||
x = (sqlite3_int64)r;
|
||||
if( r==(double)x ) return r;
|
||||
if( r>(double)x ) x++;
|
||||
return (double)x;
|
||||
}
|
||||
static double seriesFloor(double r){
|
||||
sqlite3_int64 x;
|
||||
if( r!=r ) return r;
|
||||
if( r<=(-4503599627370496.0) ) return r;
|
||||
if( r>=(+4503599627370496.0) ) return r;
|
||||
x = (sqlite3_int64)r;
|
||||
if( r==(double)x ) return r;
|
||||
if( r<(double)x ) x--;
|
||||
return (double)x;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the series_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
@@ -433,42 +422,33 @@ static int seriesFilter(
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
series_cursor *pCur = (series_cursor *)pVtabCursor;
|
||||
int iArg = 0; /* Arguments used so far */
|
||||
int i; /* Loop counter */
|
||||
sqlite3_int64 iMin = SMALLEST_INT64; /* Smallest allowed output value */
|
||||
sqlite3_int64 iMax = LARGEST_INT64; /* Largest allowed output value */
|
||||
sqlite3_int64 iLimit = 0; /* if >0, the value of the LIMIT */
|
||||
sqlite3_int64 iOffset = 0; /* if >0, the value of the OFFSET */
|
||||
int i = 0;
|
||||
int returnNoRows = 0;
|
||||
sqlite3_int64 iMin = SMALLEST_INT64;
|
||||
sqlite3_int64 iMax = LARGEST_INT64;
|
||||
sqlite3_int64 iLimit = 0;
|
||||
sqlite3_int64 iOffset = 0;
|
||||
|
||||
(void)idxStrUnused;
|
||||
|
||||
/* If any constraints have a NULL value, then return no rows.
|
||||
** See ticket https://sqlite.org/src/info/fac496b61722daf2
|
||||
*/
|
||||
for(i=0; i<argc; i++){
|
||||
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
|
||||
goto series_no_rows;
|
||||
}
|
||||
}
|
||||
|
||||
/* Capture the three HIDDEN parameters to the virtual table and insert
|
||||
** default values for any parameters that are omitted.
|
||||
*/
|
||||
if( idxNum & 0x01 ){
|
||||
pCur->iOBase = sqlite3_value_int64(argv[iArg++]);
|
||||
pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
|
||||
}else{
|
||||
pCur->iOBase = 0;
|
||||
pCur->ss.iBase = 0;
|
||||
}
|
||||
if( idxNum & 0x02 ){
|
||||
pCur->iOTerm = sqlite3_value_int64(argv[iArg++]);
|
||||
pCur->ss.iTerm = sqlite3_value_int64(argv[i++]);
|
||||
}else{
|
||||
pCur->iOTerm = 0xffffffff;
|
||||
pCur->ss.iTerm = 0xffffffff;
|
||||
}
|
||||
if( idxNum & 0x04 ){
|
||||
pCur->iOStep = sqlite3_value_int64(argv[iArg++]);
|
||||
if( pCur->iOStep==0 ) pCur->iOStep = 1;
|
||||
pCur->ss.iStep = sqlite3_value_int64(argv[i++]);
|
||||
if( pCur->ss.iStep==0 ){
|
||||
pCur->ss.iStep = 1;
|
||||
}else if( pCur->ss.iStep<0 ){
|
||||
if( (idxNum & 0x10)==0 ) idxNum |= 0x08;
|
||||
}
|
||||
}else{
|
||||
pCur->iOStep = 1;
|
||||
pCur->ss.iStep = 1;
|
||||
}
|
||||
|
||||
/* If there are constraints on the value column but there are
|
||||
@@ -478,94 +458,72 @@ static int seriesFilter(
|
||||
** further below.
|
||||
*/
|
||||
if( (idxNum & 0x05)==0 && (idxNum & 0x0380)!=0 ){
|
||||
pCur->iOBase = SMALLEST_INT64;
|
||||
pCur->ss.iBase = SMALLEST_INT64;
|
||||
}
|
||||
if( (idxNum & 0x06)==0 && (idxNum & 0x3080)!=0 ){
|
||||
pCur->iOTerm = LARGEST_INT64;
|
||||
}
|
||||
pCur->iBase = pCur->iOBase;
|
||||
pCur->iTerm = pCur->iOTerm;
|
||||
if( pCur->iOStep>0 ){
|
||||
pCur->iStep = pCur->iOStep;
|
||||
}else if( pCur->iOStep>SMALLEST_INT64 ){
|
||||
pCur->iStep = -pCur->iOStep;
|
||||
}else{
|
||||
pCur->iStep = LARGEST_INT64;
|
||||
pCur->iStep++;
|
||||
}
|
||||
pCur->bDesc = pCur->iOStep<0;
|
||||
if( pCur->bDesc==0 && pCur->iBase>pCur->iTerm ){
|
||||
goto series_no_rows;
|
||||
}
|
||||
if( pCur->bDesc!=0 && pCur->iBase<pCur->iTerm ){
|
||||
goto series_no_rows;
|
||||
pCur->ss.iTerm = LARGEST_INT64;
|
||||
}
|
||||
pCur->ss.iOBase = pCur->ss.iBase;
|
||||
pCur->ss.iOTerm = pCur->ss.iTerm;
|
||||
|
||||
/* Extract the LIMIT and OFFSET values, but do not apply them yet.
|
||||
** The range must first be constrained by the limits on value.
|
||||
*/
|
||||
if( idxNum & 0x20 ){
|
||||
iLimit = sqlite3_value_int64(argv[iArg++]);
|
||||
iLimit = sqlite3_value_int64(argv[i++]);
|
||||
if( idxNum & 0x40 ){
|
||||
iOffset = sqlite3_value_int64(argv[iArg++]);
|
||||
iOffset = sqlite3_value_int64(argv[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Narrow the range of iMin and iMax (the minimum and maximum outputs)
|
||||
** based on equality and inequality constraints on the "value" column.
|
||||
*/
|
||||
if( idxNum & 0x3380 ){
|
||||
if( idxNum & 0x0080 ){ /* value=X */
|
||||
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
|
||||
double r = sqlite3_value_double(argv[iArg++]);
|
||||
if( r==seriesCeil(r)
|
||||
&& r>=(double)SMALLEST_INT64
|
||||
&& r<=(double)LARGEST_INT64
|
||||
){
|
||||
/* Extract the maximum range of output values determined by
|
||||
** constraints on the "value" column.
|
||||
*/
|
||||
if( idxNum & 0x0080 ){
|
||||
if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
|
||||
double r = sqlite3_value_double(argv[i++]);
|
||||
if( r==ceil(r) ){
|
||||
iMin = iMax = (sqlite3_int64)r;
|
||||
}else{
|
||||
goto series_no_rows;
|
||||
returnNoRows = 1;
|
||||
}
|
||||
}else{
|
||||
iMin = iMax = sqlite3_value_int64(argv[iArg++]);
|
||||
iMin = iMax = sqlite3_value_int64(argv[i++]);
|
||||
}
|
||||
}else{
|
||||
if( idxNum & 0x0300 ){ /* value>X or value>=X */
|
||||
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
|
||||
double r = sqlite3_value_double(argv[iArg++]);
|
||||
if( r<(double)SMALLEST_INT64 ){
|
||||
iMin = SMALLEST_INT64;
|
||||
}else if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){
|
||||
iMin = (sqlite3_int64)seriesCeil(r+1.0);
|
||||
if( idxNum & 0x0300 ){
|
||||
if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
|
||||
double r = sqlite3_value_double(argv[i++]);
|
||||
if( idxNum & 0x0200 && r==ceil(r) ){
|
||||
iMin = (sqlite3_int64)ceil(r+1.0);
|
||||
}else{
|
||||
iMin = (sqlite3_int64)seriesCeil(r);
|
||||
iMin = (sqlite3_int64)ceil(r);
|
||||
}
|
||||
}else{
|
||||
iMin = sqlite3_value_int64(argv[iArg++]);
|
||||
if( (idxNum & 0x0200)!=0 ){
|
||||
iMin = sqlite3_value_int64(argv[i++]);
|
||||
if( idxNum & 0x0200 ){
|
||||
if( iMin==LARGEST_INT64 ){
|
||||
goto series_no_rows;
|
||||
returnNoRows = 1;
|
||||
}else{
|
||||
iMin++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( idxNum & 0x3000 ){ /* value<X or value<=X */
|
||||
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
|
||||
double r = sqlite3_value_double(argv[iArg++]);
|
||||
if( r>(double)LARGEST_INT64 ){
|
||||
iMax = LARGEST_INT64;
|
||||
}else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){
|
||||
if( idxNum & 0x3000 ){
|
||||
if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
|
||||
double r = sqlite3_value_double(argv[i++]);
|
||||
if( (idxNum & 0x2000)!=0 && r==floor(r) ){
|
||||
iMax = (sqlite3_int64)(r-1.0);
|
||||
}else{
|
||||
iMax = (sqlite3_int64)seriesFloor(r);
|
||||
iMax = (sqlite3_int64)floor(r);
|
||||
}
|
||||
}else{
|
||||
iMax = sqlite3_value_int64(argv[iArg++]);
|
||||
iMax = sqlite3_value_int64(argv[i++]);
|
||||
if( idxNum & 0x2000 ){
|
||||
if( iMax==SMALLEST_INT64 ){
|
||||
goto series_no_rows;
|
||||
returnNoRows = 1;
|
||||
}else{
|
||||
iMax--;
|
||||
}
|
||||
@@ -573,99 +531,72 @@ static int seriesFilter(
|
||||
}
|
||||
}
|
||||
if( iMin>iMax ){
|
||||
goto series_no_rows;
|
||||
returnNoRows = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to reduce the range of values to be generated based on
|
||||
** constraints on the "value" column.
|
||||
*/
|
||||
if( pCur->bDesc==0 ){
|
||||
if( pCur->iBase<iMin ){
|
||||
sqlite3_uint64 span = span64(iMin,pCur->iBase);
|
||||
pCur->iBase = add64(pCur->iBase, (span/pCur->iStep)*pCur->iStep);
|
||||
if( pCur->iBase<iMin ){
|
||||
if( pCur->iBase > sub64(LARGEST_INT64, pCur->iStep) ){
|
||||
goto series_no_rows;
|
||||
}
|
||||
pCur->iBase = add64(pCur->iBase, pCur->iStep);
|
||||
}
|
||||
if( pCur->ss.iStep>0 ){
|
||||
sqlite3_int64 szStep = pCur->ss.iStep;
|
||||
if( pCur->ss.iBase<iMin ){
|
||||
sqlite3_uint64 d = iMin - pCur->ss.iBase;
|
||||
pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
|
||||
}
|
||||
if( pCur->iTerm>iMax ){
|
||||
pCur->iTerm = iMax;
|
||||
if( pCur->ss.iTerm>iMax ){
|
||||
pCur->ss.iTerm = iMax;
|
||||
}
|
||||
}else{
|
||||
if( pCur->iBase>iMax ){
|
||||
sqlite3_uint64 span = span64(pCur->iBase,iMax);
|
||||
pCur->iBase = sub64(pCur->iBase, (span/pCur->iStep)*pCur->iStep);
|
||||
if( pCur->iBase>iMax ){
|
||||
if( pCur->iBase < add64(SMALLEST_INT64, pCur->iStep) ){
|
||||
goto series_no_rows;
|
||||
}
|
||||
pCur->iBase = sub64(pCur->iBase, pCur->iStep);
|
||||
}
|
||||
sqlite3_int64 szStep = -pCur->ss.iStep;
|
||||
assert( szStep>0 );
|
||||
if( pCur->ss.iBase>iMax ){
|
||||
sqlite3_uint64 d = pCur->ss.iBase - iMax;
|
||||
pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
|
||||
}
|
||||
if( pCur->iTerm<iMin ){
|
||||
pCur->iTerm = iMin;
|
||||
if( pCur->ss.iTerm<iMin ){
|
||||
pCur->ss.iTerm = iMin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust iTerm so that it is exactly the last value of the series.
|
||||
*/
|
||||
if( pCur->bDesc==0 ){
|
||||
if( pCur->iBase>pCur->iTerm ){
|
||||
goto series_no_rows;
|
||||
}
|
||||
pCur->iTerm = sub64(pCur->iTerm,
|
||||
span64(pCur->iTerm,pCur->iBase) % pCur->iStep);
|
||||
}else{
|
||||
if( pCur->iBase<pCur->iTerm ){
|
||||
goto series_no_rows;
|
||||
}
|
||||
pCur->iTerm = add64(pCur->iTerm,
|
||||
span64(pCur->iBase,pCur->iTerm) % pCur->iStep);
|
||||
}
|
||||
|
||||
/* Transform the series generator to output values in the requested
|
||||
** order.
|
||||
*/
|
||||
if( ((idxNum & 0x0008)!=0 && pCur->bDesc==0)
|
||||
|| ((idxNum & 0x0010)!=0 && pCur->bDesc!=0)
|
||||
){
|
||||
sqlite3_int64 tmp = pCur->iBase;
|
||||
pCur->iBase = pCur->iTerm;
|
||||
pCur->iTerm = tmp;
|
||||
pCur->bDesc = !pCur->bDesc;
|
||||
}
|
||||
|
||||
/* Apply LIMIT and OFFSET constraints, if any */
|
||||
assert( pCur->iStep!=0 );
|
||||
if( idxNum & 0x20 ){
|
||||
if( iOffset>0 ){
|
||||
if( seriesSteps(pCur) < (sqlite3_uint64)iOffset ){
|
||||
goto series_no_rows;
|
||||
}else if( pCur->bDesc ){
|
||||
pCur->iBase = sub64(pCur->iBase, pCur->iStep*iOffset);
|
||||
pCur->ss.iBase += pCur->ss.iStep*iOffset;
|
||||
}
|
||||
if( iLimit>=0 ){
|
||||
sqlite3_int64 iTerm;
|
||||
iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep;
|
||||
if( pCur->ss.iStep<0 ){
|
||||
if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
|
||||
}else{
|
||||
pCur->iBase = add64(pCur->iBase, pCur->iStep*iOffset);
|
||||
if( iTerm<pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
|
||||
}
|
||||
}
|
||||
if( iLimit>=0 && seriesSteps(pCur) > (sqlite3_uint64)iLimit ){
|
||||
pCur->iTerm = add64(pCur->iBase, (iLimit - 1)*pCur->iStep);
|
||||
}
|
||||
|
||||
|
||||
for(i=0; i<argc; i++){
|
||||
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
|
||||
/* If any of the constraints have a NULL value, then return no rows.
|
||||
** See ticket https://sqlite.org/src/info/fac496b61722daf2 */
|
||||
returnNoRows = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pCur->iValue = pCur->iBase;
|
||||
pCur->bDone = 0;
|
||||
if( returnNoRows ){
|
||||
pCur->ss.iBase = 1;
|
||||
pCur->ss.iTerm = 0;
|
||||
pCur->ss.iStep = 1;
|
||||
}
|
||||
if( idxNum & 0x08 ){
|
||||
pCur->ss.isReversing = pCur->ss.iStep > 0;
|
||||
}else{
|
||||
pCur->ss.isReversing = pCur->ss.iStep < 0;
|
||||
}
|
||||
setupSequence( &pCur->ss );
|
||||
return SQLITE_OK;
|
||||
|
||||
series_no_rows:
|
||||
pCur->iBase = 0;
|
||||
pCur->iTerm = 0;
|
||||
pCur->iStep = 1;
|
||||
pCur->bDesc = 0;
|
||||
pCur->bDone = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+7
-16
@@ -230,16 +230,13 @@ static void hash_finish(
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
** Two SQL functions: sha1(X) and sha1b(X).
|
||||
** Implementation of the sha1(X) function.
|
||||
**
|
||||
** sha1(X) returns a lower-case hexadecimal rendering of the SHA1 hash
|
||||
** of the argument X. If X is a BLOB, it is hashed as is. For all other
|
||||
** Return a lower-case hexadecimal rendering of the SHA1 hash of the
|
||||
** argument X. If X is a BLOB, it is hashed as is. For all other
|
||||
** types of input, X is converted into a UTF-8 string and the string
|
||||
** is hashed without the trailing 0x00 terminator. The hash of a NULL
|
||||
** is hash without the trailing 0x00 terminator. The hash of a NULL
|
||||
** value is NULL.
|
||||
**
|
||||
** sha1b(X) is the same except that it returns a 20-byte BLOB containing
|
||||
** the binary hash instead of a hexadecimal string.
|
||||
*/
|
||||
static void sha1Func(
|
||||
sqlite3_context *context,
|
||||
@@ -249,27 +246,22 @@ static void sha1Func(
|
||||
SHA1Context cx;
|
||||
int eType = sqlite3_value_type(argv[0]);
|
||||
int nByte = sqlite3_value_bytes(argv[0]);
|
||||
const unsigned char *pData;
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( eType==SQLITE_NULL ) return;
|
||||
hash_init(&cx);
|
||||
if( eType==SQLITE_BLOB ){
|
||||
pData = (const unsigned char*)sqlite3_value_blob(argv[0]);
|
||||
hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
|
||||
}else{
|
||||
pData = (const unsigned char*)sqlite3_value_text(argv[0]);
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
if( pData==0 ) return;
|
||||
hash_step(&cx, pData, nByte);
|
||||
if( sqlite3_user_data(context)!=0 ){
|
||||
/* sha1b() - binary result */
|
||||
hash_finish(&cx, zOut, 1);
|
||||
sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
/* sha1() - hexadecimal text result */
|
||||
hash_finish(&cx, zOut, 0);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +315,6 @@ static void sha1QueryFunc(
|
||||
}
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
z = sqlite3_sql(pStmt);
|
||||
if( z==0 ) z = "";
|
||||
n = (int)strlen(z);
|
||||
hash_step_vformat(&cx,"S%d:",n);
|
||||
hash_step(&cx,(unsigned char*)z,n);
|
||||
|
||||
+3
-3
@@ -46,7 +46,7 @@ static void sqlarCompressFunc(
|
||||
uLongf nOut = compressBound(nData);
|
||||
Bytef *pOut;
|
||||
|
||||
pOut = (Bytef*)sqlite3_malloc64(nOut);
|
||||
pOut = (Bytef*)sqlite3_malloc(nOut);
|
||||
if( pOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
@@ -84,14 +84,14 @@ static void sqlarUncompressFunc(
|
||||
sqlite3_int64 sz;
|
||||
|
||||
assert( argc==2 );
|
||||
sz = sqlite3_value_int64(argv[1]);
|
||||
sz = sqlite3_value_int(argv[1]);
|
||||
|
||||
if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
|
||||
sqlite3_result_value(context, argv[0]);
|
||||
}else{
|
||||
uLongf szf = sz;
|
||||
const Bytef *pData= sqlite3_value_blob(argv[0]);
|
||||
Bytef *pOut = sqlite3_malloc64(sz);
|
||||
Bytef *pOut = sqlite3_malloc(sz);
|
||||
if( pOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else if( Z_OK!=uncompress(pOut, &szf, pData, nData) ){
|
||||
|
||||
@@ -101,8 +101,8 @@ FILE *sqlite3_fopen(const char *zFilename, const char *zMode){
|
||||
|
||||
sz1 = (int)strlen(zFilename);
|
||||
sz2 = (int)strlen(zMode);
|
||||
b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) );
|
||||
b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) );
|
||||
b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
|
||||
b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
|
||||
if( b1 && b2 ){
|
||||
sz1 = MultiByteToWideChar(CP_UTF8, 0, zFilename, sz1, b1, sz1);
|
||||
b1[sz1] = 0;
|
||||
@@ -127,8 +127,8 @@ FILE *sqlite3_popen(const char *zCommand, const char *zMode){
|
||||
|
||||
sz1 = (int)strlen(zCommand);
|
||||
sz2 = (int)strlen(zMode);
|
||||
b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) );
|
||||
b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) );
|
||||
b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
|
||||
b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
|
||||
if( b1 && b2 ){
|
||||
sz1 = MultiByteToWideChar(CP_UTF8, 0, zCommand, sz1, b1, sz1);
|
||||
b1[sz1] = 0;
|
||||
@@ -151,7 +151,7 @@ char *sqlite3_fgets(char *buf, int sz, FILE *in){
|
||||
** that into UTF-8. Otherwise, non-ASCII characters all get translated
|
||||
** into '?'.
|
||||
*/
|
||||
wchar_t *b1 = sqlite3_malloc64( sz*sizeof(wchar_t) );
|
||||
wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
|
||||
if( b1==0 ) return 0;
|
||||
#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
|
||||
DWORD nRead = 0;
|
||||
@@ -226,7 +226,7 @@ int sqlite3_fputs(const char *z, FILE *out){
|
||||
** to the console on Windows.
|
||||
*/
|
||||
int sz = (int)strlen(z);
|
||||
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(wchar_t) );
|
||||
wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
|
||||
if( b1==0 ) return 0;
|
||||
sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
|
||||
b1[sz] = 0;
|
||||
@@ -258,7 +258,7 @@ int sqlite3_fputs(const char *z, FILE *out){
|
||||
|
||||
|
||||
/*
|
||||
** Work-alikes for fprintf() and vfprintf() from the standard C library.
|
||||
** Work-alike for fprintf() from the standard C library.
|
||||
*/
|
||||
int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
|
||||
int rc;
|
||||
@@ -285,24 +285,6 @@ int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
int sqlite3_vfprintf(FILE *out, const char *zFormat, va_list ap){
|
||||
int rc;
|
||||
if( UseWtextForOutput(out) ){
|
||||
/* When writing to the command-prompt in Windows, it is necessary
|
||||
** to use _O_WTEXT input mode and write UTF-16 characters.
|
||||
*/
|
||||
char *z;
|
||||
z = sqlite3_vmprintf(zFormat, ap);
|
||||
sqlite3_fputs(z, out);
|
||||
rc = (int)strlen(z);
|
||||
sqlite3_free(z);
|
||||
}else{
|
||||
/* Writing to a file or other destination, just write bytes without
|
||||
** any translation. */
|
||||
rc = vfprintf(out, zFormat, ap);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the mode for an output stream. mode argument is typically _O_BINARY or
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#ifdef _WIN32
|
||||
/**** Definitions For Windows ****/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <windows.h>
|
||||
|
||||
FILE *sqlite3_fopen(const char *zFilename, const char *zMode);
|
||||
@@ -39,7 +38,6 @@ FILE *sqlite3_popen(const char *zCommand, const char *type);
|
||||
char *sqlite3_fgets(char *s, int size, FILE *stream);
|
||||
int sqlite3_fputs(const char *s, FILE *stream);
|
||||
int sqlite3_fprintf(FILE *stream, const char *format, ...);
|
||||
int sqlite3_vfprintf(FILE *stream, const char *format, va_list);
|
||||
void sqlite3_fsetmode(FILE *stream, int mode);
|
||||
|
||||
|
||||
@@ -51,7 +49,6 @@ void sqlite3_fsetmode(FILE *stream, int mode);
|
||||
#define sqlite3_fgets fgets
|
||||
#define sqlite3_fputs fputs
|
||||
#define sqlite3_fprintf fprintf
|
||||
#define sqlite3_vfprintf vfprintf
|
||||
#define sqlite3_fsetmode(F,X) /*no-op*/
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ static void stmtrandFunc(
|
||||
p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
|
||||
if( p==0 ){
|
||||
unsigned int seed;
|
||||
p = sqlite3_malloc64( sizeof(*p) );
|
||||
p = sqlite3_malloc( sizeof(*p) );
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
|
||||
@@ -101,7 +101,7 @@ static int templatevtabConnect(
|
||||
#define TEMPLATEVTAB_A 0
|
||||
#define TEMPLATEVTAB_B 1
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -123,7 +123,7 @@ static int templatevtabDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int templatevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
templatevtab_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -613,7 +613,7 @@ static int vstattabConnect(
|
||||
|
||||
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
@@ -633,7 +633,7 @@ static int vstattabDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
VfsStatCursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
|
||||
+1
-1
@@ -892,7 +892,7 @@ static int vfstraceOpen(
|
||||
vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
|
||||
pInfo->zVfsName, p->zFName, flags);
|
||||
if( p->pReal->pMethods ){
|
||||
sqlite3_io_methods *pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
const sqlite3_io_methods *pSub = p->pReal->pMethods;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->iVersion = pSub->iVersion;
|
||||
|
||||
+8
-54
@@ -14,8 +14,6 @@
|
||||
** on stdout when its key interfaces are called. This is intended for
|
||||
** interactive analysis and debugging of virtual table interfaces.
|
||||
**
|
||||
** HOW TO COMPILE:
|
||||
**
|
||||
** To build this extension as a separately loaded shared library or
|
||||
** DLL, use compiler command-lines similar to the following:
|
||||
**
|
||||
@@ -23,7 +21,7 @@
|
||||
** (mac) clang -fPIC -dynamiclib vtablog.c -o vtablog.dylib
|
||||
** (windows) cl vtablog.c -link -dll -out:vtablog.dll
|
||||
**
|
||||
** USAGE EXAMPLE:
|
||||
** Usage example:
|
||||
**
|
||||
** .load ./vtablog
|
||||
** CREATE VIRTUAL TABLE temp.log USING vtablog(
|
||||
@@ -31,23 +29,6 @@
|
||||
** rows=25
|
||||
** );
|
||||
** SELECT * FROM log;
|
||||
**
|
||||
** ARGUMENTS TO CREATE VIRTUAL TABLE:
|
||||
**
|
||||
** In "CREATE VIRTUAL TABLE temp.log AS vtablog(ARGS....)" statement, the
|
||||
** ARGS argument is a list of key-value pairs that can be any of the
|
||||
** following.
|
||||
**
|
||||
** schema=TEXT Text is a CREATE TABLE statement that defines
|
||||
** the schema of the new virtual table.
|
||||
**
|
||||
** rows=N The table as N rows.
|
||||
**
|
||||
** consume_order_by=N If the left-most ORDER BY terms is ASC and
|
||||
** against column N (where the leftmost column
|
||||
** is #1) then set the orderByConsumed=1 flag in
|
||||
** xBestIndex. Or if the left-most ORDER BY is
|
||||
** DESC and against column -N, do likewise.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
@@ -68,8 +49,6 @@ struct vtablog_vtab {
|
||||
char *zName; /* Table name. argv[2] of xConnect/xCreate */
|
||||
int nRow; /* Number of rows in the table */
|
||||
int nCursor; /* Number of cursors created */
|
||||
int iConsumeOB; /* Consume the ORDER BY clause if on column N-th
|
||||
** and consumeOB=N or consumeOB=(-N) and DESC */
|
||||
};
|
||||
|
||||
/* vtablog_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
@@ -201,7 +180,6 @@ static int vtablogConnectCreate(
|
||||
int rc;
|
||||
char *zSchema = 0;
|
||||
char *zNRow = 0;
|
||||
char *zConsumeOB = 0;
|
||||
|
||||
printf("%s.%s.%s():\n", argv[1], argv[2],
|
||||
isCreate ? "xCreate" : "xConnect");
|
||||
@@ -225,32 +203,20 @@ static int vtablogConnectCreate(
|
||||
rc = SQLITE_ERROR;
|
||||
goto vtablog_end_connect;
|
||||
}
|
||||
if( vtablog_string_parameter(pzErr, "consume_order_by", z, &zConsumeOB) ){
|
||||
rc = SQLITE_ERROR;
|
||||
goto vtablog_end_connect;
|
||||
}
|
||||
}
|
||||
if( zSchema==0 ){
|
||||
zSchema = sqlite3_mprintf("%s","CREATE TABLE x(a,b);");
|
||||
if( zSchema==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto vtablog_end_connect;
|
||||
}
|
||||
}
|
||||
printf(" schema = '%s'\n", zSchema);
|
||||
rc = sqlite3_declare_vtab(db, zSchema);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->nRow = 10;
|
||||
if( zNRow ) pNew->nRow = atoi(zNRow);
|
||||
printf(" nrow = %d\n", pNew->nRow);
|
||||
if( zConsumeOB ) pNew->iConsumeOB = atoi(zConsumeOB);
|
||||
if( pNew->iConsumeOB ){
|
||||
printf(" consume_order_by = %d\n", pNew->iConsumeOB);
|
||||
}
|
||||
pNew->zDb = sqlite3_mprintf("%s", argv[1]);
|
||||
pNew->zName = sqlite3_mprintf("%s", argv[2]);
|
||||
}
|
||||
@@ -258,7 +224,6 @@ static int vtablogConnectCreate(
|
||||
vtablog_end_connect:
|
||||
sqlite3_free(zSchema);
|
||||
sqlite3_free(zNRow);
|
||||
sqlite3_free(zConsumeOB);
|
||||
return rc;
|
||||
}
|
||||
static int vtablogCreate(
|
||||
@@ -313,7 +278,7 @@ static int vtablogOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
vtablog_cursor *pCur;
|
||||
printf("%s.%s.xOpen(cursor=%d)\n", pTab->zDb, pTab->zName,
|
||||
++pTab->nCursor);
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->iCursor = pTab->nCursor;
|
||||
@@ -545,27 +510,16 @@ static int vtablogBestIndex(
|
||||
}
|
||||
}
|
||||
printf(" nOrderBy: %d\n", p->nOrderBy);
|
||||
if( p->nOrderBy ){
|
||||
for(i=0; i<p->nOrderBy; i++){
|
||||
printf(" orderby[%d]: col=%d desc=%d\n",
|
||||
i,
|
||||
p->aOrderBy[i].iColumn,
|
||||
p->aOrderBy[i].desc);
|
||||
}
|
||||
if( pTab->iConsumeOB ){
|
||||
int N = p->aOrderBy[0].iColumn+1;
|
||||
if( (p->aOrderBy[0].desc && N==-pTab->iConsumeOB)
|
||||
|| (!p->aOrderBy[0].desc && N==pTab->iConsumeOB)
|
||||
){
|
||||
p->orderByConsumed = 1;
|
||||
}
|
||||
}
|
||||
for(i=0; i<p->nOrderBy; i++){
|
||||
printf(" orderby[%d]: col=%d desc=%d\n",
|
||||
i,
|
||||
p->aOrderBy[i].iColumn,
|
||||
p->aOrderBy[i].desc);
|
||||
}
|
||||
p->estimatedCost = (double)500;
|
||||
p->estimatedRows = 500;
|
||||
printf(" idxNum=%d\n", p->idxNum);
|
||||
printf(" idxStr=NULL\n");
|
||||
printf(" sqlite3_vtab_distinct()=%d\n", sqlite3_vtab_distinct(p));
|
||||
printf(" orderByConsumed=%d\n", p->orderByConsumed);
|
||||
printf(" estimatedCost=%g\n", p->estimatedCost);
|
||||
printf(" estimatedRows=%lld\n", p->estimatedRows);
|
||||
|
||||
+5
-5
@@ -86,7 +86,7 @@ static int vtshimCreate(
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -125,7 +125,7 @@ static int vtshimConnect(
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
@@ -192,7 +192,7 @@ static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){
|
||||
int rc;
|
||||
*ppCursor = 0;
|
||||
if( pAux->bDisposed ) return SQLITE_ERROR;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild);
|
||||
@@ -444,7 +444,7 @@ static int vtshimCopyModule(
|
||||
){
|
||||
sqlite3_module *p;
|
||||
if( !pMod || !ppMod ) return SQLITE_ERROR;
|
||||
p = sqlite3_malloc64( sizeof(*p) );
|
||||
p = sqlite3_malloc( sizeof(*p) );
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
memcpy(p, pMod, sizeof(*p));
|
||||
*ppMod = p;
|
||||
@@ -464,7 +464,7 @@ void *sqlite3_create_disposable_module(
|
||||
vtshim_aux *pAux;
|
||||
sqlite3_module *pMod;
|
||||
int rc;
|
||||
pAux = sqlite3_malloc64( sizeof(*pAux) );
|
||||
pAux = sqlite3_malloc( sizeof(*pAux) );
|
||||
if( pAux==0 ){
|
||||
if( xDestroy ) xDestroy(pClientData);
|
||||
return 0;
|
||||
|
||||
@@ -47,7 +47,7 @@ static int wholenumberConnect(
|
||||
char **pzErr
|
||||
){
|
||||
sqlite3_vtab *pNew;
|
||||
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
@@ -69,7 +69,7 @@ static int wholenumberDisconnect(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int wholenumberOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
wholenumber_cursor *pCur;
|
||||
pCur = sqlite3_malloc64( sizeof(*pCur) );
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
|
||||
+32
-61
@@ -115,14 +115,9 @@ static const char ZIPFILE_SCHEMA[] =
|
||||
") WITHOUT ROWID;";
|
||||
|
||||
#define ZIPFILE_F_COLUMN_IDX 7 /* Index of column "file" in the above */
|
||||
#define ZIPFILE_BUFFER_SIZE (64*1024)
|
||||
#define ZIPFILE_MX_NAME (250) /* Windows limitation on filename size */
|
||||
|
||||
/*
|
||||
** The buffer should be large enough to contain 3 65536 byte strings - the
|
||||
** filename, the extra field and the file comment.
|
||||
*/
|
||||
#define ZIPFILE_BUFFER_SIZE (200*1024)
|
||||
|
||||
|
||||
/*
|
||||
** Magic numbers used to read and write zip files.
|
||||
@@ -393,7 +388,7 @@ static int zipfileConnect(
|
||||
|
||||
rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = (ZipfileTab*)sqlite3_malloc64((i64)nByte+nFile);
|
||||
pNew = (ZipfileTab*)sqlite3_malloc64((sqlite3_int64)nByte+nFile);
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, nByte+nFile);
|
||||
pNew->db = db;
|
||||
@@ -456,7 +451,7 @@ static int zipfileDisconnect(sqlite3_vtab *pVtab){
|
||||
static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
|
||||
ZipfileTab *pTab = (ZipfileTab*)p;
|
||||
ZipfileCsr *pCsr;
|
||||
pCsr = sqlite3_malloc64(sizeof(*pCsr));
|
||||
pCsr = sqlite3_malloc(sizeof(*pCsr));
|
||||
*ppCsr = (sqlite3_vtab_cursor*)pCsr;
|
||||
if( pCsr==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
@@ -539,15 +534,14 @@ static void zipfileCursorErr(ZipfileCsr *pCsr, const char *zFmt, ...){
|
||||
static int zipfileReadData(
|
||||
FILE *pFile, /* Read from this file */
|
||||
u8 *aRead, /* Read into this buffer */
|
||||
i64 nRead, /* Number of bytes to read */
|
||||
int nRead, /* Number of bytes to read */
|
||||
i64 iOff, /* Offset to read from */
|
||||
char **pzErrmsg /* OUT: Error message (from sqlite3_malloc) */
|
||||
){
|
||||
size_t n;
|
||||
fseek(pFile, (long)iOff, SEEK_SET);
|
||||
n = fread(aRead, 1, (long)nRead, pFile);
|
||||
if( n!=(size_t)nRead ){
|
||||
sqlite3_free(*pzErrmsg);
|
||||
n = fread(aRead, 1, nRead, pFile);
|
||||
if( (int)n!=nRead ){
|
||||
*pzErrmsg = sqlite3_mprintf("error in fread()");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@@ -564,7 +558,7 @@ static int zipfileAppendData(
|
||||
fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
|
||||
n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
|
||||
if( (int)n!=nWrite ){
|
||||
zipfileTableErr(pTab,"error in fwrite()");
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pTab->szCurrent += nWrite;
|
||||
@@ -705,12 +699,7 @@ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){
|
||||
u8 *p = aExtra;
|
||||
u8 *pEnd = &aExtra[nExtra];
|
||||
|
||||
/* Stop when there are less than 9 bytes left to scan in the buffer. This
|
||||
** is because the timestamp field requires exactly 9 bytes - 4 bytes of
|
||||
** header fields and 5 bytes of data. If there are less than 9 bytes
|
||||
** remaining, either it is some other field or else the extra data
|
||||
** is corrupt. Either way, do not process it. */
|
||||
while( p+(2*sizeof(u16) + 1 + sizeof(u32))<=pEnd ){
|
||||
while( p<pEnd ){
|
||||
u16 id = zipfileRead16(p);
|
||||
u16 nByte = zipfileRead16(p);
|
||||
|
||||
@@ -811,16 +800,6 @@ static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set (*pzErr) to point to a buffer from sqlite3_malloc() containing a
|
||||
** generic corruption message and return SQLITE_CORRUPT;
|
||||
*/
|
||||
static int zipfileCorrupt(char **pzErr){
|
||||
sqlite3_free(*pzErr);
|
||||
*pzErr = sqlite3_mprintf("zip archive is corrupt");
|
||||
return SQLITE_CORRUPT;
|
||||
}
|
||||
|
||||
/*
|
||||
** If aBlob is not NULL, then it is a pointer to a buffer (nBlob bytes in
|
||||
** size) containing an entire zip archive image. Or, if aBlob is NULL,
|
||||
@@ -835,7 +814,7 @@ static int zipfileCorrupt(char **pzErr){
|
||||
static int zipfileGetEntry(
|
||||
ZipfileTab *pTab, /* Store any error message here */
|
||||
const u8 *aBlob, /* Pointer to in-memory file image */
|
||||
i64 nBlob, /* Size of aBlob[] in bytes */
|
||||
int nBlob, /* Size of aBlob[] in bytes */
|
||||
FILE *pFile, /* If aBlob==0, read from this file */
|
||||
i64 iOff, /* Offset of CDS record */
|
||||
ZipfileEntry **ppEntry /* OUT: Pointer to new object */
|
||||
@@ -843,15 +822,12 @@ static int zipfileGetEntry(
|
||||
u8 *aRead;
|
||||
char **pzErr = &pTab->base.zErrMsg;
|
||||
int rc = SQLITE_OK;
|
||||
(void)nBlob;
|
||||
|
||||
if( aBlob==0 ){
|
||||
aRead = pTab->aBuffer;
|
||||
rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr);
|
||||
}else{
|
||||
if( (iOff+ZIPFILE_CDS_FIXED_SZ)>nBlob ){
|
||||
/* Not enough data for the CDS structure. Corruption. */
|
||||
return zipfileCorrupt(pzErr);
|
||||
}
|
||||
aRead = (u8*)&aBlob[iOff];
|
||||
}
|
||||
|
||||
@@ -875,16 +851,13 @@ static int zipfileGetEntry(
|
||||
memset(pNew, 0, sizeof(ZipfileEntry));
|
||||
rc = zipfileReadCDS(aRead, &pNew->cds);
|
||||
if( rc!=SQLITE_OK ){
|
||||
zipfileTableErr(pTab, "failed to read CDS at offset %lld", iOff);
|
||||
*pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff);
|
||||
}else if( aBlob==0 ){
|
||||
rc = zipfileReadData(
|
||||
pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr
|
||||
);
|
||||
}else{
|
||||
aRead = (u8*)&aBlob[iOff + ZIPFILE_CDS_FIXED_SZ];
|
||||
if( (iOff + ZIPFILE_CDS_FIXED_SZ + nFile + nExtra)>nBlob ){
|
||||
rc = zipfileCorrupt(pzErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,26 +880,22 @@ static int zipfileGetEntry(
|
||||
rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr);
|
||||
}else{
|
||||
aRead = (u8*)&aBlob[pNew->cds.iOffset];
|
||||
if( ((i64)pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ)>nBlob ){
|
||||
rc = zipfileCorrupt(pzErr);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&lfh, 0, sizeof(lfh));
|
||||
if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew->iDataOff = (i64)pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
|
||||
pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
|
||||
pNew->iDataOff += lfh.nFile + lfh.nExtra;
|
||||
if( aBlob && pNew->cds.szCompressed ){
|
||||
if( pNew->iDataOff + pNew->cds.szCompressed > nBlob ){
|
||||
rc = zipfileCorrupt(pzErr);
|
||||
rc = SQLITE_CORRUPT;
|
||||
}else{
|
||||
pNew->aData = &pNew->aExtra[nExtra];
|
||||
memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
zipfileTableErr(pTab, "failed to read LFH at offset %d",
|
||||
*pzErr = sqlite3_mprintf("failed to read LFH at offset %d",
|
||||
(int)pNew->cds.iOffset
|
||||
);
|
||||
}
|
||||
@@ -950,7 +919,7 @@ static int zipfileNext(sqlite3_vtab_cursor *cur){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( pCsr->pFile ){
|
||||
i64 iEof = (i64)pCsr->eocd.iOffset + (i64)pCsr->eocd.nSize;
|
||||
i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize;
|
||||
zipfileEntryFree(pCsr->pCurrent);
|
||||
pCsr->pCurrent = 0;
|
||||
if( pCsr->iNextOff>=iEof ){
|
||||
@@ -995,7 +964,7 @@ static void zipfileInflate(
|
||||
int nIn, /* Size of buffer aIn[] in bytes */
|
||||
int nOut /* Expected output size */
|
||||
){
|
||||
u8 *aRes = sqlite3_malloc64(nOut);
|
||||
u8 *aRes = sqlite3_malloc(nOut);
|
||||
if( aRes==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
}else{
|
||||
@@ -1016,7 +985,7 @@ static void zipfileInflate(
|
||||
if( err!=Z_STREAM_END ){
|
||||
zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err);
|
||||
}else{
|
||||
sqlite3_result_blob(pCtx, aRes, (int)str.total_out, zipfileFree);
|
||||
sqlite3_result_blob(pCtx, aRes, nOut, zipfileFree);
|
||||
aRes = 0;
|
||||
}
|
||||
}
|
||||
@@ -1188,12 +1157,12 @@ static int zipfileEof(sqlite3_vtab_cursor *cur){
|
||||
static int zipfileReadEOCD(
|
||||
ZipfileTab *pTab, /* Return errors here */
|
||||
const u8 *aBlob, /* Pointer to in-memory file image */
|
||||
i64 nBlob, /* Size of aBlob[] in bytes */
|
||||
int nBlob, /* Size of aBlob[] in bytes */
|
||||
FILE *pFile, /* Read from this file if aBlob==0 */
|
||||
ZipfileEOCD *pEOCD /* Object to populate */
|
||||
){
|
||||
u8 *aRead = pTab->aBuffer; /* Temporary buffer */
|
||||
i64 nRead; /* Bytes to read from file */
|
||||
int nRead; /* Bytes to read from file */
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
memset(pEOCD, 0, sizeof(ZipfileEOCD));
|
||||
@@ -1214,7 +1183,7 @@ static int zipfileReadEOCD(
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 i;
|
||||
int i;
|
||||
|
||||
/* Scan backwards looking for the signature bytes */
|
||||
for(i=nRead-20; i>=0; i--){
|
||||
@@ -1225,7 +1194,9 @@ static int zipfileReadEOCD(
|
||||
}
|
||||
}
|
||||
if( i<0 ){
|
||||
zipfileTableErr(pTab, "cannot find end of central directory record");
|
||||
pTab->base.zErrMsg = sqlite3_mprintf(
|
||||
"cannot find end of central directory record"
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
@@ -1270,7 +1241,7 @@ static void zipfileAddEntry(
|
||||
}
|
||||
}
|
||||
|
||||
static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, i64 nBlob){
|
||||
static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, int nBlob){
|
||||
ZipfileEOCD eocd;
|
||||
int rc;
|
||||
int i;
|
||||
@@ -1318,7 +1289,7 @@ static int zipfileFilter(
|
||||
}else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
|
||||
static const u8 aEmptyBlob = 0;
|
||||
const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
|
||||
i64 nBlob = sqlite3_value_bytes(argv[0]);
|
||||
int nBlob = sqlite3_value_bytes(argv[0]);
|
||||
assert( pTab->pFirstEntry==0 );
|
||||
if( aBlob==0 ){
|
||||
aBlob = &aEmptyBlob;
|
||||
@@ -1392,7 +1363,7 @@ static int zipfileBestIndex(
|
||||
|
||||
static ZipfileEntry *zipfileNewEntry(const char *zPath){
|
||||
ZipfileEntry *pNew;
|
||||
pNew = sqlite3_malloc64(sizeof(ZipfileEntry));
|
||||
pNew = sqlite3_malloc(sizeof(ZipfileEntry));
|
||||
if( pNew ){
|
||||
memset(pNew, 0, sizeof(ZipfileEntry));
|
||||
pNew->cds.zFile = sqlite3_mprintf("%s", zPath);
|
||||
@@ -1516,7 +1487,7 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
|
||||
|
||||
assert( pTab->pWriteFd==0 );
|
||||
if( pTab->zFile==0 || pTab->zFile[0]==0 ){
|
||||
zipfileTableErr(pTab, "zipfile: missing filename");
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
@@ -1526,9 +1497,9 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
|
||||
** in main-memory until the transaction is committed. */
|
||||
pTab->pWriteFd = sqlite3_fopen(pTab->zFile, "ab+");
|
||||
if( pTab->pWriteFd==0 ){
|
||||
zipfileTableErr(pTab,
|
||||
"zipfile: failed to open file %s for writing", pTab->zFile
|
||||
);
|
||||
pTab->base.zErrMsg = sqlite3_mprintf(
|
||||
"zipfile: failed to open file %s for writing", pTab->zFile
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
fseek(pTab->pWriteFd, 0, SEEK_END);
|
||||
@@ -1993,7 +1964,7 @@ struct ZipfileCtx {
|
||||
ZipfileBuffer cds;
|
||||
};
|
||||
|
||||
static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){
|
||||
static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){
|
||||
if( pBuf->n+nByte>pBuf->nAlloc ){
|
||||
u8 *aNew;
|
||||
sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512;
|
||||
@@ -2042,7 +2013,7 @@ static void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
|
||||
char *zName = 0; /* Path (name) of new entry */
|
||||
int nName = 0; /* Size of zName in bytes */
|
||||
char *zFree = 0; /* Free this before returning */
|
||||
i64 nByte;
|
||||
int nByte;
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user