Compare commits

..

1 Commits

Author SHA1 Message Date
drh 4bf96311af Take care to clear the subtype on VDBE registers when the value of the
register is overwritten with new content.
Fix for ticket [f45ac567eaa9f93].

FossilOrigin-Name: ec653cbcae74ecab4ec9df0548d5836e81dc5d14
2016-01-30 14:53:06 +00:00
344 changed files with 6083 additions and 13353 deletions
+11 -23
View File
@@ -173,7 +173,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
fts5.lo \
func.lo global.lo hash.lo \
icu.lo insert.lo json1.lo legacy.lo loadext.lo \
icu.lo insert.lo journal.lo json1.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
memjournal.lo \
mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
@@ -224,6 +224,7 @@ SRC = \
$(TOP)/src/hash.h \
$(TOP)/src/hwtime.h \
$(TOP)/src/insert.c \
$(TOP)/src/journal.c \
$(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \
$(TOP)/src/main.c \
@@ -375,7 +376,6 @@ TESTSRC = \
$(TOP)/src/test_autoext.c \
$(TOP)/src/test_async.c \
$(TOP)/src/test_backup.c \
$(TOP)/src/test_bestindex.c \
$(TOP)/src/test_blob.c \
$(TOP)/src/test_btree.c \
$(TOP)/src/test_config.c \
@@ -549,8 +549,7 @@ TESTOPTS = --verbose=file --output=test-out.txt
# Extra compiler options for various shell tools
#
SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
@@ -576,20 +575,14 @@ libtclsqlite3.la: tclsqlite.lo libsqlite3.la
-version-info "8:6:8" \
-avoid-version
sqlite3$(TEXE): $(TOP)/src/shell.c sqlite3.c
sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
$(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \
$(TOP)/src/shell.c sqlite3.c \
$(TOP)/src/shell.c libsqlite3.la \
$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS)
srcck1$(BEXE): $(TOP)/tool/srcck1.c
$(BCC) -o srcck1$(BEXE) $(TOP)/tool/srcck1.c
sourcetest: srcck1$(BEXE) sqlite3.c
./srcck1 sqlite3.c
fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(FUZZERSHELL_OPT) \
$(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS)
@@ -738,6 +731,9 @@ hash.lo: $(TOP)/src/hash.c $(HDR)
insert.lo: $(TOP)/src/insert.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/insert.c
journal.lo: $(TOP)/src/journal.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/journal.c
legacy.lo: $(TOP)/src/legacy.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/legacy.c
@@ -1047,8 +1043,6 @@ sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
TESTFIXTURE_FLAGS += -DBUILD_sqlite
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
TESTFIXTURE_SRC1 = sqlite3.c
@@ -1089,7 +1083,7 @@ quicktest: ./testfixture$(TEXE)
# This is the common case. Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
test: $(TESTPROGS) sourcetest fastfuzztest
test: $(TESTPROGS) fastfuzztest
./testfixture$(TEXE) $(TOP)/test/veryquick.test $(TESTOPTS)
# Run a test using valgrind. This can take a really long time
@@ -1155,15 +1149,10 @@ checksymbols: sqlite3.lo
nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0
echo '0 errors out of 1 tests'
# Build the amalgamation-autoconf package. The amalamgation-tarball target builds
# a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz.
# The snapshot-tarball target builds a tarball named by the SHA1 hash
# Build the amalgamation-autoconf package.
#
amalgamation-tarball: sqlite3.c
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
snapshot-tarball: sqlite3.c
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh
# The next two rules are used to support the "threadtest" target. Building
# threadtest runs a few thread-safety tests that are implemented in C. This
@@ -1230,7 +1219,6 @@ clean:
rm -f sqlite-*-output.vsix
rm -f mptester mptester.exe
rm -f rbu rbu.exe
rm -f srcck1 srcck1.exe
rm -f fuzzershell fuzzershell.exe
rm -f fuzzcheck fuzzcheck.exe
rm -f sqldiff sqldiff.exe
+155 -212
View File
@@ -126,12 +126,12 @@ USE_RC = 1
FOR_WINRT = 0
!ENDIF
# Set this non-0 to compile binaries suitable for the UWP environment.
# Set this non-0 to compile binaries suitable for the UAP environment.
# This setting does not apply to any binaries that require Tcl to operate
# properly (i.e. the text fixture, etc).
#
!IFNDEF FOR_UWP
FOR_UWP = 0
!IFNDEF FOR_UAP
FOR_UAP = 0
!ENDIF
# Set this non-0 to compile binaries suitable for the Windows 10 platform.
@@ -219,43 +219,27 @@ SQLITE3H = sqlite3.h
# This is the name to use for the SQLite dynamic link library (DLL).
#
!IFNDEF SQLITE3DLL
!IF $(FOR_WIN10)!=0
SQLITE3DLL = winsqlite3.dll
!ELSE
SQLITE3DLL = sqlite3.dll
!ENDIF
!ENDIF
# This is the name to use for the SQLite import library (LIB).
#
!IFNDEF SQLITE3LIB
!IF $(FOR_WIN10)!=0
SQLITE3LIB = winsqlite3.lib
!ELSE
SQLITE3LIB = sqlite3.lib
!ENDIF
!ENDIF
# This is the name to use for the SQLite shell executable (EXE).
#
!IFNDEF SQLITE3EXE
!IF $(FOR_WIN10)!=0
SQLITE3EXE = winsqlite3shell.exe
!ELSE
SQLITE3EXE = sqlite3.exe
!ENDIF
!ENDIF
# This is the argument used to set the program database (PDB) file for the
# SQLite shell executable (EXE).
#
!IFNDEF SQLITE3EXEPDB
!IF $(FOR_WIN10)!=0
SQLITE3EXEPDB =
!ELSE
SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
!ENDIF
!ENDIF
# These are the "standard" SQLite compilation options used when compiling for
# the Windows platform.
@@ -271,8 +255,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
#
!IFNDEF EXT_FEATURE_FLAGS
!IF $(FOR_WIN10)!=0
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_STAT4=1
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_OMIT_LOCALTIME=1
@@ -285,15 +267,6 @@ EXT_FEATURE_FLAGS =
############################### END OF OPTIONS ################################
###############################################################################
# When compiling for the Windows 10 platform, the PLATFORM macro must be set
# to an appropriate value (e.g. x86, x64, arm, arm64, etc).
#
!IF $(FOR_WIN10)!=0
!IFNDEF PLATFORM
!ERROR Using the FOR_WIN10 option requires a value for PLATFORM.
!ENDIF
!ENDIF
# This assumes that MSVC is always installed in 32-bit Program Files directory
# and sets the variable for use in locating other 32-bit installs accordingly.
#
@@ -308,14 +281,6 @@ PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\)
CC = cl.exe
!ENDIF
# Check for the predefined command macro CSC. This should point to a working
# C Sharp compiler binary. If it is not defined, simply define it to the
# legacy default value 'csc.exe'.
#
!IFNDEF CSC
CSC = csc.exe
!ENDIF
# Check for the command macro LD. This should point to the linker binary for
# the target platform. If it is not defined, simply define it to the legacy
# default value 'link.exe'.
@@ -332,7 +297,7 @@ LD = link.exe
RC = rc.exe
!ENDIF
# Check for the MSVC runtime library path macro. Otherwise, this value will
# Check for the MSVC runtime library path macro. Othertise, this value will
# default to the 'lib' directory underneath the MSVC installation directory.
#
!IFNDEF CRTLIBPATH
@@ -369,7 +334,7 @@ NCC = $(NCC:\\=\)
NCC = $(CC)
!ENDIF
# Check for the MSVC native runtime library path macro. Otherwise,
# Check for the MSVC native runtime library path macro. Othertise,
# this value will default to the 'lib' directory underneath the MSVC
# installation directory.
#
@@ -379,7 +344,7 @@ NCRTLIBPATH = $(VCINSTALLDIR)\lib
NCRTLIBPATH = $(NCRTLIBPATH:\\=\)
# Check for the Platform SDK library path macro. Otherwise, this
# Check for the Platform SDK library path macro. Othertise, this
# value will default to the 'lib' directory underneath the Windows
# SDK installation directory (the environment variable used appears
# to be available when using Visual C++ 2008 or later via the
@@ -391,16 +356,6 @@ NSDKLIBPATH = $(WINDOWSSDKDIR)\lib
NSDKLIBPATH = $(NSDKLIBPATH:\\=\)
# Check for the UCRT library path macro. Otherwise, this value will
# default to the version-specific, platform-specific 'lib' directory
# underneath the Windows SDK installation directory.
#
!IFNDEF UCRTLIBPATH
UCRTLIBPATH = $(WINDOWSSDKDIR)\lib\$(WINDOWSSDKLIBVERSION)\ucrt\$(PLATFORM)
!ENDIF
UCRTLIBPATH = $(UCRTLIBPATH:\\=\)
# C compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
@@ -440,8 +395,17 @@ TCC = $(CC) -nologo -W4 -DINCLUDE_MSVC_H=1 $(CCOPTS) $(TCCOPTS)
TCC = $(CC) -nologo -W3 $(CCOPTS) $(TCCOPTS)
!ENDIF
TCC = $(TCC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src -fp:precise
RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src $(RCOPTS) $(RCCOPTS)
TCC = $(TCC) -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src -fp:precise
RCC = $(RC) -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src $(RCOPTS) $(RCCOPTS)
# Adjust the names of the primary targets for use with Windows 10.
#
!IF $(FOR_WIN10)!=0
SQLITE3DLL = winsqlite3.dll
SQLITE3LIB = winsqlite3.lib
SQLITE3EXE = winsqlite3shell.exe
SQLITE3EXEPDB =
!ENDIF
# Check if we want to use the "stdcall" calling convention when compiling.
# This is not supported by the compilers for non-x86 platforms. It should
@@ -482,24 +446,20 @@ CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS)
# when linking.
#
!IFNDEF CORE_LINK_DEP
!IF $(DYNAMIC_SHELL)!=0
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
CORE_LINK_DEP =
!ELSEIF $(FOR_WIN10)==0 || "$(PLATFORM)"=="x86"
CORE_LINK_DEP = sqlite3.def
!ELSE
CORE_LINK_DEP =
CORE_LINK_DEP = sqlite3.def
!ENDIF
!ENDIF
# These are additional linker options used for the core library.
#
!IFNDEF CORE_LINK_OPTS
!IF $(DYNAMIC_SHELL)!=0
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
CORE_LINK_OPTS =
!ELSEIF $(FOR_WIN10)==0 || "$(PLATFORM)"=="x86"
CORE_LINK_OPTS = /DEF:sqlite3.def
!ELSE
CORE_LINK_OPTS =
CORE_LINK_OPTS = /DEF:sqlite3.def
!ENDIF
!ENDIF
@@ -572,8 +532,8 @@ RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
# C compiler options for the Windows 10 platform (needs MSVC 2015).
#
!IF $(FOR_WIN10)!=0
TCC = $(TCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
TCC = $(TCC) /guard:cf -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
BCC = $(BCC) /guard:cf -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
!ENDIF
# Also, we need to dynamically link to the correct MSVC runtime
@@ -581,7 +541,7 @@ 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 $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
!IF $(FOR_WINRT)!=0 || $(FOR_WIN10)!=0 || $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
@@ -928,10 +888,9 @@ LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelH
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.
# When compiling for UAP, some extra linker options are also required.
#
!IF $(FOR_UWP)!=0 || $(FOR_WIN10)!=0
!IF $(FOR_UAP)!=0 || $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib
LTLINKOPTS = $(LTLINKOPTS) mincore.lib
!IFDEF PSDKLIBPATH
@@ -939,15 +898,6 @@ LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)"
!ENDIF
!ENDIF
!IF $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) /guard:cf "/LIBPATH:$(UCRTLIBPATH)"
!IF $(DEBUG)>1
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrtd.lib /DEFAULTLIB:ucrtd.lib
!ELSE
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
!ENDIF
!ENDIF
# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
@@ -987,7 +937,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
fts5.lo \
func.lo global.lo hash.lo \
icu.lo insert.lo legacy.lo loadext.lo \
icu.lo insert.lo journal.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
memjournal.lo \
mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
@@ -1026,9 +976,9 @@ LIBRESOBJS =
!ENDIF
# <<mark>>
# Core source code files, part 1.
# All of the source code files.
#
SRC00 = \
SRC1 = \
$(TOP)\src\alter.c \
$(TOP)\src\analyze.c \
$(TOP)\src\attach.c \
@@ -1037,6 +987,8 @@ SRC00 = \
$(TOP)\src\bitvec.c \
$(TOP)\src\btmutex.c \
$(TOP)\src\btree.c \
$(TOP)\src\btree.h \
$(TOP)\src\btreeInt.h \
$(TOP)\src\build.c \
$(TOP)\src\callback.c \
$(TOP)\src\complete.c \
@@ -1050,7 +1002,10 @@ SRC00 = \
$(TOP)\src\func.c \
$(TOP)\src\global.c \
$(TOP)\src\hash.c \
$(TOP)\src\hash.h \
$(TOP)\src\hwtime.h \
$(TOP)\src\insert.c \
$(TOP)\src\journal.c \
$(TOP)\src\legacy.c \
$(TOP)\src\loadext.c \
$(TOP)\src\main.c \
@@ -1061,22 +1016,29 @@ SRC00 = \
$(TOP)\src\mem3.c \
$(TOP)\src\mem5.c \
$(TOP)\src\memjournal.c \
$(TOP)\src\msvc.h \
$(TOP)\src\mutex.c \
$(TOP)\src\mutex.h \
$(TOP)\src\mutex_noop.c \
$(TOP)\src\mutex_unix.c \
$(TOP)\src\mutex_w32.c \
$(TOP)\src\notify.c \
$(TOP)\src\os.c \
$(TOP)\src\os.h \
$(TOP)\src\os_common.h \
$(TOP)\src\os_setup.h \
$(TOP)\src\os_unix.c \
$(TOP)\src\os_win.c
# Core source code files, part 2.
#
SRC01 = \
$(TOP)\src\os_win.c \
$(TOP)\src\os_win.h
SRC2 = \
$(TOP)\src\pager.c \
$(TOP)\src\pager.h \
$(TOP)\src\parse.y \
$(TOP)\src\pcache.c \
$(TOP)\src\pcache.h \
$(TOP)\src\pcache1.c \
$(TOP)\src\pragma.c \
$(TOP)\src\pragma.h \
$(TOP)\src\prepare.c \
$(TOP)\src\printf.c \
$(TOP)\src\random.c \
@@ -1084,6 +1046,11 @@ SRC01 = \
$(TOP)\src\rowset.c \
$(TOP)\src\select.c \
$(TOP)\src\status.c \
$(TOP)\src\shell.c \
$(TOP)\src\sqlite.h.in \
$(TOP)\src\sqlite3ext.h \
$(TOP)\src\sqliteInt.h \
$(TOP)\src\sqliteLimit.h \
$(TOP)\src\table.c \
$(TOP)\src\threads.c \
$(TOP)\src\tclsqlite.c \
@@ -1095,132 +1062,83 @@ SRC01 = \
$(TOP)\src\util.c \
$(TOP)\src\vacuum.c \
$(TOP)\src\vdbe.c \
$(TOP)\src\vdbe.h \
$(TOP)\src\vdbeapi.c \
$(TOP)\src\vdbeaux.c \
$(TOP)\src\vdbeblob.c \
$(TOP)\src\vdbemem.c \
$(TOP)\src\vdbesort.c \
$(TOP)\src\vdbetrace.c \
$(TOP)\src\vdbeInt.h \
$(TOP)\src\vtab.c \
$(TOP)\src\vxworks.h \
$(TOP)\src\wal.c \
$(TOP)\src\wal.h \
$(TOP)\src\walker.c \
$(TOP)\src\where.c \
$(TOP)\src\wherecode.c \
$(TOP)\src\whereexpr.c
# Shell source code files.
#
SRC02 = \
$(TOP)\src\shell.c
# Core miscellaneous files.
#
SRC03 = \
$(TOP)\src\parse.y
# Core header files, part 1.
#
SRC04 = \
$(TOP)\src\btree.h \
$(TOP)\src\btreeInt.h \
$(TOP)\src\hash.h \
$(TOP)\src\hwtime.h \
$(TOP)\src\msvc.h \
$(TOP)\src\mutex.h \
$(TOP)\src\os.h \
$(TOP)\src\os_common.h \
$(TOP)\src\os_setup.h \
$(TOP)\src\os_win.h
# Core header files, part 2.
#
SRC05 = \
$(TOP)\src\pager.h \
$(TOP)\src\pcache.h \
$(TOP)\src\pragma.h \
$(TOP)\src\sqlite.h.in \
$(TOP)\src\sqlite3ext.h \
$(TOP)\src\sqliteInt.h \
$(TOP)\src\sqliteLimit.h \
$(TOP)\src\vdbe.h \
$(TOP)\src\vdbeInt.h \
$(TOP)\src\vxworks.h \
$(TOP)\src\wal.h \
$(TOP)\src\whereexpr.c \
$(TOP)\src\whereInt.h
# Extension source code files, part 1.
# Source code for extensions
#
SRC06 = \
SRC3 = \
$(TOP)\ext\fts1\fts1.c \
$(TOP)\ext\fts1\fts1.h \
$(TOP)\ext\fts1\fts1_hash.c \
$(TOP)\ext\fts1\fts1_hash.h \
$(TOP)\ext\fts1\fts1_porter.c \
$(TOP)\ext\fts1\fts1_tokenizer.h \
$(TOP)\ext\fts1\fts1_tokenizer1.c \
$(TOP)\ext\fts2\fts2.c \
$(TOP)\ext\fts2\fts2.h \
$(TOP)\ext\fts2\fts2_hash.c \
$(TOP)\ext\fts2\fts2_hash.h \
$(TOP)\ext\fts2\fts2_icu.c \
$(TOP)\ext\fts2\fts2_porter.c \
$(TOP)\ext\fts2\fts2_tokenizer.h \
$(TOP)\ext\fts2\fts2_tokenizer.c \
$(TOP)\ext\fts2\fts2_tokenizer1.c
# Extension source code files, part 2.
#
SRC07 = \
SRC4 = \
$(TOP)\ext\fts3\fts3.c \
$(TOP)\ext\fts3\fts3.h \
$(TOP)\ext\fts3\fts3Int.h \
$(TOP)\ext\fts3\fts3_aux.c \
$(TOP)\ext\fts3\fts3_expr.c \
$(TOP)\ext\fts3\fts3_hash.c \
$(TOP)\ext\fts3\fts3_hash.h \
$(TOP)\ext\fts3\fts3_icu.c \
$(TOP)\ext\fts3\fts3_porter.c \
$(TOP)\ext\fts3\fts3_snippet.c \
$(TOP)\ext\fts3\fts3_tokenizer.h \
$(TOP)\ext\fts3\fts3_tokenizer.c \
$(TOP)\ext\fts3\fts3_tokenizer1.c \
$(TOP)\ext\fts3\fts3_tokenize_vtab.c \
$(TOP)\ext\fts3\fts3_unicode.c \
$(TOP)\ext\fts3\fts3_unicode2.c \
$(TOP)\ext\fts3\fts3_write.c \
$(TOP)\ext\icu\sqliteicu.h \
$(TOP)\ext\icu\icu.c \
$(TOP)\ext\rtree\rtree.h \
$(TOP)\ext\rtree\rtree.c \
$(TOP)\ext\rbu\sqlite3rbu.h \
$(TOP)\ext\rbu\sqlite3rbu.c \
$(TOP)\ext\misc\json1.c
# Extension header files, part 1.
#
SRC08 = \
$(TOP)\ext\fts1\fts1.h \
$(TOP)\ext\fts1\fts1_hash.h \
$(TOP)\ext\fts1\fts1_tokenizer.h \
$(TOP)\ext\fts2\fts2.h \
$(TOP)\ext\fts2\fts2_hash.h \
$(TOP)\ext\fts2\fts2_tokenizer.h
# Extension header files, part 2.
#
SRC09 = \
$(TOP)\ext\fts3\fts3.h \
$(TOP)\ext\fts3\fts3Int.h \
$(TOP)\ext\fts3\fts3_hash.h \
$(TOP)\ext\fts3\fts3_tokenizer.h \
$(TOP)\ext\icu\sqliteicu.h \
$(TOP)\ext\rtree\rtree.h \
$(TOP)\ext\rbu\sqlite3rbu.h
# Generated source code files
#
SRC10 = \
opcodes.c \
parse.c
# Generated header files
#
SRC11 = \
SRC5 = \
keywordhash.h \
opcodes.c \
opcodes.h \
parse.c \
parse.h \
$(SQLITE3H)
# All source code files.
#
SRC = $(SRC00) $(SRC01) $(SRC02) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11)
SRC = $(SRC1) $(SRC2) $(SRC3) $(SRC4) $(SRC5)
# Source code to the test files.
#
@@ -1237,7 +1155,6 @@ TESTSRC = \
$(TOP)\src\test_autoext.c \
$(TOP)\src\test_async.c \
$(TOP)\src\test_backup.c \
$(TOP)\src\test_bestindex.c \
$(TOP)\src\test_blob.c \
$(TOP)\src\test_btree.c \
$(TOP)\src\test_config.c \
@@ -1270,7 +1187,7 @@ TESTSRC = \
$(TOP)\ext\fts3\fts3_test.c \
$(TOP)\ext\rbu\test_rbu.c
# Statically linked extensions.
# Statically linked extensions
#
TESTEXT = \
$(TOP)\ext\misc\amatch.c \
@@ -1290,14 +1207,56 @@ TESTEXT = \
$(TOP)\ext\misc\totype.c \
$(TOP)\ext\misc\wholenumber.c
# Source code to the library files needed by the test fixture
#
TESTSRC2 = \
$(SRC00) \
$(SRC01) \
$(SRC06) \
$(SRC07) \
$(SRC10) \
$(TOP)\src\attach.c \
$(TOP)\src\backup.c \
$(TOP)\src\bitvec.c \
$(TOP)\src\btree.c \
$(TOP)\src\build.c \
$(TOP)\src\ctime.c \
$(TOP)\src\date.c \
$(TOP)\src\dbstat.c \
$(TOP)\src\expr.c \
$(TOP)\src\func.c \
$(TOP)\src\insert.c \
$(TOP)\src\wal.c \
$(TOP)\src\main.c \
$(TOP)\src\mem5.c \
$(TOP)\src\os.c \
$(TOP)\src\os_unix.c \
$(TOP)\src\os_win.c \
$(TOP)\src\pager.c \
$(TOP)\src\pragma.c \
$(TOP)\src\prepare.c \
$(TOP)\src\printf.c \
$(TOP)\src\random.c \
$(TOP)\src\pcache.c \
$(TOP)\src\pcache1.c \
$(TOP)\src\select.c \
$(TOP)\src\tokenize.c \
$(TOP)\src\utf.c \
$(TOP)\src\util.c \
$(TOP)\src\vdbeapi.c \
$(TOP)\src\vdbeaux.c \
$(TOP)\src\vdbe.c \
$(TOP)\src\vdbemem.c \
$(TOP)\src\vdbesort.c \
$(TOP)\src\vdbetrace.c \
$(TOP)\src\where.c \
$(TOP)\src\wherecode.c \
$(TOP)\src\whereexpr.c \
parse.c \
$(TOP)\ext\fts3\fts3.c \
$(TOP)\ext\fts3\fts3_aux.c \
$(TOP)\ext\fts3\fts3_expr.c \
$(TOP)\ext\fts3\fts3_tokenizer.c \
$(TOP)\ext\fts3\fts3_tokenize_vtab.c \
$(TOP)\ext\fts3\fts3_unicode.c \
$(TOP)\ext\fts3\fts3_unicode2.c \
$(TOP)\ext\fts3\fts3_write.c \
$(TOP)\ext\async\sqlite3async.c
# Header files used by all library source files.
@@ -1371,7 +1330,7 @@ FUZZDATA = \
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
!ENDIF
# <<mark>>
@@ -1401,30 +1360,30 @@ all: dll libsqlite3.lib shell $(ALL_TCL_TARGETS)
# Dynamic link library section.
#
dll: $(SQLITE3DLL)
dll: $(SQLITE3DLL)
# Shell executable.
#
shell: $(SQLITE3EXE)
shell: $(SQLITE3EXE)
# <<mark>>
libsqlite3.lib: $(LIBOBJ)
$(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS)
# <<mark>>
libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib
$(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCLSTUB) $(TLIBS)
# <</mark>>
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
# <<block2>>
sqlite3.def: libsqlite3.lib
# <<mark>>
sqlite3.def: libsqlite3.lib
echo EXPORTS > sqlite3.def
dumpbin /all libsqlite3.lib \
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3_[^@]*)(?:@\d+)?$$" \1 \
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3_.*)$$" \1 \
| sort >> sqlite3.def
# <</block2>>
# <</mark>>
$(SQLITE3EXE): $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
$(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c $(SHELL_CORE_SRC) \
@@ -1434,12 +1393,6 @@ $(SQLITE3EXE): $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_S
sqldiff.exe: $(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
srcck1.exe: $(TOP)\tool\srcck1.c
$(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c
sourcetest: srcck1.exe sqlite3.c
srcck1.exe sqlite3.c
fuzzershell.exe: $(TOP)\tool\fuzzershell.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) $(TOP)\tool\fuzzershell.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -1472,18 +1425,11 @@ mptest: mptester.exe
.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl fts5.c
-rmdir /Q/S tsrc 2>NUL
-mkdir tsrc
for %i in ($(SRC00)) do copy /Y %i tsrc
for %i in ($(SRC01)) do copy /Y %i tsrc
for %i in ($(SRC02)) do copy /Y %i tsrc
for %i in ($(SRC03)) do copy /Y %i tsrc
for %i in ($(SRC04)) do copy /Y %i tsrc
for %i in ($(SRC05)) do copy /Y %i tsrc
for %i in ($(SRC06)) do copy /Y %i tsrc
for %i in ($(SRC07)) do copy /Y %i tsrc
for %i in ($(SRC08)) do copy /Y %i tsrc
for %i in ($(SRC09)) do copy /Y %i tsrc
for %i in ($(SRC10)) do copy /Y %i tsrc
for %i in ($(SRC11)) do copy /Y %i tsrc
for %i in ($(SRC1)) do copy /Y %i tsrc
for %i in ($(SRC2)) do copy /Y %i tsrc
for %i in ($(SRC3)) do copy /Y %i tsrc
for %i in ($(SRC4)) do copy /Y %i tsrc
for %i in ($(SRC5)) do copy /Y %i tsrc
copy /Y fts5.c tsrc
copy /Y fts5.h tsrc
del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL
@@ -1611,6 +1557,9 @@ hash.lo: $(TOP)\src\hash.c $(HDR)
insert.lo: $(TOP)\src\insert.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\insert.c
journal.lo: $(TOP)\src\journal.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\journal.c
legacy.lo: $(TOP)\src\legacy.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\legacy.c
@@ -1795,7 +1744,7 @@ parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\tool\addopcodes.tcl
$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H)
sqlite3ext.h: .target_source
sqlite3ext.h: .target_source
copy tsrc\sqlite3ext.h .
mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c
@@ -1896,9 +1845,9 @@ fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
del /Q fts5parse.h 2>NUL
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) fts5parse.y
fts5parse.h: fts5parse.c
fts5parse.h: fts5parse.c
fts5.c: $(FTS5_SRC)
fts5.c: $(FTS5_SRC)
$(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
copy $(TOP)\ext\fts5\fts5.h .
@@ -1924,10 +1873,8 @@ sqlite3rbu.lo: $(TOP)\ext\rbu\sqlite3rbu.c $(HDR) $(EXTHDR)
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE=""
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN)
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) $(SHELL_CORE_DEP)
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
!IF $(USE_AMALGAMATION)==0
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0)
@@ -1941,7 +1888,7 @@ testfixture.exe: $(TESTFIXTURE_SRC) $(SQLITE3H) $(LIBRESOBJS) $(HDR)
$(TESTFIXTURE_SRC) \
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
extensiontest: testfixture.exe testloadext.dll
extensiontest: testfixture.exe testloadext.dll
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
@@ -1969,14 +1916,14 @@ fastfuzztest: fuzzcheck.exe
# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest: testfixture.exe sourcetest
quicktest: testfixture.exe
@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.
#
test: $(TESTPROGS) sourcetest fastfuzztest
test: $(TESTPROGS) fastfuzztest
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)
@@ -1984,7 +1931,7 @@ smoketest: $(TESTPROGS)
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl
echo #define TCLSH 2 > $@
echo #define SQLITE_ENABLE_DBSTAT_VTAB 1 >> $@
copy $@ + $(SQLITE3C) + $(TOP)\src\tclsqlite.c $@
@@ -2000,7 +1947,7 @@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
testloadext.lo: $(TOP)\src\test_loadext.c
$(LTCOMPILE) $(NO_WARN) -c $(TOP)\src\test_loadext.c
testloadext.dll: testloadext.lo
testloadext.dll: testloadext.lo
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ testloadext.lo
showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C) $(SQLITE3H)
@@ -2038,21 +1985,16 @@ speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \
$(TOP)\test\speedtest1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
rbu.exe: $(TOP)\ext\rbu\rbu.c $(TOP)\ext\rbu\sqlite3rbu.c $(SQLITE3C) $(SQLITE3H)
rbu.exe: $(TOP)\ext\rbu\rbu.c $(TOP)\ext\rbu\sqlite3rbu.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) -DSQLITE_ENABLE_RBU -Fe$@ \
$(TOP)\ext\rbu\rbu.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
moreclean: clean
del /Q $(SQLITE3C) $(SQLITE3H) 2>NUL
# <</mark>>
clean:
del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
# <<mark>>
del /Q sqlite3.c sqlite3.h 2>NUL
del /Q opcodes.c opcodes.h 2>NUL
del /Q $(SQLITE3C) $(SQLITE3H) opcodes.c opcodes.h 2>NUL
del /Q lemon.* lempar.c parse.* 2>NUL
del /Q mkkeywordhash.* keywordhash.h 2>NUL
del /Q notasharedlib.* 2>NUL
@@ -2068,7 +2010,8 @@ clean:
del /Q testfixture.exe test.db 2>NUL
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe 2>NUL
del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
del /Q mptester.exe wordcount.exe rbu.exe 2>NUL
del /Q $(SQLITE3EXE) $(SQLITE3DLL) sqlite3.def 2>NUL
del /Q sqlite3.c sqlite3-*.c 2>NUL
del /Q sqlite3rc.h 2>NUL
del /Q shell.c sqlite3ext.h 2>NUL
+1 -1
View File
@@ -1 +1 @@
3.12.2
3.11.0
+2 -2
View File
@@ -10,11 +10,11 @@ sqlite3_SOURCES = shell.c sqlite3.h
EXTRA_sqlite3_SOURCES = sqlite3.c
sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS
sqlite3_CFLAGS = $(AM_CFLAGS)
include_HEADERS = sqlite3.h sqlite3ext.h
EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt Replace.cs
EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = sqlite3.pc
+33 -89
View File
@@ -119,12 +119,12 @@ USE_RC = 1
FOR_WINRT = 0
!ENDIF
# Set this non-0 to compile binaries suitable for the UWP environment.
# Set this non-0 to compile binaries suitable for the UAP environment.
# This setting does not apply to any binaries that require Tcl to operate
# properly (i.e. the text fixture, etc).
#
!IFNDEF FOR_UWP
FOR_UWP = 0
!IFNDEF FOR_UAP
FOR_UAP = 0
!ENDIF
# Set this non-0 to compile binaries suitable for the Windows 10 platform.
@@ -204,43 +204,27 @@ SQLITE3H = sqlite3.h
# This is the name to use for the SQLite dynamic link library (DLL).
#
!IFNDEF SQLITE3DLL
!IF $(FOR_WIN10)!=0
SQLITE3DLL = winsqlite3.dll
!ELSE
SQLITE3DLL = sqlite3.dll
!ENDIF
!ENDIF
# This is the name to use for the SQLite import library (LIB).
#
!IFNDEF SQLITE3LIB
!IF $(FOR_WIN10)!=0
SQLITE3LIB = winsqlite3.lib
!ELSE
SQLITE3LIB = sqlite3.lib
!ENDIF
!ENDIF
# This is the name to use for the SQLite shell executable (EXE).
#
!IFNDEF SQLITE3EXE
!IF $(FOR_WIN10)!=0
SQLITE3EXE = winsqlite3shell.exe
!ELSE
SQLITE3EXE = sqlite3.exe
!ENDIF
!ENDIF
# This is the argument used to set the program database (PDB) file for the
# SQLite shell executable (EXE).
#
!IFNDEF SQLITE3EXEPDB
!IF $(FOR_WIN10)!=0
SQLITE3EXEPDB =
!ELSE
SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
!ENDIF
!ENDIF
# These are the "standard" SQLite compilation options used when compiling for
# the Windows platform.
@@ -256,8 +240,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
#
!IFNDEF EXT_FEATURE_FLAGS
!IF $(FOR_WIN10)!=0
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_STAT4=1
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1
EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_OMIT_LOCALTIME=1
@@ -270,15 +252,6 @@ EXT_FEATURE_FLAGS =
############################### END OF OPTIONS ################################
###############################################################################
# When compiling for the Windows 10 platform, the PLATFORM macro must be set
# to an appropriate value (e.g. x86, x64, arm, arm64, etc).
#
!IF $(FOR_WIN10)!=0
!IFNDEF PLATFORM
!ERROR Using the FOR_WIN10 option requires a value for PLATFORM.
!ENDIF
!ENDIF
# This assumes that MSVC is always installed in 32-bit Program Files directory
# and sets the variable for use in locating other 32-bit installs accordingly.
#
@@ -293,14 +266,6 @@ PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\)
CC = cl.exe
!ENDIF
# Check for the predefined command macro CSC. This should point to a working
# C Sharp compiler binary. If it is not defined, simply define it to the
# legacy default value 'csc.exe'.
#
!IFNDEF CSC
CSC = csc.exe
!ENDIF
# Check for the command macro LD. This should point to the linker binary for
# the target platform. If it is not defined, simply define it to the legacy
# default value 'link.exe'.
@@ -317,7 +282,7 @@ LD = link.exe
RC = rc.exe
!ENDIF
# Check for the MSVC runtime library path macro. Otherwise, this value will
# Check for the MSVC runtime library path macro. Othertise, this value will
# default to the 'lib' directory underneath the MSVC installation directory.
#
!IFNDEF CRTLIBPATH
@@ -354,7 +319,7 @@ NCC = $(NCC:\\=\)
NCC = $(CC)
!ENDIF
# Check for the MSVC native runtime library path macro. Otherwise,
# Check for the MSVC native runtime library path macro. Othertise,
# this value will default to the 'lib' directory underneath the MSVC
# installation directory.
#
@@ -364,7 +329,7 @@ NCRTLIBPATH = $(VCINSTALLDIR)\lib
NCRTLIBPATH = $(NCRTLIBPATH:\\=\)
# Check for the Platform SDK library path macro. Otherwise, this
# Check for the Platform SDK library path macro. Othertise, this
# value will default to the 'lib' directory underneath the Windows
# SDK installation directory (the environment variable used appears
# to be available when using Visual C++ 2008 or later via the
@@ -376,16 +341,6 @@ NSDKLIBPATH = $(WINDOWSSDKDIR)\lib
NSDKLIBPATH = $(NSDKLIBPATH:\\=\)
# Check for the UCRT library path macro. Otherwise, this value will
# default to the version-specific, platform-specific 'lib' directory
# underneath the Windows SDK installation directory.
#
!IFNDEF UCRTLIBPATH
UCRTLIBPATH = $(WINDOWSSDKDIR)\lib\$(WINDOWSSDKLIBVERSION)\ucrt\$(PLATFORM)
!ENDIF
UCRTLIBPATH = $(UCRTLIBPATH:\\=\)
# C compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
@@ -425,8 +380,17 @@ TCC = $(CC) -nologo -W4 -DINCLUDE_MSVC_H=1 $(CCOPTS) $(TCCOPTS)
TCC = $(CC) -nologo -W3 $(CCOPTS) $(TCCOPTS)
!ENDIF
TCC = $(TCC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -fp:precise
RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) $(RCOPTS) $(RCCOPTS)
TCC = $(TCC) -DSQLITE_OS_WIN=1 -I$(TOP) -fp:precise
RCC = $(RC) -DSQLITE_OS_WIN=1 -I$(TOP) $(RCOPTS) $(RCCOPTS)
# Adjust the names of the primary targets for use with Windows 10.
#
!IF $(FOR_WIN10)!=0
SQLITE3DLL = winsqlite3.dll
SQLITE3LIB = winsqlite3.lib
SQLITE3EXE = winsqlite3shell.exe
SQLITE3EXEPDB =
!ENDIF
# Check if we want to use the "stdcall" calling convention when compiling.
# This is not supported by the compilers for non-x86 platforms. It should
@@ -467,10 +431,8 @@ CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS)
# when linking.
#
!IFNDEF CORE_LINK_DEP
!IF $(DYNAMIC_SHELL)!=0
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
CORE_LINK_DEP =
!ELSEIF $(FOR_WIN10)==0 || "$(PLATFORM)"=="x86"
CORE_LINK_DEP = sqlite3.def
!ELSE
CORE_LINK_DEP =
!ENDIF
@@ -479,10 +441,8 @@ CORE_LINK_DEP =
# These are additional linker options used for the core library.
#
!IFNDEF CORE_LINK_OPTS
!IF $(DYNAMIC_SHELL)!=0
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
CORE_LINK_OPTS =
!ELSEIF $(FOR_WIN10)==0 || "$(PLATFORM)"=="x86"
CORE_LINK_OPTS = /DEF:sqlite3.def
!ELSE
CORE_LINK_OPTS =
!ENDIF
@@ -557,8 +517,8 @@ RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
# C compiler options for the Windows 10 platform (needs MSVC 2015).
#
!IF $(FOR_WIN10)!=0
TCC = $(TCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
TCC = $(TCC) /guard:cf -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
BCC = $(BCC) /guard:cf -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
!ENDIF
# Also, we need to dynamically link to the correct MSVC runtime
@@ -566,7 +526,7 @@ 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 $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
!IF $(FOR_WINRT)!=0 || $(FOR_WIN10)!=0 || $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
@@ -823,10 +783,9 @@ LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelH
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.
# When compiling for UAP, some extra linker options are also required.
#
!IF $(FOR_UWP)!=0 || $(FOR_WIN10)!=0
!IF $(FOR_UAP)!=0 || $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib
LTLINKOPTS = $(LTLINKOPTS) mincore.lib
!IFDEF PSDKLIBPATH
@@ -834,15 +793,6 @@ LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)"
!ENDIF
!ENDIF
!IF $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) /guard:cf "/LIBPATH:$(UCRTLIBPATH)"
!IF $(DEBUG)>1
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrtd.lib /DEFAULTLIB:ucrtd.lib
!ELSE
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
!ENDIF
!ENDIF
# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
@@ -877,35 +827,30 @@ LIBRESOBJS =
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
!ENDIF
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
all: dll shell
all: dll libsqlite3.lib shell
# Dynamic link library section.
#
dll: $(SQLITE3DLL)
dll: $(SQLITE3DLL)
# Shell executable.
#
shell: $(SQLITE3EXE)
shell: $(SQLITE3EXE)
libsqlite3.lib: $(LIBOBJ)
$(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS)
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
Replace.exe:
$(CSC) /target:exe $(TOP)\Replace.cs
sqlite3.def: Replace.exe $(LIBOBJ)
echo EXPORTS > sqlite3.def
dumpbin /all $(LIBOBJ) \
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
| sort >> sqlite3.def
$(SQLITE3EXE): $(TOP)\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
$(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\shell.c $(SHELL_CORE_SRC) \
@@ -944,5 +889,4 @@ $(LIBRESOBJS): $(TOP)\sqlite3.rc rcver.vc $(SQLITE3H)
clean:
del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+10 -10
View File
@@ -1,13 +1,13 @@
This package contains:
* the SQLite library amalgamation source code file: sqlite3.c
* the sqlite3.h and sqlite3ext.h header files that define the C-language
interface to the sqlite3.c library file
* the shell.c file used to build the sqlite3 command-line shell program
* the SQLite library amalgamation (single file) source code distribution,
* the shell.c file used to build the sqlite3 shell too, and
* the sqlite3.h and sqlite3ext.h header files required to link programs
and sqlite extensions against the installed libary.
* autoconf/automake installation infrastucture for building on POSIX
compliant systems
* a Makefile.msc, sqlite3.rc, and Replace.cs for building with Microsoft
Visual C++ on Windows
compliant systems.
* a Makefile.msc and sqlite3.rc for building with Microsoft Visual C++ on
Windows.
SUMMARY OF HOW TO BUILD
=======================
@@ -39,7 +39,7 @@ to produce a smaller installation footprint.
Other SQLite compilation parameters can also be set using CFLAGS. For
example:
$ CFLAGS="-Os -DSQLITE_THREADSAFE=0" ./configure
$ CFLAGS="-Os -DSQLITE_OMIT_TRIGGERS" ./configure
BUILDING WITH MICROSOFT VISUAL C++
@@ -75,10 +75,10 @@ NMAKE command line as well:
"NSDKLIBPATH=%WindowsSdkDir%\..\8.1\lib\winv6.3\um\x86"
Building for UWP 10.0
Building for UAP 10.0
---------------------
FOR_WINRT=1 FOR_UWP=1
FOR_WINRT=1 FOR_UAP=1
Using Microsoft Visual C++ 2015 (or later) is required. When using the
above, something like the following macros will need to be added to the
+1 -1
View File
@@ -130,7 +130,7 @@ AC_ARG_ENABLE(static-shell, [AS_HELP_STRING(
[statically link libsqlite3 into shell tool [default=yes]])],
[], [enable_static_shell=yes])
if test x"$enable_static_shell" == "xyes"; then
EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT
EXTRA_SHELL_OBJ=sqlite3.$OBJEXT
else
EXTRA_SHELL_OBJ=libsqlite3.la
fi
-12
View File
@@ -45,18 +45,6 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the pread() function. */
#undef HAVE_PREAD
/* Define to 1 if you have the pread64() function. */
#undef HAVE_PREAD64
/* Define to 1 if you have the pwrite() function. */
#undef HAVE_PWRITE
/* Define to 1 if you have the pwrite64() function. */
#undef HAVE_PWRITE64
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
Vendored
+10 -10
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.12.2.
# Generated by GNU Autoconf 2.69 for sqlite 3.11.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -726,8 +726,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.12.2'
PACKAGE_STRING='sqlite 3.12.2'
PACKAGE_VERSION='3.11.0'
PACKAGE_STRING='sqlite 3.11.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1460,7 +1460,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.12.2 to adapt to many kinds of systems.
\`configure' configures sqlite 3.11.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1525,7 +1525,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.12.2:";;
short | recursive ) echo "Configuration of sqlite 3.11.0:";;
esac
cat <<\_ACEOF
@@ -1646,7 +1646,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.12.2
sqlite configure 3.11.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2065,7 +2065,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.12.2, which was
It was created by sqlite $as_me 3.11.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -10273,7 +10273,7 @@ done
#########
# Figure out whether or not we have these functions
#
for ac_func in fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64
for ac_func in fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -12079,7 +12079,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.12.2, which was
This file was extended by sqlite $as_me 3.11.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12145,7 +12145,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
sqlite config.status 3.12.2
sqlite config.status 3.11.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
+1 -1
View File
@@ -108,7 +108,7 @@ AC_CHECK_HEADERS([sys/types.h stdlib.h stdint.h inttypes.h malloc.h])
#########
# Figure out whether or not we have these functions
#
AC_CHECK_FUNCS([fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64])
AC_CHECK_FUNCS([fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime])
#########
# By default, we use the amalgamation (this may be changed below...)
+98 -193
View File
@@ -5,17 +5,14 @@
<body bgcolor=white>
<h1 align=center>The Lemon Parser Generator</h1>
<p>Lemon is an LALR(1) parser generator for C.
It does the same job as "bison" and "yacc".
But lemon is not a bison or yacc clone. Lemon
<p>Lemon is an LALR(1) parser generator for C or C++.
It does the same job as ``bison'' and ``yacc''.
But lemon is not another bison or yacc clone. It
uses a different grammar syntax which is designed to
reduce the number of coding errors. Lemon also uses a
parsing engine that is faster than yacc and
bison and which is both reentrant and threadsafe.
(Update: Since the previous sentence was written, bison
has also been updated so that it too can generate a
reentrant and threadsafe parser.)
Lemon also implements features that can be used
reduce the number of coding errors. Lemon also uses a more
sophisticated parsing engine that is faster than yacc and
bison and which is both reentrant and thread-safe.
Furthermore, Lemon implements features that can be used
to eliminate resource leaks, making is suitable for use
in long-running programs such as graphical user interfaces
or embedded controllers.</p>
@@ -47,18 +44,18 @@ one and three files of outputs.
automaton.
</ul>
By default, all three of these output files are generated.
The header file is suppressed if the "-m" command-line option is
used and the report file is omitted when "-q" is selected.</p>
The header file is suppressed if the ``-m'' command-line option is
used and the report file is omitted when ``-q'' is selected.</p>
<p>The grammar specification file uses a ".y" suffix, by convention.
<p>The grammar specification file uses a ``.y'' suffix, by convention.
In the examples used in this document, we'll assume the name of the
grammar file is "gram.y". A typical use of Lemon would be the
grammar file is ``gram.y''. A typical use of Lemon would be the
following command:
<pre>
lemon gram.y
</pre>
This command will generate three output files named "gram.c",
"gram.h" and "gram.out".
This command will generate three output files named ``gram.c'',
``gram.h'' and ``gram.out''.
The first is C code to implement the parser. The second
is the header file that defines numerical values for all
terminal symbols, and the last is the report that explains
@@ -74,35 +71,39 @@ with a brief explanation of what each does by typing
</pre>
As of this writing, the following command-line options are supported:
<ul>
<li><b>-b</b>
Show only the basis for each parser state in the report file.
<li><b>-c</b>
Do not compress the generated action tables.
<li><b>-D<i>name</i></b>
Define C preprocessor macro <i>name</i>. This macro is useable by
"%ifdef" lines in the grammar file.
<li><b>-g</b>
Do not generate a parser. Instead write the input grammar to standard
output with all comments, actions, and other extraneous text removed.
<li><b>-l</b>
Omit "#line" directives int the generated parser C code.
<li><b>-m</b>
Cause the output C source code to be compatible with the "makeheaders"
program.
<li><b>-p</b>
Display all conflicts that are resolved by
<a href='#precrules'>precedence rules</a>.
<li><b>-q</b>
Suppress generation of the report file.
<li><b>-r</b>
Do not sort or renumber the parser states as part of optimization.
<li><b>-s</b>
Show parser statistics before existing.
<li><b>-T<i>file</i></b>
Use <i>file</i> as the template for the generated C-code parser implementation.
<li><b>-x</b>
Print the Lemon version number.
<li><tt>-b</tt>
<li><tt>-c</tt>
<li><tt>-g</tt>
<li><tt>-m</tt>
<li><tt>-q</tt>
<li><tt>-s</tt>
<li><tt>-x</tt>
</ul>
The ``-b'' option reduces the amount of text in the report file by
printing only the basis of each parser state, rather than the full
configuration.
The ``-c'' option suppresses action table compression. Using -c
will make the parser a little larger and slower but it will detect
syntax errors sooner.
The ``-g'' option causes no output files to be generated at all.
Instead, the input grammar file is printed on standard output but
with all comments, actions and other extraneous text deleted. This
is a useful way to get a quick summary of a grammar.
The ``-m'' option causes the output C source file to be compatible
with the ``makeheaders'' program.
Makeheaders is a program that automatically generates header files
from C source code. When the ``-m'' option is used, the header
file is not output since the makeheaders program will take care
of generated all header files automatically.
The ``-q'' option suppresses the report file.
Using ``-s'' causes a brief summary of parser statistics to be
printed. Like this:
<pre>
Parser statistics: 74 terminals, 70 nonterminals, 179 rules
340 states, 2026 parser table entries, 0 conflicts
</pre>
Finally, the ``-x'' option causes Lemon to print its version number
and then stops without attempting to read the grammar or generate a parser.</p>
<h3>The Parser Interface</h3>
@@ -120,12 +121,12 @@ A new parser is created as follows:
</pre>
The ParseAlloc() routine allocates and initializes a new parser and
returns a pointer to it.
The actual data structure used to represent a parser is opaque &mdash;
The actual data structure used to represent a parser is opaque --
its internal structure is not visible or usable by the calling routine.
For this reason, the ParseAlloc() routine returns a pointer to void
rather than a pointer to some particular structure.
The sole argument to the ParseAlloc() routine is a pointer to the
subroutine used to allocate memory. Typically this means malloc().</p>
subroutine used to allocate memory. Typically this means ``malloc()''.</p>
<p>After a program is finished using a parser, it can reclaim all
memory allocated by that parser by calling
@@ -150,19 +151,18 @@ type of the next token in the data stream.
There is one token type for each terminal symbol in the grammar.
The gram.h file generated by Lemon contains #define statements that
map symbolic terminal symbol names into appropriate integer values.
A value of 0 for the second argument is a special flag to the
parser to indicate that the end of input has been reached.
(A value of 0 for the second argument is a special flag to the
parser to indicate that the end of input has been reached.)
The third argument is the value of the given token. By default,
the type of the third argument is integer, but the grammar will
usually redefine this type to be some kind of structure.
Typically the second argument will be a broad category of tokens
such as "identifier" or "number" and the third argument will
such as ``identifier'' or ``number'' and the third argument will
be the name of the identifier or the value of the number.</p>
<p>The Parse() function may have either three or four arguments,
depending on the grammar. If the grammar specification file requests
it (via the <a href='#extraarg'><tt>extra_argument</tt> directive</a>),
the Parse() function will have a fourth parameter that can be
depending on the grammar. If the grammar specification file request
it, the Parse() function will have a fourth parameter that can be
of any type chosen by the programmer. The parser doesn't do anything
with this argument except to pass it through to action routines.
This is a convenient mechanism for passing state information down
@@ -192,7 +192,7 @@ following:
</pre>
This example shows a user-written routine that parses a file of
text and returns a pointer to the parse tree.
(All error-handling code is omitted from this example to keep it
(We've omitted all error-handling from this example to keep it
simple.)
We assume the existence of some kind of tokenizer which is created
using TokenizerCreate() on line 8 and deleted by TokenizerFree()
@@ -263,12 +263,6 @@ with prior yacc and bison experience.
But after years of experience using Lemon, I firmly
believe that the Lemon way of doing things is better.</p>
<p><i>Updated as of 2016-02-16:</i>
The text above was written in the 1990s.
We are told that Bison has lately been enhanced to support the
tokenizer-calls-parser paradigm used by Lemon, and to obviate the
need for global variables.</p>
<h2>Input File Syntax</h2>
<p>The main purpose of the grammar specification file for Lemon is
@@ -286,7 +280,7 @@ tokens) and it honors the same commenting conventions as C and C++.</p>
<h3>Terminals and Nonterminals</h3>
<p>A terminal symbol (token) is any string of alphanumeric
and/or underscore characters
and underscore characters
that begins with an upper case letter.
A terminal can contain lowercase letters after the first character,
but the usual convention is to make terminals all upper case.
@@ -313,7 +307,7 @@ must have alphanumeric names.</p>
<p>The main component of a Lemon grammar file is a sequence of grammar
rules.
Each grammar rule consists of a nonterminal symbol followed by
the special symbol "::=" and then a list of terminals and/or nonterminals.
the special symbol ``::='' and then a list of terminals and/or nonterminals.
The rule is terminated by a period.
The list of terminals and nonterminals on the right-hand side of the
rule can be empty.
@@ -329,9 +323,9 @@ A typical sequence of grammar rules might look something like this:
</pre>
</p>
<p>There is one non-terminal in this example, "expr", and five
terminal symbols or tokens: "PLUS", "TIMES", "LPAREN",
"RPAREN" and "VALUE".</p>
<p>There is one non-terminal in this example, ``expr'', and five
terminal symbols or tokens: ``PLUS'', ``TIMES'', ``LPAREN'',
``RPAREN'' and ``VALUE''.</p>
<p>Like yacc and bison, Lemon allows the grammar to specify a block
of C code that will be executed whenever a grammar rule is reduced
@@ -347,15 +341,15 @@ For example:
<p>In order to be useful, grammar actions must normally be linked to
their associated grammar rules.
In yacc and bison, this is accomplished by embedding a "$$" in the
In yacc and bison, this is accomplished by embedding a ``$$'' in the
action to stand for the value of the left-hand side of the rule and
symbols "$1", "$2", and so forth to stand for the value of
symbols ``$1'', ``$2'', and so forth to stand for the value of
the terminal or nonterminal at position 1, 2 and so forth on the
right-hand side of the rule.
This idea is very powerful, but it is also very error-prone. The
single most common source of errors in a yacc or bison grammar is
to miscount the number of symbols on the right-hand side of a grammar
rule and say "$7" when you really mean "$8".</p>
rule and say ``$7'' when you really mean ``$8''.</p>
<p>Lemon avoids the need to count grammar symbols by assigning symbolic
names to each symbol in a grammar rule and then using those symbolic
@@ -385,7 +379,7 @@ For example, the rule
<pre>
expr(A) ::= expr(B) PLUS expr(C). { A = B; }
</pre>
will generate an error because the linking symbol "C" is used
will generate an error because the linking symbol ``C'' is used
in the grammar rule but not in the reduce action.</p>
<p>The Lemon notation for linking grammar rules to reduce actions
@@ -393,7 +387,6 @@ also facilitates the use of destructors for reclaiming memory
allocated by the values of terminals and nonterminals on the
right-hand side of a rule.</p>
<a name='precrules'></a>
<h3>Precedence Rules</h3>
<p>Lemon resolves parsing ambiguities in exactly the same way as
@@ -405,10 +398,7 @@ whichever rule comes first in the grammar file.</p>
yacc and bison, Lemon allows a measure of control
over the resolution of paring conflicts using precedence rules.
A precedence value can be assigned to any terminal symbol
using the
<a href='#pleft'>%left</a>,
<a href='#pright'>%right</a> or
<a href='#pnonassoc'>%nonassoc</a> directives. Terminal symbols
using the %left, %right or %nonassoc directives. Terminal symbols
mentioned in earlier directives have a lower precedence that
terminal symbols mentioned in later directives. For example:</p>
@@ -528,11 +518,7 @@ other than that, the order of directives in Lemon is arbitrary.</p>
<li><tt>%default_destructor</tt>
<li><tt>%default_type</tt>
<li><tt>%destructor</tt>
<li><tt>%endif</tt>
<li><tt>%extra_argument</tt>
<li><tt>%fallback</tt>
<li><tt>%ifdef</tt>
<li><tt>%ifndef</tt>
<li><tt>%include</tt>
<li><tt>%left</tt>
<li><tt>%name</tt>
@@ -544,57 +530,49 @@ other than that, the order of directives in Lemon is arbitrary.</p>
<li><tt>%stack_size</tt>
<li><tt>%start_symbol</tt>
<li><tt>%syntax_error</tt>
<li><tt>%token_class</tt>
<li><tt>%token_destructor</tt>
<li><tt>%token_prefix</tt>
<li><tt>%token_type</tt>
<li><tt>%type</tt>
<li><tt>%wildcard</tt>
</ul>
Each of these directives will be described separately in the
following sections:</p>
<a name='pcode'></a>
<h4>The <tt>%code</tt> directive</h4>
<p>The %code directive is used to specify addition C code that
<p>The %code directive is used to specify addition C/C++ code that
is added to the end of the main output file. This is similar to
the <a href='#pinclude'>%include</a> directive except that %include
is inserted at the beginning of the main output file.</p>
the %include directive except that %include is inserted at the
beginning of the main output file.</p>
<p>%code is typically used to include some action routines or perhaps
a tokenizer or even the "main()" function
as part of the output file.</p>
a tokenizer as part of the output file.</p>
<a name='default_destructor'></a>
<h4>The <tt>%default_destructor</tt> directive</h4>
<p>The %default_destructor directive specifies a destructor to
use for non-terminals that do not have their own destructor
specified by a separate %destructor directive. See the documentation
on the <a name='#destructor'>%destructor</a> directive below for
additional information.</p>
on the %destructor directive below for additional information.</p>
<p>In some grammers, many different non-terminal symbols have the
same datatype and hence the same destructor. This directive is
a convenience way to specify the same destructor for all those
non-terminals using a single statement.</p>
<a name='default_type'></a>
<h4>The <tt>%default_type</tt> directive</h4>
<p>The %default_type directive specifies the datatype of non-terminal
symbols that do no have their own datatype defined using a separate
<a href='#ptype'>%type</a> directive.
</p>
%type directive. See the documentation on %type below for addition
information.</p>
<a name='destructor'></a>
<h4>The <tt>%destructor</tt> directive</h4>
<p>The %destructor directive is used to specify a destructor for
a non-terminal symbol.
(See also the <a href='#token_destructor'>%token_destructor</a>
directive which is used to specify a destructor for terminal symbols.)</p>
(See also the %token_destructor directive which is used to
specify a destructor for terminal symbols.)</p>
<p>A non-terminal's destructor is called to dispose of the
non-terminal's value whenever the non-terminal is popped from
@@ -617,28 +595,28 @@ or other resources held by that non-terminal.</p>
</pre>
This example is a bit contrived but it serves to illustrate how
destructors work. The example shows a non-terminal named
"nt" that holds values of type "void*". When the rule for
an "nt" reduces, it sets the value of the non-terminal to
``nt'' that holds values of type ``void*''. When the rule for
an ``nt'' reduces, it sets the value of the non-terminal to
space obtained from malloc(). Later, when the nt non-terminal
is popped from the stack, the destructor will fire and call
free() on this malloced space, thus avoiding a memory leak.
(Note that the symbol "$$" in the destructor code is replaced
(Note that the symbol ``$$'' in the destructor code is replaced
by the value of the non-terminal.)</p>
<p>It is important to note that the value of a non-terminal is passed
to the destructor whenever the non-terminal is removed from the
stack, unless the non-terminal is used in a C-code action. If
the non-terminal is used by C-code, then it is assumed that the
C-code will take care of destroying it.
More commonly, the value is used to build some
C-code will take care of destroying it if it should really
be destroyed. More commonly, the value is used to build some
larger structure and we don't want to destroy it, which is why
the destructor is not called in this circumstance.</p>
<p>Destructors help avoid memory leaks by automatically freeing
allocated objects when they go out of scope.
<p>By appropriate use of destructors, it is possible to
build a parser using Lemon that can be used within a long-running
program, such as a GUI, that will not leak memory or other resources.
To do the same using yacc or bison is much more difficult.</p>
<a name="extraarg"></a>
<h4>The <tt>%extra_argument</tt> directive</h4>
The %extra_argument directive instructs Lemon to add a 4th parameter
@@ -652,66 +630,17 @@ and so forth. For example, if the grammar file contains:</p>
</pre></p>
<p>Then the Parse() function generated will have an 4th parameter
of type "MyStruct*" and all action routines will have access to
a variable named "pAbc" that is the value of the 4th parameter
of type ``MyStruct*'' and all action routines will have access to
a variable named ``pAbc'' that is the value of the 4th parameter
in the most recent call to Parse().</p>
<a name='pfallback'></a>
<h4>The <tt>%fallback</tt> directive</h4>
<p>The %fallback directive specifies an alternative meaning for one
or more tokens. The alternative meaning is tried if the original token
would have generated a syntax error.
<p>The %fallback directive was added to support robust parsing of SQL
syntax in <a href="https://www.sqlite.org/">SQLite</a>.
The SQL language contains a large assortment of keywords, each of which
appears as a different token to the language parser. SQL contains so
many keywords, that it can be difficult for programmers to keep up with
them all. Programmers will, therefore, sometimes mistakenly use an
obscure language keyword for an identifier. The %fallback directive
provides a mechanism to tell the parser: "If you are unable to parse
this keyword, try treating it as an identifier instead."
<p>The syntax of %fallback is as follows:
<blockquote>
<tt>%fallback</tt> <i>ID</i> <i>TOKEN...</i> <b>.</b>
</blockquote>
<p>In words, the %fallback directive is followed by a list of token names
terminated by a period. The first token name is the fallback token - the
token to which all the other tokens fall back to. The second and subsequent
arguments are tokens which fall back to the token identified by the first
argument.
<a name='pifdef'></a>
<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives.</h4>
<p>The %ifdef, %ifndef, and %endif directives are similar to
#ifdef, #ifndef, and #endif in the C-preprocessor, just not as general.
Each of these directives must begin at the left margin. No whitespace
is allowed between the "%" and the directive name.
<p>Grammar text in between "%ifdef MACRO" and the next nested "%endif" is
ignored unless the "-DMACRO" command-line option is used. Grammar text
betwen "%ifndef MACRO" and the next nested "%endif" is included except when
the "-DMACRO" command-line option is used.
<p>Note that the argument to %ifdef and %ifndef must be a single
preprocessor symbol name, not a general expression. There is no "%else"
directive.
<a name='pinclude'></a>
<h4>The <tt>%include</tt> directive</h4>
<p>The %include directive specifies C code that is included at the
top of the generated parser. You can include any text you want --
the Lemon parser generator copies it blindly. If you have multiple
%include directives in your grammar file, their values are concatenated
so that all %include code ultimately appears near the top of the
generated parser, in the same order as it appeared in the grammer.</p>
%include directives in your grammar file the value of the last
%include directive overwrites all the others.</p.
<p>The %include directive is very handy for getting some extra #include
preprocessor statements at the beginning of the generated parser.
@@ -724,13 +653,12 @@ For example:</p>
<p>This might be needed, for example, if some of the C actions in the
grammar call functions that are prototyed in unistd.h.</p>
<a name='pleft'></a>
<h4>The <tt>%left</tt> directive</h4>
The %left directive is used (along with the <a href='#pright'>%right</a> and
<a href='#pnonassoc'>%nonassoc</a> directives) to declare precedences of
terminal symbols. Every terminal symbol whose name appears after
a %left directive but before the next period (".") is
The %left directive is used (along with the %right and
%nonassoc directives) to declare precedences of terminal
symbols. Every terminal symbol whose name appears after
a %left directive but before the next period (``.'') is
given the same left-associative precedence value. Subsequent
%left directives have higher precedence. For example:</p>
@@ -751,11 +679,10 @@ a large amount of stack space if you make heavy use or right-associative
operators. For this reason, it is recommended that you use %left
rather than %right whenever possible.</p>
<a name='pname'></a>
<h4>The <tt>%name</tt> directive</h4>
<p>By default, the functions generated by Lemon all begin with the
five-character string "Parse". You can change this string to something
five-character string ``Parse''. You can change this string to something
different using the %name directive. For instance:</p>
<p><pre>
@@ -774,19 +701,16 @@ The %name directive allows you to generator two or more different
parsers and link them all into the same executable.
</p>
<a name='pnonassoc'></a>
<h4>The <tt>%nonassoc</tt> directive</h4>
<p>This directive is used to assign non-associative precedence to
one or more terminal symbols. See the section on
<a href='#precrules'>precedence rules</a>
or on the <a href='#pleft'>%left</a> directive for additional information.</p>
one or more terminal symbols. See the section on precedence rules
or on the %left directive for additional information.</p>
<a name='parse_accept'></a>
<h4>The <tt>%parse_accept</tt> directive</h4>
<p>The %parse_accept directive specifies a block of C code that is
executed whenever the parser accepts its input string. To "accept"
executed whenever the parser accepts its input string. To ``accept''
an input string means that the parser was able to process all tokens
without error.</p>
@@ -798,7 +722,7 @@ without error.</p>
}
</pre></p>
<a name='parse_failure'></a>
<h4>The <tt>%parse_failure</tt> directive</h4>
<p>The %parse_failure directive specifies a block of C code that
@@ -813,15 +737,12 @@ only invoked when parsing is unable to continue.</p>
}
</pre></p>
<a name='pright'></a>
<h4>The <tt>%right</tt> directive</h4>
<p>This directive is used to assign right-associative precedence to
one or more terminal symbols. See the section on
<a href='#precrules'>precedence rules</a>
or on the <a href='#pleft'>%left</a> directive for additional information.</p>
one or more terminal symbols. See the section on precedence rules
or on the %left directive for additional information.</p>
<a name='stack_overflow'></a>
<h4>The <tt>%stack_overflow</tt> directive</h4>
<p>The %stack_overflow directive specifies a block of C code that
@@ -850,7 +771,6 @@ Not like this:
list ::= .
</pre>
<a name='stack_size'></a>
<h4>The <tt>%stack_size</tt> directive</h4>
<p>If stack overflow is a problem and you can't resolve the trouble
@@ -863,7 +783,6 @@ with a stack of the requested size. The default value is 100.</p>
%stack_size 2000
</pre></p>
<a name='start_symbol'></a>
<h4>The <tt>%start_symbol</tt> directive</h4>
<p>By default, the start-symbol for the grammar that Lemon generates
@@ -874,7 +793,6 @@ can choose a different start-symbol using the %start_symbol directive.</p>
%start_symbol prog
</pre></p>
<a name='token_destructor'></a>
<h4>The <tt>%token_destructor</tt> directive</h4>
<p>The %destructor directive assigns a destructor to a non-terminal
@@ -887,7 +805,6 @@ the %token_type directive) and so they use a common destructor. Other
than that, the token destructor works just like the non-terminal
destructors.</p>
<a name='token_prefix'></a>
<h4>The <tt>%token_prefix</tt> directive</h4>
<p>Lemon generates #defines that assign small integer constants
@@ -913,7 +830,6 @@ to cause Lemon to produce these symbols instead:
#define TOKEN_PLUS 4
</pre>
<a name='token_type'></a><a name='ptype'></a>
<h4>The <tt>%token_type</tt> and <tt>%type</tt> directives</h4>
<p>These directives are used to specify the data types for values
@@ -929,7 +845,7 @@ token structure. Like this:</p>
</pre></p>
<p>If the data type of terminals is not specified, the default value
is "int".</p>
is ``int''.</p>
<p>Non-terminal symbols can each have their own data types. Typically
the data type of a non-terminal is a pointer to the root of a parse-tree
@@ -950,17 +866,6 @@ non-terminal whose data type requires 1K of storage, then your 100
entry parser stack will require 100K of heap space. If you are willing
and able to pay that price, fine. You just need to know.</p>
<a name='pwildcard'></a>
<h4>The <tt>%wildcard</tt> directive</h4>
<p>The %wildcard directive is followed by a single token name and a
period. This directive specifies that the identified token should
match any input token.
<p>When the generated parser has the choice of matching an input against
the wildcard token and some other token, the other token is always used.
The wildcard token is only matched if there are no other alternatives.
<h3>Error Processing</h3>
<p>After extensive experimentation over several years, it has been
@@ -972,7 +877,7 @@ first invokes the code specified by the %syntax_error directive, if
any. It then enters its error recovery strategy. The error recovery
strategy is to begin popping the parsers stack until it enters a
state where it is permitted to shift a special non-terminal symbol
named "error". It then shifts this non-terminal and continues
named ``error''. It then shifts this non-terminal and continues
parsing. But the %syntax_error routine will not be called again
until at least three new tokens have been successfully shifted.</p>
@@ -981,7 +886,7 @@ is unable to shift the error symbol, then the %parse_failed routine
is invoked and the parser resets itself to its start state, ready
to begin parsing a new file. This is what will happen at the very
first syntax error, of course, if there are no instances of the
"error" non-terminal in your grammar.</p>
``error'' non-terminal in your grammar.</p>
</body>
</html>
-6
View File
@@ -18,12 +18,6 @@
# define NDEBUG 1
#endif
/* FTS3/FTS4 require virtual tables */
#ifdef SQLITE_OMIT_VIRTUALTABLE
# undef SQLITE_ENABLE_FTS3
# undef SQLITE_ENABLE_FTS4
#endif
/*
** FTS4 is really an extension for FTS3. It is enabled using the
** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all
+1 -2
View File
@@ -526,8 +526,7 @@ static int fts3_test_varint_cmd(
#ifdef SQLITE_ENABLE_FTS3
char aBuf[24];
int rc;
Tcl_WideInt w;
sqlite3_int64 w2;
Tcl_WideInt w, w2;
int nByte, nByte2;
if( objc!=2 ){
+20 -38
View File
@@ -29,18 +29,6 @@
#include <assert.h>
#include <string.h>
/*
** Return true if the two-argument version of fts3_tokenizer()
** has been activated via a prior call to sqlite3_db_config(db,
** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
*/
static int fts3TokenizerEnabled(sqlite3_context *context){
sqlite3 *db = sqlite3_context_db_handle(context);
int isEnabled = 0;
sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled);
return isEnabled;
}
/*
** Implementation of the SQL scalar function for accessing the underlying
** hash table. This function may be called as follows:
@@ -61,7 +49,7 @@ static int fts3TokenizerEnabled(sqlite3_context *context){
** is a blob containing the pointer stored as the hash data corresponding
** to string <key-name> (after the hash-table is updated, if applicable).
*/
static void fts3TokenizerFunc(
static void scalarFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
@@ -79,20 +67,16 @@ static void fts3TokenizerFunc(
nName = sqlite3_value_bytes(argv[0])+1;
if( argc==2 ){
if( fts3TokenizerEnabled(context) ){
void *pOld;
int n = sqlite3_value_bytes(argv[1]);
if( zName==0 || n!=sizeof(pPtr) ){
sqlite3_result_error(context, "argument type mismatch", -1);
return;
}
pPtr = *(void **)sqlite3_value_blob(argv[1]);
pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
if( pOld==pPtr ){
sqlite3_result_error(context, "out of memory", -1);
}
}else{
sqlite3_result_error(context, "fts3tokenize disabled", -1);
void *pOld;
int n = sqlite3_value_bytes(argv[1]);
if( zName==0 || n!=sizeof(pPtr) ){
sqlite3_result_error(context, "argument type mismatch", -1);
return;
}
pPtr = *(void **)sqlite3_value_blob(argv[1]);
pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
if( pOld==pPtr ){
sqlite3_result_error(context, "out of memory", -1);
return;
}
}else{
@@ -106,6 +90,7 @@ static void fts3TokenizerFunc(
return;
}
}
sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
}
@@ -365,7 +350,6 @@ int registerTokenizer(
return sqlite3_finalize(pStmt);
}
static
int queryTokenizer(
sqlite3 *db,
@@ -436,13 +420,11 @@ static void intTestFunc(
assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );
/* Test the storage function */
if( fts3TokenizerEnabled(context) ){
rc = registerTokenizer(db, "nosuchtokenizer", p1);
assert( rc==SQLITE_OK );
rc = queryTokenizer(db, "nosuchtokenizer", &p2);
assert( rc==SQLITE_OK );
assert( p2==p1 );
}
rc = registerTokenizer(db, "nosuchtokenizer", p1);
assert( rc==SQLITE_OK );
rc = queryTokenizer(db, "nosuchtokenizer", &p2);
assert( rc==SQLITE_OK );
assert( p2==p1 );
sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
}
@@ -458,7 +440,7 @@ static void intTestFunc(
** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
**
** This function adds a scalar function (see header comment above
** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is
** scalarFunc() in this file for details) and, if ENABLE_TABLE is
** defined at compilation time, a temporary virtual table (see header
** comment above struct HashTableVtab) to the database schema. Both
** provide read/write access to the contents of *pHash.
@@ -487,10 +469,10 @@ int sqlite3Fts3InitHashTable(
#endif
if( SQLITE_OK==rc ){
rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0);
rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
}
if( SQLITE_OK==rc ){
rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0);
rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
}
#ifdef SQLITE_TEST
if( SQLITE_OK==rc ){
+4 -6
View File
@@ -333,8 +333,7 @@ static int fts3SqlStmt(
** of the oldest level in the db that contains at least ? segments. Or,
** if no level in the FTS index contains more than ? segments, the statement
** returns zero rows. */
/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
" GROUP BY level HAVING cnt>=?"
/* 28 */ "SELECT level FROM %Q.'%q_segdir' GROUP BY level HAVING count(*)>=?"
" ORDER BY (level %% 1024) ASC LIMIT 1",
/* Estimate the upper limit on the number of leaf nodes in a new segment
@@ -3195,7 +3194,7 @@ static int fts3SegmentMerge(
** segment. The level of the new segment is equal to the numerically
** greatest segment level currently present in the database for this
** index. The idx of the new segment is always 0. */
if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){
if( csr.nSegment==1 ){
rc = SQLITE_DONE;
goto finished;
}
@@ -4837,11 +4836,10 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
** set nSeg to -1.
*/
rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin));
sqlite3_bind_int(pFindLevel, 1, nMin);
if( sqlite3_step(pFindLevel)==SQLITE_ROW ){
iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
nSeg = sqlite3_column_int(pFindLevel, 1);
assert( nSeg>=2 );
nSeg = nMin;
}else{
nSeg = -1;
}
+2 -2
View File
@@ -226,9 +226,9 @@ proc print_isalnum {zFunc lRange} {
an_print_range_array $lRange
an_print_ascii_bitmap $lRange
puts {
if( (unsigned int)c<128 ){
if( c<128 ){
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
}else if( (unsigned int)c<(1<<22) ){
}else if( c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
+13 -35
View File
@@ -26,7 +26,6 @@ SQLITE_EXTENSION_INIT1
typedef unsigned char u8;
typedef unsigned int u32;
typedef unsigned short u16;
typedef short i16;
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
@@ -47,10 +46,6 @@ typedef sqlite3_uint64 u64;
#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
** field that occurs at the start of each leaf page (see fts5_index.c). */
#define FTS5_MAX_TOKEN_SIZE 32768
/*
** Maximum number of prefix indexes on single FTS5 table. This must be
@@ -85,16 +80,6 @@ extern int sqlite3_fts5_may_be_corrupt;
# define assert_nc(x) assert(x)
#endif
/* Mark a function parameter as unused, to suppress nuisance compiler
** warnings. */
#ifndef UNUSED_PARAM
# define UNUSED_PARAM(X) (void)(X)
#endif
#ifndef UNUSED_PARAM2
# define UNUSED_PARAM2(X, Y) (void)(X), (void)(Y)
#endif
typedef struct Fts5Global Fts5Global;
typedef struct Fts5Colset Fts5Colset;
@@ -176,7 +161,6 @@ struct Fts5Config {
int pgsz; /* Approximate page size used in %_data */
int nAutomerge; /* 'automerge' setting */
int nCrisisMerge; /* Maximum allowed segments per level */
int nUsermerge; /* 'usermerge' setting */
int nHashSize; /* Bytes of memory for in-memory hash */
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
@@ -298,7 +282,6 @@ struct Fts5PoslistWriter {
i64 iPrev;
};
int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64);
void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64);
int sqlite3Fts5PoslistNext64(
const u8 *a, int n, /* Buffer containing poslist */
@@ -336,11 +319,8 @@ struct Fts5IndexIter {
i64 iRowid;
const u8 *pData;
int nData;
u8 bEof;
};
#define sqlite3Fts5IterEof(x) ((x)->bEof)
/*
** Values used as part of the flags argument passed to IndexQuery().
*/
@@ -349,18 +329,22 @@ struct Fts5IndexIter {
#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
/* The following are used internally by the fts5_index.c module. They are
** defined here only to make it easier to avoid clashes with the flags
** above. */
#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
/*
** Create/destroy an Fts5Index object.
*/
int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**);
int sqlite3Fts5IndexClose(Fts5Index *p);
/*
** for(
** sqlite3Fts5IndexQuery(p, "token", 5, 0, 0, &pIter);
** 0==sqlite3Fts5IterEof(pIter);
** sqlite3Fts5IterNext(pIter)
** ){
** i64 iRowid = sqlite3Fts5IterRowid(pIter);
** }
*/
/*
** Return a simple checksum value based on the arguments.
*/
@@ -400,8 +384,10 @@ int sqlite3Fts5IndexQuery(
** The various operations on open token or token prefix iterators opened
** using sqlite3Fts5IndexQuery().
*/
int sqlite3Fts5IterEof(Fts5IndexIter*);
int sqlite3Fts5IterNext(Fts5IndexIter*);
int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
i64 sqlite3Fts5IterRowid(Fts5IndexIter*);
/*
** Close an iterator opened by sqlite3Fts5IndexQuery().
@@ -484,7 +470,6 @@ int sqlite3Fts5IndexReads(Fts5Index *p);
int sqlite3Fts5IndexReinit(Fts5Index *p);
int sqlite3Fts5IndexOptimize(Fts5Index *p);
int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
int sqlite3Fts5IndexReset(Fts5Index *p);
int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
@@ -627,7 +612,6 @@ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
int sqlite3Fts5StorageRebuild(Fts5Storage *p);
int sqlite3Fts5StorageOptimize(Fts5Storage *p);
int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
int sqlite3Fts5StorageReset(Fts5Storage *p);
/*
** End of interface to code in fts5_storage.c.
@@ -688,7 +672,7 @@ int sqlite3Fts5ExprPopulatePoslists(
void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64);
void sqlite3Fts5ExprClearEof(Fts5Expr*);
int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**);
int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
@@ -707,12 +691,6 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
Fts5ExprNearset *pNear
);
Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
Fts5Parse *pParse,
Fts5ExprNode *pLeft,
Fts5ExprNode *pRight
);
Fts5ExprPhrase *sqlite3Fts5ParseTerm(
Fts5Parse *pParse,
Fts5ExprPhrase *pPhrase,
-3
View File
@@ -158,8 +158,6 @@ static int fts5HighlightCb(
int rc = SQLITE_OK;
int iPos;
UNUSED_PARAM2(pToken, nToken);
if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
iPos = p->iPos++;
@@ -393,7 +391,6 @@ static int fts5CountCb(
void *pUserData /* Pointer to sqlite3_int64 variable */
){
sqlite3_int64 *pn = (sqlite3_int64*)pUserData;
UNUSED_PARAM2(pApi, pFts);
(*pn)++;
return SQLITE_OK;
}
+27 -39
View File
@@ -16,20 +16,18 @@
#include "fts5Int.h"
int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
if( (u32)pBuf->nSpace<nByte ){
u32 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
u8 *pNew;
while( nNew<nByte ){
nNew = nNew * 2;
}
pNew = sqlite3_realloc(pBuf->p, nNew);
if( pNew==0 ){
*pRc = SQLITE_NOMEM;
return 1;
}else{
pBuf->nSpace = nNew;
pBuf->p = pNew;
}
u32 nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
u8 *pNew;
while( nNew<nByte ){
nNew = nNew * 2;
}
pNew = sqlite3_realloc(pBuf->p, nNew);
if( pNew==0 ){
*pRc = SQLITE_NOMEM;
return 1;
}else{
pBuf->nSpace = nNew;
pBuf->p = pNew;
}
return 0;
}
@@ -210,36 +208,23 @@ int sqlite3Fts5PoslistReaderInit(
return pIter->bEof;
}
/*
** Append position iPos to the position list being accumulated in buffer
** pBuf, which must be already be large enough to hold the new data.
** The previous position written to this list is *piPrev. *piPrev is set
** to iPos before returning.
*/
void sqlite3Fts5PoslistSafeAppend(
Fts5Buffer *pBuf,
i64 *piPrev,
i64 iPos
){
static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
if( (iPos & colmask) != (*piPrev & colmask) ){
pBuf->p[pBuf->n++] = 1;
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
*piPrev = (iPos & colmask);
}
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
*piPrev = iPos;
}
int sqlite3Fts5PoslistWriterAppend(
Fts5Buffer *pBuf,
Fts5PoslistWriter *pWriter,
i64 iPos
){
int rc = 0; /* Initialized only to suppress erroneous warning from Clang */
if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc;
sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos);
return SQLITE_OK;
static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
int rc = SQLITE_OK;
if( 0==fts5BufferGrow(&rc, pBuf, 5+5+5) ){
if( (iPos & colmask) != (pWriter->iPrev & colmask) ){
pBuf->p[pBuf->n++] = 1;
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
pWriter->iPrev = (iPos & colmask);
}
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-pWriter->iPrev)+2);
pWriter->iPrev = iPos;
}
return rc;
}
void *sqlite3Fts5MallocZero(int *pRc, int nByte){
@@ -390,3 +375,6 @@ void sqlite3Fts5TermsetFree(Fts5Termset *p){
sqlite3_free(p);
}
}
+3 -18
View File
@@ -18,7 +18,6 @@
#define FTS5_DEFAULT_PAGE_SIZE 4050
#define FTS5_DEFAULT_AUTOMERGE 4
#define FTS5_DEFAULT_USERMERGE 4
#define FTS5_DEFAULT_CRISISMERGE 16
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
@@ -207,7 +206,7 @@ static int fts5ConfigSetEnum(
const char *zEnum,
int *peVal
){
int nEnum = (int)strlen(zEnum);
int nEnum = strlen(zEnum);
int i;
int iVal = -1;
@@ -442,9 +441,7 @@ static const char *fts5ConfigGobbleWord(
*pbQuoted = 1;
}else{
zRet = fts5ConfigSkipBareword(zIn);
if( zRet ){
zOut[zRet-zIn] = '\0';
}
zOut[zRet-zIn] = '\0';
}
}
@@ -860,18 +857,6 @@ int sqlite3Fts5ConfigSetValue(
}
}
else if( 0==sqlite3_stricmp(zKey, "usermerge") ){
int nUsermerge = -1;
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
nUsermerge = sqlite3_value_int(pVal);
}
if( nUsermerge<2 || nUsermerge>16 ){
*pbBadkey = 1;
}else{
pConfig->nUsermerge = nUsermerge;
}
}
else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){
int nCrisisMerge = -1;
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
@@ -918,7 +903,6 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
/* Set default values */
pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE;
pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE;
pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
@@ -959,3 +943,4 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
}
return rc;
}
+401 -550
View File
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -62,10 +62,10 @@ struct Fts5HashEntry {
int nAlloc; /* Total size of allocation */
int iSzPoslist; /* Offset of space for 4-byte poslist size */
int nData; /* Total bytes of data (incl. structure) */
int nKey; /* Length of zKey[] in bytes */
u8 bDel; /* Set delete-flag @ iSzPoslist */
u8 bContent; /* Set content-flag (detail=none mode) */
i16 iCol; /* Column of last value written */
int iCol; /* Column of last value written */
int iPos; /* Position of last value written */
i64 iRowid; /* Rowid of last value written */
char zKey[8]; /* Nul-terminated entry key */
@@ -245,8 +245,8 @@ int sqlite3Fts5HashWrite(
iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
if( p->zKey[0]==bByte
&& p->nKey==nToken
&& memcmp(&p->zKey[1], pToken, nToken)==0
&& p->zKey[nToken+1]==0
){
break;
}
@@ -273,7 +273,6 @@ int sqlite3Fts5HashWrite(
p->zKey[0] = bByte;
memcpy(&p->zKey[1], pToken, nToken);
assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
p->nKey = nToken;
p->zKey[nToken+1] = '\0';
p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
p->pHashNext = pHash->aSlot[iHash];
+788 -948
View File
File diff suppressed because it is too large Load Diff
+39 -74
View File
@@ -220,10 +220,10 @@ struct Fts5Cursor {
/*
** Values for Fts5Cursor.csrflags
*/
#define FTS5CSR_EOF 0x01
#define FTS5CSR_REQUIRE_CONTENT 0x02
#define FTS5CSR_REQUIRE_DOCSIZE 0x04
#define FTS5CSR_REQUIRE_INST 0x08
#define FTS5CSR_REQUIRE_CONTENT 0x01
#define FTS5CSR_REQUIRE_DOCSIZE 0x02
#define FTS5CSR_REQUIRE_INST 0x04
#define FTS5CSR_EOF 0x08
#define FTS5CSR_FREE_ZRANK 0x10
#define FTS5CSR_REQUIRE_RESEEK 0x20
#define FTS5CSR_REQUIRE_POSLIST 0x40
@@ -597,38 +597,27 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
return SQLITE_OK;
}
static int fts5NewTransaction(Fts5Table *pTab){
Fts5Cursor *pCsr;
for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
}
return sqlite3Fts5StorageReset(pTab->pStorage);
}
/*
** Implementation of xOpen method.
*/
static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
Fts5Table *pTab = (Fts5Table*)pVTab;
Fts5Config *pConfig = pTab->pConfig;
Fts5Cursor *pCsr = 0; /* New cursor object */
Fts5Cursor *pCsr; /* New cursor object */
int nByte; /* Bytes of space to allocate */
int rc; /* Return code */
int rc = SQLITE_OK; /* Return code */
rc = fts5NewTransaction(pTab);
if( rc==SQLITE_OK ){
nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
if( pCsr ){
Fts5Global *pGlobal = pTab->pGlobal;
memset(pCsr, 0, nByte);
pCsr->aColumnSize = (int*)&pCsr[1];
pCsr->pNext = pGlobal->pCsr;
pGlobal->pCsr = pCsr;
pCsr->iCsrId = ++pGlobal->iNextId;
}else{
rc = SQLITE_NOMEM;
}
nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
if( pCsr ){
Fts5Global *pGlobal = pTab->pGlobal;
memset(pCsr, 0, nByte);
pCsr->aColumnSize = (int*)&pCsr[1];
pCsr->pNext = pGlobal->pCsr;
pGlobal->pCsr = pCsr;
pCsr->iCsrId = ++pGlobal->iNextId;
}else{
rc = SQLITE_NOMEM;
}
*ppCsr = (sqlite3_vtab_cursor*)pCsr;
return rc;
@@ -789,7 +778,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
*pbSkip = 1;
}
@@ -797,7 +786,6 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
fts5CsrNewrow(pCsr);
if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
CsrFlagSet(pCsr, FTS5CSR_EOF);
*pbSkip = 1;
}
}
return rc;
@@ -814,24 +802,24 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
*/
static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
int rc;
int rc = SQLITE_OK;
assert( (pCsr->ePlan<3)==
(pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
);
assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
if( pCsr->ePlan<3 ){
int bSkip = 0;
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
CsrFlagSet(pCsr, FTS5CSR_EOF);
}
fts5CsrNewrow(pCsr);
}else{
switch( pCsr->ePlan ){
case FTS5_PLAN_SPECIAL: {
CsrFlagSet(pCsr, FTS5CSR_EOF);
rc = SQLITE_OK;
break;
}
@@ -1107,7 +1095,7 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
static int fts5FilterMethod(
sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
int idxNum, /* Strategy index */
const char *zUnused, /* Unused */
const char *idxStr, /* Unused */
int nVal, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
@@ -1125,9 +1113,6 @@ static int fts5FilterMethod(
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
char **pzErrmsg = pConfig->pzErrmsg;
UNUSED_PARAM(zUnused);
UNUSED_PARAM(nVal);
if( pCsr->ePlan ){
fts5FreeCursorComponents(pCsr);
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
@@ -1412,7 +1397,8 @@ static int fts5SpecialInsert(
static int fts5SpecialDelete(
Fts5Table *pTab,
sqlite3_value **apVal
sqlite3_value **apVal,
sqlite3_int64 *piRowid
){
int rc = SQLITE_OK;
int eType1 = sqlite3_value_type(apVal[1]);
@@ -1488,7 +1474,7 @@ static int fts5UpdateMethod(
if( pConfig->eContent!=FTS5_CONTENT_NORMAL
&& 0==sqlite3_stricmp("delete", z)
){
rc = fts5SpecialDelete(pTab, apVal);
rc = fts5SpecialDelete(pTab, apVal, pRowid);
}else{
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
}
@@ -1522,13 +1508,13 @@ static int fts5UpdateMethod(
rc = SQLITE_ERROR;
}
/* DELETE */
/* Case 1: DELETE */
else if( nArg==1 ){
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
}
/* INSERT */
/* Case 2: INSERT */
else if( eType0!=SQLITE_INTEGER ){
/* If this is a REPLACE, first remove the current entry (if any) */
if( eConflict==SQLITE_REPLACE
@@ -1540,7 +1526,7 @@ static int fts5UpdateMethod(
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
/* UPDATE */
/* Case 2: UPDATE */
else{
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
@@ -1590,7 +1576,6 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
*/
static int fts5BeginMethod(sqlite3_vtab *pVtab){
fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
fts5NewTransaction((Fts5Table*)pVtab);
return SQLITE_OK;
}
@@ -1600,7 +1585,6 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){
** by fts5SyncMethod().
*/
static int fts5CommitMethod(sqlite3_vtab *pVtab){
UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
return SQLITE_OK;
}
@@ -1854,14 +1838,12 @@ static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
static int fts5ColumnSizeCb(
void *pContext, /* Pointer to int */
int tflags,
const char *pUnused, /* Buffer containing token */
int nUnused, /* Size of token in bytes */
int iUnused1, /* Start offset of token */
int iUnused2 /* End offset of token */
const char *pToken, /* Buffer containing token */
int nToken, /* Size of token in bytes */
int iStart, /* Start offset of token */
int iEnd /* End offset of token */
){
int *pCnt = (int*)pContext;
UNUSED_PARAM2(pUnused, nUnused);
UNUSED_PARAM2(iUnused1, iUnused2);
if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
(*pCnt)++;
}
@@ -1977,11 +1959,10 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
}
static void fts5ApiPhraseNext(
Fts5Context *pUnused,
Fts5Context *pCtx,
Fts5PhraseIter *pIter,
int *piCol, int *piOff
){
UNUSED_PARAM(pUnused);
if( pIter->a>=pIter->b ){
*piCol = -1;
*piOff = -1;
@@ -2133,11 +2114,12 @@ static int fts5ApiQueryPhrase(
rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
if( rc==SQLITE_OK ){
Fts5Config *pConf = pTab->pConfig;
pNew->ePlan = FTS5_PLAN_MATCH;
pNew->iFirstRowid = SMALLEST_INT64;
pNew->iLastRowid = LARGEST_INT64;
pNew->base.pVtab = (sqlite3_vtab*)pTab;
rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr);
rc = sqlite3Fts5ExprClonePhrase(pConf, pCsr->pExpr, iPhrase, &pNew->pExpr);
}
if( rc==SQLITE_OK ){
@@ -2350,7 +2332,7 @@ static int fts5ColumnMethod(
*/
static int fts5FindFunctionMethod(
sqlite3_vtab *pVtab, /* Virtual table handle */
int nUnused, /* Number of SQL function arguments */
int nArg, /* Number of SQL function arguments */
const char *zName, /* Name of SQL function */
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
void **ppArg /* OUT: User data for *pxFunc */
@@ -2358,7 +2340,6 @@ static int fts5FindFunctionMethod(
Fts5Table *pTab = (Fts5Table*)pVtab;
Fts5Auxiliary *pAux;
UNUSED_PARAM(nUnused);
pAux = fts5FindAuxiliary(pTab, zName);
if( pAux ){
*pxFunc = fts5ApiCallback;
@@ -2388,7 +2369,6 @@ static int fts5RenameMethod(
*/
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5Table *pTab = (Fts5Table*)pVtab;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
fts5TripCursors(pTab);
return sqlite3Fts5StorageSync(pTab->pStorage, 0);
@@ -2401,7 +2381,6 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
*/
static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5Table *pTab = (Fts5Table*)pVtab;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
fts5TripCursors(pTab);
return sqlite3Fts5StorageSync(pTab->pStorage, 0);
@@ -2414,7 +2393,6 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
*/
static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5Table *pTab = (Fts5Table*)pVtab;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
fts5TripCursors(pTab);
return sqlite3Fts5StorageRollback(pTab->pStorage);
@@ -2594,11 +2572,10 @@ static void fts5ModuleDestroy(void *pCtx){
static void fts5Fts5Func(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
sqlite3_value **apVal /* Function arguments */
){
Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
char buf[8];
UNUSED_PARAM2(nArg, apUnused);
assert( nArg==0 );
assert( sizeof(buf)>=sizeof(pGlobal) );
memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
@@ -2611,10 +2588,9 @@ static void fts5Fts5Func(
static void fts5SourceIdFunc(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
sqlite3_value **apVal /* Function arguments */
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
}
@@ -2676,17 +2652,6 @@ static int fts5Init(sqlite3 *db){
);
}
}
/* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
** fts5_test_mi.c is compiled and linked into the executable. And call
** its entry point to enable the matchinfo() demo. */
#ifdef SQLITE_FTS5_ENABLE_TEST_MI
if( rc==SQLITE_OK ){
extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
rc = sqlite3Fts5TestRegisterMatchinfo(db);
}
#endif
return rc;
}
+6 -14
View File
@@ -145,7 +145,6 @@ static int fts5StorageGetStmt(
}
*ppStmt = p->aStmt[eStmt];
sqlite3_reset(*ppStmt);
return rc;
}
@@ -363,13 +362,11 @@ static int fts5StorageInsertCallback(
int tflags,
const char *pToken, /* Buffer containing token */
int nToken, /* Size of token in bytes */
int iUnused1, /* Start offset of token */
int iUnused2 /* End offset of token */
int iStart, /* Start offset of token */
int iEnd /* End offset of token */
){
Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
Fts5Index *pIdx = pCtx->pStorage->pIndex;
UNUSED_PARAM2(iUnused1, iUnused2);
if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
pCtx->szCol++;
}
@@ -641,10 +638,6 @@ int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
}
int sqlite3Fts5StorageReset(Fts5Storage *p){
return sqlite3Fts5IndexReset(p->pIndex);
}
/*
** Allocate a new rowid. This is used for "external content" tables when
** a NULL value is inserted into the rowid column. The new rowid is allocated
@@ -804,8 +797,8 @@ static int fts5StorageIntegrityCallback(
int tflags,
const char *pToken, /* Buffer containing token */
int nToken, /* Size of token in bytes */
int iUnused1, /* Start offset of token */
int iUnused2 /* End offset of token */
int iStart, /* Start offset of token */
int iEnd /* End offset of token */
){
Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
Fts5Termset *pTermset = pCtx->pTermset;
@@ -815,9 +808,6 @@ static int fts5StorageIntegrityCallback(
int iPos;
int iCol;
UNUSED_PARAM2(iUnused1, iUnused2);
if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
pCtx->szCol++;
}
@@ -1128,3 +1118,5 @@ int sqlite3Fts5StorageConfigValue(
}
return rc;
}
+19 -20
View File
@@ -41,17 +41,16 @@
*/
#ifdef SQLITE_TEST
#ifdef SQLITE_ENABLE_FTS5
#include "fts5.h"
#include <tcl.h>
#include <assert.h>
#include <string.h>
typedef struct Fts5MatchinfoCtx Fts5MatchinfoCtx;
#ifndef SQLITE_AMALGAMATION
typedef unsigned int u32;
#endif
struct Fts5MatchinfoCtx {
int nCol; /* Number of cols in FTS5 table */
@@ -68,22 +67,18 @@ struct Fts5MatchinfoCtx {
** If an error occurs, return NULL and leave an error in the database
** handle (accessible using sqlite3_errcode()/errmsg()).
*/
static int fts5_api_from_db(sqlite3 *db, fts5_api **ppApi){
static fts5_api *fts5_api_from_db(sqlite3 *db){
fts5_api *pRet = 0;
sqlite3_stmt *pStmt = 0;
int rc;
*ppApi = 0;
rc = sqlite3_prepare(db, "SELECT fts5()", -1, &pStmt, 0);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pStmt)
&& sizeof(fts5_api*)==sqlite3_column_bytes(pStmt, 0)
){
memcpy(ppApi, sqlite3_column_blob(pStmt, 0), sizeof(fts5_api*));
}
rc = sqlite3_finalize(pStmt);
if( SQLITE_OK==sqlite3_prepare(db, "SELECT fts5()", -1, &pStmt, 0)
&& SQLITE_ROW==sqlite3_step(pStmt)
&& sizeof(pRet)==sqlite3_column_bytes(pStmt, 0)
){
memcpy(&pRet, sqlite3_column_blob(pStmt, 0), sizeof(pRet));
}
return rc;
sqlite3_finalize(pStmt);
return pRet;
}
@@ -249,7 +244,11 @@ static int fts5MatchinfoLocalCb(
iOff>=0;
pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
){
aOut[nMul * (iCol + iPhrase * p->nCol)]++;
if( f=='b' ){
aOut[iPhrase * ((p->nCol+31)/32) + iCol/32] |= ((u32)1 << iCol%32);
}else{
aOut[nMul * (iCol + iPhrase * p->nCol)]++;
}
}
}
@@ -403,15 +402,14 @@ int sqlite3Fts5TestRegisterMatchinfo(sqlite3 *db){
/* Extract the FTS5 API pointer from the database handle. The
** fts5_api_from_db() function above is copied verbatim from the
** FTS5 documentation. Refer there for details. */
rc = fts5_api_from_db(db, &pApi);
if( rc!=SQLITE_OK ) return rc;
pApi = fts5_api_from_db(db);
/* If fts5_api_from_db() returns NULL, then either FTS5 is not registered
** with this database handle, or an error (OOM perhaps?) has occurred.
**
** Also check that the fts5_api object is version 2 or newer.
*/
if( pApi==0 || pApi->iVersion<2 ){
if( pApi==0 || pApi->iVersion<1 ){
return SQLITE_ERROR;
}
@@ -422,4 +420,5 @@ int sqlite3Fts5TestRegisterMatchinfo(sqlite3 *db){
}
#endif /* SQLITE_ENABLE_FTS5 */
#endif /* SQLITE_TEST */
+4 -11
View File
@@ -62,13 +62,12 @@ static void fts5AsciiDelete(Fts5Tokenizer *p){
** Create an "ascii" tokenizer.
*/
static int fts5AsciiCreate(
void *pUnused,
void *pCtx,
const char **azArg, int nArg,
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK;
AsciiTokenizer *p = 0;
UNUSED_PARAM(pUnused);
if( nArg%2 ){
rc = SQLITE_ERROR;
}else{
@@ -117,7 +116,7 @@ static void asciiFold(char *aOut, const char *aIn, int nByte){
static int fts5AsciiTokenize(
Fts5Tokenizer *pTokenizer,
void *pCtx,
int iUnused,
int flags,
const char *pText, int nText,
int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
){
@@ -131,8 +130,6 @@ static int fts5AsciiTokenize(
char *pFold = aFold;
unsigned char *a = p->aTokenChar;
UNUSED_PARAM(iUnused);
while( is<nText && rc==SQLITE_OK ){
int nByte;
@@ -326,15 +323,13 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
** Create a "unicode61" tokenizer.
*/
static int fts5UnicodeCreate(
void *pUnused,
void *pCtx,
const char **azArg, int nArg,
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK; /* Return code */
Unicode61Tokenizer *p = 0; /* New tokenizer object */
UNUSED_PARAM(pUnused);
if( nArg%2 ){
rc = SQLITE_ERROR;
}else{
@@ -391,7 +386,7 @@ static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
static int fts5UnicodeTokenize(
Fts5Tokenizer *pTokenizer,
void *pCtx,
int iUnused,
int flags,
const char *pText, int nText,
int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
){
@@ -407,8 +402,6 @@ static int fts5UnicodeTokenize(
int nFold = p->nFold;
const char *pEnd = &aFold[nFold-6];
UNUSED_PARAM(iUnused);
/* Each iteration of this loop gobbles up a contiguous run of separators,
** then the next token. */
while( rc==SQLITE_OK ){
+2 -2
View File
@@ -125,9 +125,9 @@ int sqlite3Fts5UnicodeIsalnum(int c){
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
};
if( (unsigned int)c<128 ){
if( c<128 ){
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
}else if( (unsigned int)c<(1<<22) ){
}else if( c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
-3
View File
@@ -333,10 +333,7 @@ int sqlite3Fts5PutVarint(unsigned char *p, u64 v){
int sqlite3Fts5GetVarintLen(u32 iVal){
#if 0
if( iVal<(1 << 7 ) ) return 1;
#endif
assert( iVal>=(1 << 7) );
if( iVal<(1 << 14) ) return 2;
if( iVal<(1 << 21) ) return 3;
if( iVal<(1 << 28) ) return 4;
+3 -7
View File
@@ -237,7 +237,7 @@ static int fts5VocabCreateMethod(
** Implementation of the xBestIndex method.
*/
static int fts5VocabBestIndexMethod(
sqlite3_vtab *pUnused,
sqlite3_vtab *pVTab,
sqlite3_index_info *pInfo
){
int i;
@@ -247,8 +247,6 @@ static int fts5VocabBestIndexMethod(
int idxNum = 0;
int nArg = 0;
UNUSED_PARAM(pUnused);
for(i=0; i<pInfo->nConstraint; i++){
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
if( p->usable==0 ) continue;
@@ -490,8 +488,8 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
static int fts5VocabFilterMethod(
sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
int idxNum, /* Strategy index */
const char *zUnused, /* Unused */
int nUnused, /* Number of elements in apVal */
const char *idxStr, /* Unused */
int nVal, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
@@ -506,8 +504,6 @@ static int fts5VocabFilterMethod(
sqlite3_value *pGe = 0;
sqlite3_value *pLe = 0;
UNUSED_PARAM2(zUnused, nUnused);
fts5VocabResetCursor(pCsr);
if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
+2 -3
View File
@@ -28,13 +28,12 @@
// This code runs whenever there is a syntax error
//
%syntax_error {
UNUSED_PARAM(yymajor); /* Silence a compiler warning */
sqlite3Fts5ParseError(
pParse, "fts5: syntax error near \"%.*s\"",TOKEN.n,TOKEN.p
);
}
%stack_overflow {
sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow");
assert( 0 );
}
// The name of the generated procedure that implements the parser
@@ -104,7 +103,7 @@ expr(A) ::= exprlist(X). {A = X;}
exprlist(A) ::= cnearset(X). {A = X;}
exprlist(A) ::= exprlist(X) cnearset(Y). {
A = sqlite3Fts5ParseImplicitAnd(pParse, X, Y);
A = sqlite3Fts5ParseNode(pParse, FTS5_AND, X, Y, 0);
}
cnearset(A) ::= nearset(X). {
+7 -12
View File
@@ -16,13 +16,8 @@ if {![info exists testdir]} {
source $testdir/tester.tcl
ifcapable !fts5 {
proc return_if_no_fts5 {} {
finish_test
return -code return
}
finish_test
return
} else {
proc return_if_no_fts5 {} {}
}
catch {
@@ -30,6 +25,12 @@ catch {
reset_db
}
# If SQLITE_ENABLE_FTS5 is not defined, skip this test.
ifcapable !fts5 {
finish_test
return
}
proc fts5_test_poslist {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xInstCount]} {incr i} {
@@ -159,12 +160,6 @@ proc fts5_aux_test_functions {db} {
}
}
proc fts5_segcount {tbl} {
set N 0
foreach n [fts5_level_segs $tbl] { incr N $n }
set N
}
proc fts5_level_segs {tbl} {
set sql "SELECT fts5_decode(rowid,block) aS r FROM ${tbl}_data WHERE rowid=10"
set ret [list]
+1 -8
View File
@@ -432,16 +432,9 @@ proc funk {} {
}
db func funk funk
# This test case corrupts the structure record within the first invocation
# of function funk(). Which used to cause the bm25() function to throw an
# exception. But since bm25() can now used the cached structure record,
# it never sees the corruption introduced by funk() and so the following
# statement no longer fails.
#
do_catchsql_test 16.2 {
SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
} {0 {{} -1e-06 {}}}
# {1 {SQL logic error or missing database}}
} {1 {SQL logic error or missing database}}
#-------------------------------------------------------------------------
#
-2
View File
@@ -11,8 +11,6 @@
# This file implements regression tests for SQLite library. The
# focus of this script is testing the FTS5 module.
#
# More specifically, the focus is on testing prefix queries, both with and
# without prefix indexes.
#
source [file join [file dirname [info script]] fts5_common.tcl]
-1
View File
@@ -14,7 +14,6 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5bigtok
return_if_no_fts5
proc rndterm {} {
set L [list a b c d e f g h i j k l m n o p q r s t u v w x y z]
-20
View File
@@ -243,25 +243,5 @@ foreach {tn opt} {
do_catchsql_test 11.$tn "CREATE VIRTUAL TABLE f1 USING fts5(x, $opt)" $res
}
do_catchsql_test 12.1 {
INSERT INTO t1(t1, rank) VALUES('rank', NULL);;
} {1 {SQL logic error or missing database}}
#-------------------------------------------------------------------------
# errors in the 'usermerge' option
#
do_execsql_test 13.0 {
CREATE VIRTUAL TABLE tt USING fts5(ttt);
}
foreach {tn val} {
1 -1
2 4.2
3 17
4 1
} {
set sql "INSERT INTO tt(tt, rank) VALUES('usermerge', $val)"
do_catchsql_test 13.$tn $sql {1 {SQL logic error or missing database}}
}
finish_test
+3 -39
View File
@@ -179,10 +179,6 @@ for {set i 1} {1} {incr i} {
if {$end<=$i} break
lset var end [expr $end - $i]
set struct [binary format c* $var]
db close
sqlite3 db test.db
db eval {
BEGIN;
UPDATE t1_data SET block = $struct WHERE id=10;
@@ -338,9 +334,12 @@ do_catchsql_test 6.3.5 {
} {1 {database disk image is malformed}}
}
#------------------------------------------------------------------------
#
reset_db
reset_db
proc rnddoc {n} {
set map [list a b c d]
set doc [list]
@@ -372,41 +371,6 @@ do_test 7.1 {
}
} {}
}
#------------------------------------------------------------------------
# Corruption within the structure record.
#
reset_db
do_execsql_test 8.1 {
CREATE VIRTUAL TABLE t1 USING fts5(x, y);
INSERT INTO t1 VALUES('one', 'two');
}
do_test 9.1.1 {
set blob "12345678" ;# cookie
append blob "0105" ;# 1 level, total of 5 segments
append blob "06" ;# write counter
append blob "0002" ;# first level has 0 segments merging, 2 other.
append blob "450108" ;# first segment
execsql "REPLACE INTO t1_data VALUES(10, X'$blob')"
} {}
do_catchsql_test 9.1.2 {
SELECT * FROM t1('one AND two');
} {1 {database disk image is malformed}}
do_test 9.2.1 {
set blob "12345678" ;# cookie
append blob "0205" ;# 2 levels, total of 5 segments
append blob "06" ;# write counter
append blob "0001" ;# first level has 0 segments merging, 1 other.
append blob "450108" ;# first segment
execsql "REPLACE INTO t1_data VALUES(10, X'$blob')"
} {}
do_catchsql_test 9.2.2 {
SELECT * FROM t1('one AND two');
} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
-4
View File
@@ -85,10 +85,6 @@ do_execsql_test 2.2 {
SELECT fts5_test_poslist(t2) FROM t2('aa');
} {0.0.0}
do_execsql_test 2.3 {
SELECT fts5_test_collist(t2) FROM t2('aa');
} {0.0}
set ::pc 0
#puts [nearset {{ax bx cx}} -pc ::pc -near 10 -- b*]
#exit
-67
View File
@@ -1,67 +0,0 @@
# 2016 March 21
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library. The
# focus of this script is testing the FTS5 module.
#
# Specifically, that the fts5 module is deterministic. At one point, when
# segment ids were allocated using sqlite3_randomness(), this was not the
# case.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5aa
return_if_no_fts5
proc do_determin_test {tn} {
uplevel [list
do_execsql_test $tn {
SELECT (SELECT md5sum(id, block) FROM t1_data)==
(SELECT md5sum(id, block) FROM t2_data),
(SELECT md5sum(id, block) FROM t1_data)==
(SELECT md5sum(id, block) FROM t3_data)
} {1 1}
]
}
foreach_detail_mode $::testprefix {
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix="1 2", detail=%DETAIL%);
CREATE VIRTUAL TABLE t2 USING fts5(a, b, prefix="1 2", detail=%DETAIL%);
CREATE VIRTUAL TABLE t3 USING fts5(a, b, prefix="1 2", detail=%DETAIL%);
}
do_test 1.1 {
foreach t {t1 t2 t3} {
execsql [string map [list TBL $t] {
INSERT INTO TBL VALUES('a b c', 'd e f');
INSERT INTO TBL VALUES('c1 c2 c3', 'c1 c2 c3');
INSERT INTO TBL VALUES('xyzxyzxyz', 'xyzxyzxyz');
}]
}
} {}
do_determin_test 1.2
do_test 1.3 {
foreach t {t1 t2 t3} {
execsql [string map [list TBL $t] {
INSERT INTO TBL(TBL) VALUES('optimize');
}]
}
} {}
do_determin_test 1.4
}
finish_test
+2 -2
View File
@@ -178,7 +178,7 @@ do_execsql_test 3.2 {
ORDER BY rowid DESC;
} {16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1}
do_execsql_test 3.3 {
do_execsql_test 3.2 {
INSERT INTO abc(abc) VALUES('integrity-check');
INSERT INTO abc(abc) VALUES('optimize');
INSERT INTO abc(abc) VALUES('integrity-check');
@@ -187,7 +187,7 @@ do_execsql_test 3.3 {
set v [lindex $vocab 0]
set i 0
foreach v $vocab {
do_execsql_test 3.4.[incr i] {
do_execsql_test 3.3.[incr i] {
SELECT rowid FROM abc WHERE abc MATCH $v
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
}
+6 -6
View File
@@ -33,12 +33,12 @@ foreach {tn expr res} {
1 {abc} {"abc"}
2 {abc ""} {"abc"}
3 {""} {}
4 {abc OR ""} {"abc" OR ""}
5 {abc NOT ""} {"abc" NOT ""}
6 {abc AND ""} {"abc" AND ""}
7 {"" OR abc} {"" OR "abc"}
8 {"" NOT abc} {"" NOT "abc"}
9 {"" AND abc} {"" AND "abc"}
4 {abc OR ""} {"abc"}
5 {abc NOT ""} {"abc"}
6 {abc AND ""} {"abc"}
7 {"" OR abc} {"abc"}
8 {"" NOT abc} {"abc"}
9 {"" AND abc} {"abc"}
10 {abc + "" + def} {"abc" + "def"}
11 {abc "" def} {"abc" AND "def"}
12 {r+e OR w} {"r" + "e" OR "w"}
+1 -2
View File
@@ -72,7 +72,7 @@ do_faultsim_test 3 -prep {
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t2 USING fts5(a, b);
INSERT INTO t2 VALUES('m f a jj th q gi ar', 'hj n h h sg j i m');
INSERT INTO t2 VALUES('m f a jj th q jr ar', 'hj n h h sg j i m');
INSERT INTO t2 VALUES('nr s t g od j kf h', 'sb h aq rg op rb n nl');
INSERT INTO t2 VALUES('do h h pb p p q fr', 'c rj qs or cr a l i');
INSERT INTO t2 VALUES('lk gp t i lq mq qm p', 'h mr g f op ld aj h');
@@ -95,7 +95,6 @@ foreach {tn expr res} {
7 { NEAR(r a, 5) } {9}
8 { m* f* } {1 4 6 8 9 10}
9 { m* + f* } {1 8}
10 { c NOT p } {5 6 7 10}
} {
do_faultsim_test 4.$tn -prep {
faultsim_restore_and_reopen
+1 -1
View File
@@ -16,7 +16,7 @@ source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5fault2
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
+1 -1
View File
@@ -86,7 +86,7 @@ set ::res [db eval {SELECT rowid, x1 FROM x1 WHERE x1 MATCH '*reads'}]
do_faultsim_test 4 -faults oom-* -body {
db eval {SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'}
} -test {
faultsim_test_result {0 {0 {} 3}}
faultsim_test_result {0 {0 {} 4}}
}
#-------------------------------------------------------------------------
+1 -8
View File
@@ -99,7 +99,7 @@ do_execsql_test 2.0 {
}
faultsim_save_and_close
do_faultsim_test 2.1 -faults oom-* -prep {
do_faultsim_test 2 -faults oom-* -prep {
faultsim_restore_and_reopen
} -body {
db eval { UPDATE OR REPLACE xy SET rowid=3 WHERE rowid = 2 }
@@ -107,13 +107,6 @@ do_faultsim_test 2.1 -faults oom-* -prep {
faultsim_test_result {0 {}}
}
# Test fault-injection when an empty expression is parsed.
#
do_faultsim_test 2.2 -faults oom-* -body {
db eval { SELECT * FROM xy('""') }
} -test {
faultsim_test_result {0 {}}
}
finish_test
+20 -50
View File
@@ -24,62 +24,32 @@ ifcapable !fts5 {
foreach_detail_mode $testprefix {
fts5_aux_test_functions db
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%);
INSERT INTO t1 VALUES('a b c d', '1 2 3 4');
INSERT INTO t1 VALUES('a b a b', NULL);
INSERT INTO t1 VALUES(NULL, '1 2 1 2');
}
do_faultsim_test 1 -faults oom-* -body {
execsql {
SELECT rowid, fts5_test_poslist(t1) FROM t1 WHERE t1 MATCH 'b OR 2'
}
} -test {
faultsim_test_result {0 {1 {0.0.1 1.1.1} 2 {0.0.1 0.0.3} 3 {1.1.1 1.1.3}}} \
{1 SQLITE_NOMEM}
}
do_faultsim_test 2 -faults oom-* -body {
execsql { INSERT INTO t1(t1) VALUES('integrity-check') }
} -test {
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}
if {[detail_is_none]==0} {
do_faultsim_test 3 -faults oom-* -body {
execsql { SELECT rowid FROM t1('b:2') }
} -test {
faultsim_test_result {0 {1 3}} {1 SQLITE_NOMEM}
}
}
} ;# foreach_detail_mode...
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE x2 USING fts5(a);
INSERT INTO x2(x2, rank) VALUES('crisismerge', 2);
INSERT INTO x2(x2, rank) VALUES('pgsz', 32);
INSERT INTO x2 VALUES('a b c d');
INSERT INTO x2 VALUES('e f g h');
INSERT INTO x2 VALUES('i j k l');
INSERT INTO x2 VALUES('m n o p');
INSERT INTO x2 VALUES('q r s t');
INSERT INTO x2 VALUES('u v w x');
INSERT INTO x2 VALUES('y z a b');
fts5_aux_test_functions db
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%);
INSERT INTO t1 VALUES('a b c d', '1 2 3 4');
INSERT INTO t1 VALUES('a b a b', NULL);
INSERT INTO t1 VALUES(NULL, '1 2 1 2');
}
faultsim_save_and_close
do_faultsim_test 4 -faults oom-* -prep {
faultsim_restore_and_reopen
} -body {
execsql { INSERT INTO x2(x2) VALUES('optimize') }
do_faultsim_test 1 -faults oom-* -body {
execsql {
SELECT rowid, fts5_test_poslist(t1) FROM t1 WHERE t1 MATCH 'b OR 2'
}
} -test {
faultsim_test_result {0 {1 {0.0.1 1.1.1} 2 {0.0.1 0.0.3} 3 {1.1.1 1.1.3}}} \
{1 SQLITE_NOMEM}
}
do_faultsim_test 2 -faults oom-* -body {
execsql {
INSERT INTO t1(t1) VALUES('integrity-check');
}
} -test {
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}
}
finish_test
-64
View File
@@ -1,64 +0,0 @@
# 2016 February 2
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
#
# This file is focused on OOM errors.
#
source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultA
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
foreach_detail_mode $testprefix {
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE o1 USING fts5(a, detail=%DETAIL%);
INSERT INTO o1(o1, rank) VALUES('pgsz', 32);
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<300 )
INSERT INTO o1 SELECT 'A B C' FROM s;
INSERT INTO o1 VALUES('A X C');
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<300 )
INSERT INTO o1 SELECT 'A B C' FROM s;
}
do_faultsim_test 1 -faults oom* -prep {
sqlite3 db test.db
} -body {
execsql { SELECT rowid FROM o1('a NOT b') }
} -test {
faultsim_test_result {0 301}
}
}
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE o2 USING fts5(a);
INSERT INTO o2 VALUES('A B C');
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<300 )
INSERT INTO o2 SELECT group_concat('A B C ') FROM s;
}
do_faultsim_test 2 -faults oom* -prep {
sqlite3 db test.db
} -body {
execsql { SELECT rowid FROM o2('a+b+c NOT xyz') }
} -test {
faultsim_test_result {0 {1 2}}
}
finish_test
-83
View File
@@ -1,83 +0,0 @@
# 2016 February 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 is focused on OOM errors.
#
source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultB
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
proc mit {blob} {
set scan(littleEndian) i*
set scan(bigEndian) I*
binary scan $blob $scan($::tcl_platform(byteOrder)) r
return $r
}
db func mit mit
#-------------------------------------------------------------------------
# Errors while registering the matchinfo() demo function.
#
do_faultsim_test 1 -faults oom* -prep {
sqlite3 db test.db
} -body {
sqlite3_fts5_register_matchinfo db
} -test {
faultsim_test_result {0 {}} {1 SQLITE_ERROR} {1 SQLITE_NOMEM}
}
#-------------------------------------------------------------------------
# Errors while executing the matchinfo() demo function.
#
reset_db
sqlite3_fts5_register_matchinfo db
db func mit mit
do_execsql_test 2 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b);
INSERT INTO t1 VALUES('x y z', '1 2 3');
INSERT INTO t1 VALUES('x', '1 2 3 4 5 6 7');
}
do_faultsim_test 2.1 -faults oom* -body {
execsql { SELECT mit(matchinfo(t1, 'a')) FROM t1('x') }
} -test {
faultsim_test_result {0 {{2 5} {2 5}}}
}
do_faultsim_test 2.2 -faults oom* -body {
execsql { SELECT mit(matchinfo(t1, 'l')) FROM t1('x') }
} -test {
faultsim_test_result {0 {{3 3} {1 7}}}
}
do_execsql_test 2.3 {
INSERT INTO t1 VALUES('a b c d e f', 'a b d e f c');
INSERT INTO t1 VALUES('l m b c a', 'n o a b c z');
}
do_faultsim_test 2.4 -faults oom* -body {
execsql { SELECT mit(matchinfo(t1, 's')) FROM t1('a b c') }
} -test {
faultsim_test_result {0 {{3 2} {2 3}}}
}
finish_test
-93
View File
@@ -1,93 +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]
return_if_no_fts5
set testprefix fts5fuzz1
#-------------------------------------------------------------------------
reset_db
do_catchsql_test 1.1 {
CREATE VIRTUAL TABLE f1 USING fts5(a b);
} {/1 {parse error in.*}/}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.1 {
CREATE VIRTUAL TABLE f1 USING fts5(a, b);
INSERT INTO f1 VALUES('a b', 'c d');
INSERT INTO f1 VALUES('e f', 'a b');
}
do_execsql_test 2.2.1 {
SELECT rowid FROM f1('""');
} {}
do_execsql_test 2.2.2 {
SELECT rowid FROM f1('"" AND a');
} {}
do_execsql_test 2.2.3 {
SELECT rowid FROM f1('"" a');
} {1 2}
do_execsql_test 2.2.4 {
SELECT rowid FROM f1('"" OR a');
} {1 2}
do_execsql_test 2.3 {
SELECT a, b FROM f1('NEAR("")');
} {}
do_execsql_test 2.4 {
SELECT a, b FROM f1('NEAR("", 5)');
} {}
do_execsql_test 2.5 {
SELECT a, b FROM f1('NEAR("" c, 5)');
} {{a b} {c d}}
do_execsql_test 2.6 {
SELECT a, b FROM f1('NEAR("" c d, 5)');
} {{a b} {c d}}
do_execsql_test 2.7 {
SELECT a, b FROM f1('NEAR(c d, 5)');
} {{a b} {c d}}
do_execsql_test 2.8 {
SELECT rowid FROM f1('NEAR("a" "b", 5)');
} {1 2}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.2 {
CREATE VIRTUAL TABLE f2 USING fts5(o, t, tokenize="ascii separators abc");
SELECT * FROM f2('a+4');
} {}
#-------------------------------------------------------------------------
reset_db
do_catchsql_test 4.1 {
CREATE VIRTUAL TABLE f2 USING fts5(o, t);
SELECT * FROM f2('(8 AND 9)`AND 10');
} {1 {fts5: syntax error near "`"}}
finish_test
+38 -57
View File
@@ -66,66 +66,47 @@ proc random_doc {vocab nWord} {
foreach_detail_mode $testprefix {
set vocab [build_vocab1]
db func r random_doc
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE eee USING fts5(e, ee, detail=%DETAIL%);
BEGIN;
WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100)
INSERT INTO eee SELECT r($vocab, 5), r($vocab, 7) FROM ii;
INSERT INTO eee(eee) VALUES('integrity-check');
COMMIT;
INSERT INTO eee(eee) VALUES('integrity-check');
}
set hash [sqlite3_fts5_token_hash 1024 xyz]
set vocab [build_vocab1 -prefix xyz -hash $hash]
lappend vocab xyz
do_execsql_test 1.1 {
CREATE VIRTUAL TABLE vocab USING fts5vocab(eee, 'row');
BEGIN;
}
do_test 1.2 {
for {set i 1} {$i <= 100} {incr i} {
execsql { INSERT INTO eee VALUES( r($vocab, 5), r($vocab, 7) ) }
}
} {}
do_test 1.3 {
db eval { SELECT term, doc FROM vocab } {
set nRow [db one {SELECT count(*) FROM eee WHERE eee MATCH $term}]
if {$nRow != $doc} {
error "term=$term fts5vocab=$doc cnt=$nRow"
}
}
set {} {}
} {}
do_execsql_test 1.4 {
COMMIT;
INSERT INTO eee(eee) VALUES('integrity-check');
}
set vocab [build_vocab1]
db func r random_doc
#-----------------------------------------------------------------------
# Add a small and very large token with the same hash value to an
# empty table. At one point this would provoke an asan error.
#
do_test 2.0 {
set big [string repeat 12345 40]
set hash [sqlite3_fts5_token_hash 1024 $big]
while {1} {
set small [random_token]
if {[sqlite3_fts5_token_hash 1024 $small]==$hash} break
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE eee USING fts5(e, ee, detail=%DETAIL%);
BEGIN;
WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100)
INSERT INTO eee SELECT r($vocab, 5), r($vocab, 7) FROM ii;
INSERT INTO eee(eee) VALUES('integrity-check');
COMMIT;
INSERT INTO eee(eee) VALUES('integrity-check');
}
execsql { CREATE VIRTUAL TABLE t2 USING fts5(x, detail=%DETAIL%) }
breakpoint
execsql {
INSERT INTO t2 VALUES($small || ' ' || $big);
set hash [sqlite3_fts5_token_hash 1024 xyz]
set vocab [build_vocab1 -prefix xyz -hash $hash]
lappend vocab xyz
do_execsql_test 1.1 {
CREATE VIRTUAL TABLE vocab USING fts5vocab(eee, 'row');
BEGIN;
}
do_test 1.2 {
for {set i 1} {$i <= 100} {incr i} {
execsql { INSERT INTO eee VALUES( r($vocab, 5), r($vocab, 7) ) }
}
} {}
do_test 1.3 {
db eval { SELECT term, doc FROM vocab } {
set nRow [db one {SELECT count(*) FROM eee WHERE eee MATCH $term}]
if {$nRow != $doc} {
error "term=$term fts5vocab=$doc cnt=$nRow"
}
} {}
}
set {} {}
} {}
do_execsql_test 1.4 {
COMMIT;
INSERT INTO eee(eee) VALUES('integrity-check');
}
} ;# foreach_detail_mode
-24
View File
@@ -467,29 +467,5 @@ do_execsql_test 12.1 {
} ;# foreach_detail_mode
#-------------------------------------------------------------------------
# Test that a bad fts5() return is detected
#
reset_db
proc xyz {} {}
db func fts5 -argcount 0 xyz
do_test 13.1 {
list [catch { sqlite3_fts5_register_matchinfo db } msg] $msg
} {1 SQLITE_ERROR}
#-------------------------------------------------------------------------
# Test that an invalid matchinfo() flag is detected
#
reset_db
sqlite3_fts5_register_matchinfo db
do_execsql_test 14.1 {
CREATE VIRTUAL TABLE x1 USING fts5(z);
INSERT INTO x1 VALUES('a b c a b c a b c');
} {}
do_catchsql_test 14.2 {
SELECT matchinfo(x1, 'd') FROM x1('a b c');
} {1 {unrecognized matchinfo flag: d}}
finish_test
+9 -59
View File
@@ -45,7 +45,7 @@ proc do_merge1_test {testname nRowPerSeg} {
WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg)
INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii;
INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
INSERT INTO x8(x8, rank) VALUES('automerge', 2);
}
for {set tn 1} {[lindex [fts5_level_segs x8] 0]>0} {incr tn} {
@@ -84,9 +84,9 @@ proc do_merge2_test {testname nRow} {
execsql { INSERT INTO x8 VALUES( rnddoc(($i%16) + 5) ) }
while {[not_merged x8]} {
execsql {
INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
INSERT INTO x8(x8, rank) VALUES('automerge', 2);
INSERT INTO x8(x8, rank) VALUES('merge', 1);
INSERT INTO x8(x8, rank) VALUES('usermerge', 16);
INSERT INTO x8(x8, rank) VALUES('automerge', 16);
INSERT INTO x8(x8) VALUES('integrity-check');
}
}
@@ -104,9 +104,9 @@ do_merge2_test 2.2 10
do_merge2_test 2.3 20
#-------------------------------------------------------------------------
# Test that a merge will complete any merge that has already been
# Test that an auto-merge will complete any merge that has already been
# started, even if the number of input segments is less than the current
# value of the 'usermerge' configuration parameter.
# value of the 'automerge' configuration parameter.
#
db func rnddoc fts5_rnddoc
@@ -119,7 +119,7 @@ do_execsql_test 3.1 {
}
do_test 3.2 {
execsql {
INSERT INTO x8(x8, rank) VALUES('usermerge', 4);
INSERT INTO x8(x8, rank) VALUES('automerge', 4);
INSERT INTO x8(x8, rank) VALUES('merge', 1);
}
fts5_level_segs x8
@@ -127,14 +127,14 @@ do_test 3.2 {
do_test 3.3 {
execsql {
INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
INSERT INTO x8(x8, rank) VALUES('automerge', 2);
INSERT INTO x8(x8, rank) VALUES('merge', 1);
}
fts5_level_segs x8
} {2 1}
do_test 3.4 {
execsql { INSERT INTO x8(x8, rank) VALUES('usermerge', 4) }
execsql { INSERT INTO x8(x8, rank) VALUES('automerge', 4) }
while {[not_merged x8]} {
execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1) }
}
@@ -176,7 +176,7 @@ foreach {tn pgsz} {
INSERT INTO x8 SELECT mydoc() FROM ii;
WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100)
INSERT INTO x8 SELECT mydoc() FROM ii;
INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
INSERT INTO x8(x8, rank) VALUES('automerge', 2);
}
set expect [mycount]
@@ -190,55 +190,5 @@ foreach {tn pgsz} {
# db eval {SELECT fts5_decode(rowid, block) AS r FROM x8_data} { puts $r }
}
#-------------------------------------------------------------------------
# Test that the 'merge' command does not modify the database if there is
# no work to do.
do_execsql_test 5.1 {
CREATE VIRTUAL TABLE x9 USING fts5(one, two);
INSERT INTO x9(x9, rank) VALUES('pgsz', 32);
INSERT INTO x9(x9, rank) VALUES('automerge', 2);
INSERT INTO x9(x9, rank) VALUES('usermerge', 2);
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
}
do_test 5.2 {
while 1 {
set nChange [db total_changes]
execsql { INSERT INTO x9(x9, rank) VALUES('merge', 1); }
set nChange [expr [db total_changes] - $nChange]
#puts $nChange
if {$nChange<2} break
}
} {}
#--------------------------------------------------------------------------
# Test that running 'merge' on an empty database does not cause a
# problem.
#
reset_db
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE g1 USING fts5(a, b);
}
do_execsql_test 6.1 {
INSERT INTO g1(g1, rank) VALUES('merge', 10);
}
do_execsql_test 6.2 {
INSERT INTO g1(g1, rank) VALUES('merge', -10);
}
do_execsql_test 6.3 {
INSERT INTO g1(g1) VALUES('integrity-check');
}
finish_test
+3 -2
View File
@@ -13,8 +13,7 @@
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5merge2
return_if_no_fts5
set testprefix fts5merge
proc dump_structure {} {
db eval {SELECT fts5_decode(id, block) AS t FROM t1_data WHERE id=10} {
@@ -27,6 +26,8 @@ proc dump_structure {} {
foreach_detail_mode $testprefix {
if {[detail_is_none]==0} continue
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%);
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
-48
View File
@@ -1,48 +0,0 @@
# 2016 March 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.
#
#*************************************************************************
#
source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/lock_common.tcl
set testprefix fts5multiclient
return_if_no_fts5
foreach_detail_mode $testprefix {
do_multiclient_test tn {
do_test 1.$tn.1 {
sql1 { CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%) }
sql1 { INSERT INTO t1 VALUES('a b c') }
sql2 { SELECT rowid FROM t1('b') }
} {1}
do_test 1.$tn.2 {
sql2 { INSERT INTO t1 VALUES('a b c') }
sql1 { SELECT rowid FROM t1('b') }
} {1 2}
do_test 1.$tn.3 {
sql2 { INSERT INTO t1 VALUES('a b c') }
sql1 { SELECT rowid FROM t1('b') }
} {1 2 3}
do_test 1.$tn.4 {
sql2 { INSERT INTO t1 VALUES('a b c') }
sql1 { INSERT INTO t1 VALUES('a b c') }
sql3 { INSERT INTO t1(t1) VALUES('integrity-check') }
} {}
};# do_multiclient_test
};# foreach_detail_mode
finish_test
+2 -45
View File
@@ -20,12 +20,6 @@ ifcapable !fts5 {
return
}
#
# 1.* - Warm body tests for index optimization using ('optimize')
#
# 2.* - Warm body tests for index optimization using ('merge', -1)
#
proc rnddoc {nWord} {
set vocab {a b c d e f g h i j k l m n o p q r s t u v w x y z}
set nVocab [llength $vocab]
@@ -36,12 +30,14 @@ proc rnddoc {nWord} {
return $ret
}
foreach {tn nStep} {
1 2
2 10
3 50
4 500
} {
if {$tn!=4} continue
reset_db
db func rnddoc rnddoc
do_execsql_test 1.$tn.1 {
@@ -64,46 +60,7 @@ foreach {tn nStep} {
do_execsql_test 1.$tn.5 {
INSERT INTO t1(t1) VALUES('integrity-check');
}
do_test 1.$tn.6 { fts5_segcount t1 } 1
}
foreach {tn nStep} {
1 2
2 10
3 50
4 500
} {
reset_db
db func rnddoc rnddoc
do_execsql_test 1.$tn.1 {
CREATE VIRTUAL TABLE t1 USING fts5(x, y);
}
do_test 2.$tn.2 {
for {set i 0} {$i < $nStep} {incr i} {
execsql { INSERT INTO t1 VALUES( rnddoc(5), rnddoc(5) ) }
}
} {}
do_execsql_test 2.$tn.3 {
INSERT INTO t1(t1) VALUES('integrity-check');
}
do_test 2.$tn.4 {
execsql { INSERT INTO t1(t1, rank) VALUES('merge', -1) }
while 1 {
set c [db total_changes]
execsql { INSERT INTO t1(t1, rank) VALUES('merge', 1) }
set c [expr [db total_changes]-$c]
if {$c<2} break
}
} {}
do_execsql_test 2.$tn.5 {
INSERT INTO t1(t1) VALUES('integrity-check');
}
do_test 2.$tn.6 { fts5_segcount t1 } 1
}
finish_test
+7 -92
View File
@@ -19,7 +19,7 @@ ifcapable !fts5 {
return
}
if 1 {
if 1 {
#-------------------------------------------------------------------------
#
@@ -340,7 +340,7 @@ do_test 14.2 {
#-------------------------------------------------------------------------
db func rnddoc fts5_rnddoc
do_execsql_test 14.3 {
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x);
INSERT INTO x1(x1, rank) VALUES('pgsz', 32);
@@ -348,9 +348,9 @@ do_execsql_test 14.3 {
INSERT INTO x1 SELECT rnddoc(5) FROM ii;
}
do_execsql_test 14.4 {
do_execsql_test 4.1 {
SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'
} {0 {} 3}
} {0 {} 4}
#-------------------------------------------------------------------------
reset_db
@@ -363,6 +363,8 @@ do_execsql_test 15.1 {
INSERT INTO x2(x2) VALUES('integrity-check');
}
}
#-------------------------------------------------------------------------
foreach_detail_mode $testprefix {
reset_db
@@ -380,92 +382,5 @@ foreach_detail_mode $testprefix {
} {{0.0.0 1.0.2}}
}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 17.0 {
CREATE VIRTUAL TABLE x3 USING fts5(x);
INSERT INTO x3 VALUES('a b c');
}
do_execsql_test 17.1 {
SELECT rowid FROM x3('b AND d');
}
#-------------------------------------------------------------------------
do_execsql_test 18.1 {
CREATE VIRTUAL TABLE x4 USING fts5(x);
SELECT rowid FROM x4('""');
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 19.1 {
CREATE VIRTUAL TABLE x1 USING fts5(a,b,c);
}
do_catchsql_test 19.2 {
SELECT * FROM x1 WHERE x1 MATCH 'c0 AND (c1 AND (c2 AND (c3 AND (c4 AND (c5 AND (c6 AND (c7 AND (c8 AND (c9 AND (c10 AND (c11 AND (c12 AND (c13 AND (c14 AND (c15 AND (c16 AND (c17 AND (c18 AND (c19 AND (c20 AND (c21 AND (c22 AND (c23 AND (c24 AND (c25 AND (c26 AND (c27 AND (c28 AND (c29 AND (c30 AND (c31 AND (c32 AND (c33 AND (c34 AND (c35 AND (c36 AND (c37 AND (c38 AND (c39 AND (c40 AND (c41 AND (c42 AND (c43 AND (c44 AND (c45 AND (c46 AND (c47 AND (c48 AND (c49 AND (c50 AND (c51 AND (c52 AND (c53 AND (c54 AND (c55 AND (c56 AND (c57 AND (c58 AND (c59 AND (c60 AND (c61 AND (c62 AND (c63 AND (c64 AND (c65 AND (c66 AND (c67 AND (c68 AND (c69 AND (c70 AND (c71 AND (c72 AND (c73 AND (c74 AND (c75 AND (c76 AND (c77 AND (c78 AND (c79 AND (c80 AND (c81 AND (c82 AND (c83 AND (c84 AND (c85 AND (c86 AND (c87 AND (c88 AND (c89 AND (c90 AND (c91 AND (c92 AND (c93 AND (c94 AND (c95 AND (c96 AND (c97 AND (c98 AND (c99 AND (c100 AND (c101 AND (c102 AND (c103 AND (c104 AND (c105 AND (c106 AND (c107 AND (c108 AND (c109 AND (c110 AND (c111 AND (c112 AND (c113 AND (c114 AND (c115 AND (c116 AND (c117 AND (c118 AND (c119 AND (c120 AND (c121 AND (c122 AND (c123 AND (c124 AND (c125 AND (c126 AND (c127 AND (c128 AND (c129 AND (c130 AND (c131 AND (c132 AND (c133 AND (c134 AND (c135 AND (c136 AND (c137 AND (c138 AND (c139 AND (c140 AND (c141 AND (c142 AND (c143 AND (c144 AND (c145 AND (c146 AND (c147 AND (c148 AND (c149 AND (c150 AND (c151 AND (c152 AND (c153 AND (c154 AND (c155 AND (c156 AND (c157 AND (c158 AND (c159 AND (c160 AND (c161 AND (c162 AND (c163 AND (c164 AND (c165 AND (c166 AND (c167 AND (c168 AND (c169 AND (c170 AND (c171 AND (c172 AND (c173 AND (c174 AND (c175 AND (c176 AND (c177 AND (c178 AND (c179 AND (c180 AND (c181 AND (c182 AND (c183 AND (c184 AND (c185 AND (c186 AND (c187 AND (c188 AND (c189 AND (c190 AND (c191 AND (c192 AND (c193 AND (c194 AND (c195 AND (c196 AND (c197 AND (c198 AND (c199 AND c200)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))';
} {1 {fts5: parser stack overflow}}
#-------------------------------------------------------------------------
reset_db
breakpoint
do_execsql_test 20.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x);
INSERT INTO x1(x1, rank) VALUES('pgsz', 32);
INSERT INTO x1(rowid, x) VALUES(11111, 'onetwothree');
}
do_test 20.1 {
for {set i 1} {$i <= 200} {incr i} {
execsql { INSERT INTO x1(rowid, x) VALUES($i, 'one two three'); }
}
execsql { INSERT INTO x1(x1) VALUES('optimize'); }
execsql { DELETE FROM x1 WHERE rowid = 4; }
} {}
do_execsql_test 20.2 {
INSERT INTO x1(x1) VALUES('optimize');
INSERT INTO x1(x1) VALUES('integrity-check');
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 20.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x);
INSERT INTO x1(x1, rank) VALUES('pgsz', 32);
INSERT INTO x1(rowid, x) VALUES(11111, 'onetwothree');
}
do_test 20.1 {
for {set i 1} {$i <= 200} {incr i} {
execsql { INSERT INTO x1(rowid, x) VALUES($i, 'one two three'); }
}
execsql { INSERT INTO x1(x1) VALUES('optimize'); }
execsql { DELETE FROM x1 WHERE rowid = 4; }
} {}
do_execsql_test 20.2 {
INSERT INTO x1(x1) VALUES('optimize');
INSERT INTO x1(x1) VALUES('integrity-check');
} {}
#-------------------------------------------------------------------------
reset_db
set doc "a b [string repeat x 100000]"
do_execsql_test 21.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x);
INSERT INTO x1(rowid, x) VALUES(11111, $doc);
INSERT INTO x1(rowid, x) VALUES(11112, $doc);
}
do_execsql_test 21.1 {
INSERT INTO x1(x1) VALUES('integrity-check');
}
do_execsql_test 21.2 {
SELECT rowid FROM x1($doc);
} {11111 11112}
do_execsql_test 21.3 {
DELETE FROM x1 WHERE rowid=11111;
INSERT INTO x1(x1) VALUES('integrity-check');
SELECT rowid FROM x1($doc);
} {11112}
finish_test
-41
View File
@@ -39,47 +39,6 @@ do_execsql_test 1.3 {
SELECT rowid, fts5_test_collist(t1) FROM t1('b:a');
} {}
#-------------------------------------------------------------------------
# Create detail=col and detail=full tables with 998 columns.
#
foreach_detail_mode $testprefix {
if {[detail_is_none]} continue
do_test 2.1 {
execsql { DROP TABLE IF EXISTS t2 }
set cols [list]
set vals [list]
for {set i 1} {$i <= 998} {incr i} {
lappend cols "c$i"
lappend vals "'val$i'"
}
execsql "CREATE VIRTUAL TABLE t2 USING fts5(detail=%DETAIL%,[join $cols ,])"
} {}
do_test 2.2 {
execsql "INSERT INTO t2 VALUES([join $vals ,])"
} {}
foreach {tn q res} {
1 { c1:val1 } 1
2 { c300:val300 } 1
3 { c300:val1 } {}
4 { c1:val300 } {}
} {
do_execsql_test 2.3.$tn {
SELECT rowid FROM t2($q)
} $res
}
}
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE x3 USING fts5(one);
INSERT INTO x3 VALUES('a b c');
INSERT INTO x3 VALUES('c b a');
INSERT INTO x3 VALUES('o t t');
SELECT * FROM x3('x OR y OR z');
}
finish_test
+1 -4
View File
@@ -11,11 +11,8 @@ set Q {
{1 "SELECT count(*) FROM t1 WHERE t1 MATCH 'c:t*'"}
{1 "SELECT count(*) FROM t1 WHERE t1 MATCH 'a:t* OR b:t* OR c:t* OR d:t* OR e:t* OR f:t* OR g:t*'"}
{1 "SELECT count(*) FROM t1 WHERE t1 MATCH 'a:t*'"}
{2 "SELECT count(*) FROM t1 WHERE t1 MATCH 'c:the'"}
{2 "SELECT count(*) FROM t1 WHERE t1 MATCH 'd:holmes OR e:holmes OR f:holmes OR g:holmes'" }
{2 "SELECT count(*) FROM t1 WHERE t1 MATCH 'd:holmes AND e:holmes AND f:holmes AND g:holmes'" }
{4 "SELECT count(*) FROM t1 WHERE t1 MATCH 'd:holmes NOT e:holmes'" }
{2 "SELECT count(*) FROM t1 WHERE t1 MATCH 'c:the'"}
}
proc usage {} {
+130 -149
View File
@@ -1,160 +1,142 @@
##########################################################################
# 2016 Jan 27
#-------------------------------------------------------------------------
# Command line options processor.
#
# 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.
#
proc process_cmdline {} {
cmdline::process ::A $::argv {
{fts5 "use fts5 (this is the default)"}
{fts4 "use fts4"}
{colsize "10 10 10" "list of column sizes"}
{tblname "t1" "table name to create"}
{detail "full" "Fts5 detail mode to use"}
{repeat 1 "Load each file this many times"}
{prefix "" "Fts prefix= option"}
{trans 1 "True to use a transaction"}
database
file...
} {
This script is designed to create fts4/5 tables with more than one column.
The -colsize option should be set to a Tcl list of integer values, one for
each column in the table. Each value is the number of tokens that will be
inserted into the column value for each row. For example, setting the -colsize
option to "5 10" creates an FTS table with 2 columns, with roughly 5 and 10
tokens per row in each, respectively.
Each "FILE" argument should be a text file. The contents of these text files
is split on whitespace characters to form a list of tokens. The first N1
tokens are used for the first column of the first row, where N1 is the first
element of the -colsize list. The next N2 are used for the second column of
the first row, and so on. Rows are added to the table until the entire list
of tokens is exhausted.
proc command_line_error {O E {msg ""}} {
if {$msg != ""} {
puts stderr "Error: $msg"
puts stderr ""
}
set L [list]
foreach o $O {
if {[llength $o]==1} {
lappend L [string toupper $o]
}
}
puts stderr "Usage: $::argv0 ?SWITCHES? $L"
puts stderr ""
puts stderr "Switches are:"
foreach o $O {
if {[llength $o]==3} {
foreach {a b c} $o {}
puts stderr [format " -%-15s %s (default \"%s\")" "$a VAL" $c $b]
} elseif {[llength $o]==2} {
foreach {a b} $o {}
puts stderr [format " -%-15s %s" $a $b]
}
}
puts stderr ""
puts stderr $E
exit -1
}
###########################################################################
###########################################################################
# Command line options processor. This is generic code that can be copied
# between scripts.
#
namespace eval cmdline {
proc cmdline_error {O E {msg ""}} {
if {$msg != ""} {
puts stderr "Error: $msg"
puts stderr ""
}
set L [list]
foreach o $O {
if {[llength $o]==1} {
lappend L [string toupper $o]
}
}
puts stderr "Usage: $::argv0 ?SWITCHES? $L"
puts stderr ""
puts stderr "Switches are:"
foreach o $O {
if {[llength $o]==3} {
foreach {a b c} $o {}
puts stderr [format " -%-15s %s (default \"%s\")" "$a VAL" $c $b]
} elseif {[llength $o]==2} {
foreach {a b} $o {}
puts stderr [format " -%-15s %s" $a $b]
}
}
puts stderr ""
puts stderr $E
exit -1
}
proc process {avar lArgs O E} {
upvar $avar A
set zTrailing "" ;# True if ... is present in $O
set lPosargs [list]
# Populate A() with default values. Also, for each switch in the command
# line spec, set an entry in the idx() array as follows:
#
# {tblname t1 "table name to use"}
# -> [set idx(-tblname) {tblname t1 "table name to use"}
#
# For each position parameter, append its name to $lPosargs. If the ...
# specifier is present, set $zTrailing to the name of the prefix.
#
foreach o $O {
set nm [lindex $o 0]
set nArg [llength $o]
switch -- $nArg {
1 {
if {[string range $nm end-2 end]=="..."} {
set zTrailing [string range $nm 0 end-3]
} else {
lappend lPosargs $nm
}
}
2 {
set A($nm) 0
set idx(-$nm) $o
}
3 {
set A($nm) [lindex $o 1]
set idx(-$nm) $o
}
default {
error "Error in command line specification"
proc process_command_line {avar lArgs O E} {
upvar $avar A
set zTrailing "" ;# True if ... is present in $O
set lPosargs [list]
# Populate A() with default values. Also, for each switch in the command
# line spec, set an entry in the idx() array as follows:
#
# {tblname t1 "table name to use"}
# -> [set idx(-tblname) {tblname t1 "table name to use"}
#
# For each position parameter, append its name to $lPosargs. If the ...
# specifier is present, set $zTrailing to the name of the prefix.
#
foreach o $O {
set nm [lindex $o 0]
set nArg [llength $o]
switch -- $nArg {
1 {
if {[string range $nm end-2 end]=="..."} {
set zTrailing [string range $nm 0 end-3]
} else {
lappend lPosargs $nm
}
}
}
# Set explicitly specified option values
#
set nArg [llength $lArgs]
for {set i 0} {$i < $nArg} {incr i} {
set opt [lindex $lArgs $i]
if {[string range $opt 0 0]!="-" || $opt=="--"} break
set c [array names idx "${opt}*"]
if {[llength $c]==0} { cmdline_error $O $E "Unrecognized option: $opt"}
if {[llength $c]>1} { cmdline_error $O $E "Ambiguous option: $opt"}
if {[llength $idx($c)]==3} {
if {$i==[llength $lArgs]-1} {
cmdline_error $O $E "Option requires argument: $c"
}
incr i
set A([lindex $idx($c) 0]) [lindex $lArgs $i]
} else {
set A([lindex $idx($c) 0]) 1
2 {
set A($nm) 0
set idx(-$nm) $o
}
3 {
set A($nm) [lindex $o 1]
set idx(-$nm) $o
}
default {
error "Error in command line specification"
}
}
# Deal with position arguments.
#
set nPosarg [llength $lPosargs]
set nRem [expr $nArg - $i]
if {$nRem < $nPosarg || ($zTrailing=="" && $nRem > $nPosarg)} {
cmdline_error $O $E
}
for {set j 0} {$j < $nPosarg} {incr j} {
set A([lindex $lPosargs $j]) [lindex $lArgs [expr $j+$i]]
}
if {$zTrailing!=""} {
set A($zTrailing) [lrange $lArgs [expr $j+$i] end]
}
}
} ;# namespace eval cmdline
# Set explicitly specified option values
#
set nArg [llength $lArgs]
for {set i 0} {$i < $nArg} {incr i} {
set opt [lindex $lArgs $i]
if {[string range $opt 0 0]!="-" || $opt=="--"} break
set c [array names idx "${opt}*"]
if {[llength $c]==0} { command_line_error $O $E "Unrecognized option: $opt"}
if {[llength $c]>1} { command_line_error $O $E "Ambiguous option: $opt"}
if {[llength $idx($c)]==3} {
if {$i==[llength $lArgs]-1} {
command_line_error $O $E "Option requires argument: $c"
}
incr i
set A([lindex $idx($c) 0]) [lindex $lArgs $i]
} else {
set A([lindex $idx($c) 0]) 1
}
}
# Deal with position arguments.
#
set nPosarg [llength $lPosargs]
set nRem [expr $nArg - $i]
if {$nRem < $nPosarg || ($zTrailing=="" && $nRem > $nPosarg)} {
command_line_error $O $E
}
for {set j 0} {$j < $nPosarg} {incr j} {
set A([lindex $lPosargs $j]) [lindex $lArgs [expr $j+$i]]
}
if {$zTrailing!=""} {
set A($zTrailing) [lrange $lArgs [expr $j+$i] end]
}
}
# End of command line options processor.
###########################################################################
###########################################################################
#-------------------------------------------------------------------------
process_cmdline
# If -fts4 was specified, use fts4. Otherwise, fts5.
process_command_line A $argv {
{fts5 "use fts5"}
{fts4 "use fts4"}
{colsize "10 10 10" "list of column sizes"}
{tblname "t1" "table name to create"}
{detail "full" "Fts5 detail mode to use"}
{repeat 1 "Load each file this many times"}
database
file...
} {
This script is designed to create fts4/5 tables with more than one column.
The -colsize option should be set to a Tcl list of integer values, one for
each column in the table. Each value is the number of tokens that will be
inserted into the column value for each row. For example, setting the -colsize
option to "5 10" creates an FTS table with 2 columns, with roughly 5 and 10
tokens per row in each, respectively.
Each "FILE" argument should be a text file. The contents of these text files is
split on whitespace characters to form a list of tokens. The first N1 tokens
are used for the first column of the first row, where N1 is the first element
of the -colsize list. The next N2 are used for the second column of the first
row, and so on. Rows are added to the table until the entire list of tokens
is exhausted.
}
if {$A(fts4)} {
set A(fts) fts4
} else {
@@ -174,8 +156,7 @@ proc create_table {} {
set sql "CREATE VIRTUAL TABLE IF NOT EXISTS $A(tblname) USING $A(fts) ("
append sql [join $cols ,]
if {$A(fts)=="fts5"} { append sql ",detail=$A(detail)" }
append sql ", prefix='$A(prefix)');"
if {$A(fts)=="fts5"} { append sql ",detail=$A(detail));" }
db eval $sql
return $cols
@@ -215,7 +196,7 @@ foreach c [lrange $cols 1 end] {
}
append sql ")"
if {$A(trans)} { db eval BEGIN }
db eval BEGIN
while {$i < $N} {
foreach c $cols s $A(colsize) {
set R($c) [lrange $tokens $i [expr $i+$s-1]]
@@ -223,7 +204,7 @@ if {$A(trans)} { db eval BEGIN }
}
db eval $sql
}
if {$A(trans)} { db eval COMMIT }
db eval COMMIT
+37 -75
View File
@@ -60,38 +60,6 @@ static void xFree(void *p){
sqlite3_free(p);
}
/*
** This lookup table is used to help decode the first byte of
** a multi-byte UTF8 character. It is copied here from SQLite source
** code file utf8.c.
*/
static const unsigned char icuUtf8Trans1[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
};
#define SQLITE_ICU_READ_UTF8(zIn, c) \
c = *(zIn++); \
if( c>=0xc0 ){ \
c = icuUtf8Trans1[c-0xc0]; \
while( (*zIn & 0xc0)==0x80 ){ \
c = (c<<6) + (0x3f & *(zIn++)); \
} \
}
#define SQLITE_ICU_SKIP_UTF8(zIn) \
assert( *zIn ); \
if( *(zIn++)>=0xc0 ){ \
while( (*zIn & 0xc0)==0x80 ){zIn++;} \
}
/*
** Compare two UTF-8 strings for equality where the first string is
** a "LIKE" expression. Return true (1) if they are the same and
@@ -105,14 +73,16 @@ static int icuLikeCompare(
static const int MATCH_ONE = (UChar32)'_';
static const int MATCH_ALL = (UChar32)'%';
int iPattern = 0; /* Current byte index in zPattern */
int iString = 0; /* Current byte index in zString */
int prevEscape = 0; /* True if the previous character was uEsc */
while( 1 ){
while( zPattern[iPattern]!=0 ){
/* Read (and consume) the next character from the input pattern. */
UChar32 uPattern;
SQLITE_ICU_READ_UTF8(zPattern, uPattern);
if( uPattern==0 ) break;
U8_NEXT_UNSAFE(zPattern, iPattern, uPattern);
/* There are now 4 possibilities:
**
@@ -129,28 +99,28 @@ static int icuLikeCompare(
** MATCH_ALL. For each MATCH_ONE, skip one character in the
** test string.
*/
while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){
if( c==MATCH_ONE ){
if( *zString==0 ) return 0;
SQLITE_ICU_SKIP_UTF8(zString);
if( zString[iString]==0 ) return 0;
U8_FWD_1_UNSAFE(zString, iString);
}
zPattern++;
iPattern++;
}
if( *zPattern==0 ) return 1;
if( zPattern[iPattern]==0 ) return 1;
while( *zString ){
if( icuLikeCompare(zPattern, zString, uEsc) ){
while( zString[iString] ){
if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){
return 1;
}
SQLITE_ICU_SKIP_UTF8(zString);
U8_FWD_1_UNSAFE(zString, iString);
}
return 0;
}else if( !prevEscape && uPattern==MATCH_ONE ){
/* Case 2. */
if( *zString==0 ) return 0;
SQLITE_ICU_SKIP_UTF8(zString);
if( zString[iString]==0 ) return 0;
U8_FWD_1_UNSAFE(zString, iString);
}else if( !prevEscape && uPattern==uEsc){
/* Case 3. */
@@ -159,7 +129,7 @@ static int icuLikeCompare(
}else{
/* Case 4. */
UChar32 uString;
SQLITE_ICU_READ_UTF8(zString, uString);
U8_NEXT_UNSAFE(zString, iString, uString);
uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT);
uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT);
if( uString!=uPattern ){
@@ -169,7 +139,7 @@ static int icuLikeCompare(
}
}
return *zString==0;
return zString[iString]==0;
}
/*
@@ -355,11 +325,11 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
*/
static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
const UChar *zInput;
UChar *zOutput = 0;
UChar *zOutput;
int nInput;
int nOut;
int cnt;
UErrorCode status;
int nOutput;
UErrorCode status = U_ZERO_ERROR;
const char *zLocale = 0;
assert(nArg==1 || nArg==2);
@@ -371,34 +341,26 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
if( !zInput ){
return;
}
nOut = nInput = sqlite3_value_bytes16(apArg[0]);
if( nOut==0 ){
sqlite3_result_text16(p, "", 0, SQLITE_STATIC);
nInput = sqlite3_value_bytes16(apArg[0]);
nOutput = nInput * 2 + 2;
zOutput = sqlite3_malloc(nOutput);
if( !zOutput ){
return;
}
for(cnt=0; cnt<2; cnt++){
UChar *zNew = sqlite3_realloc(zOutput, nOut);
if( zNew==0 ){
sqlite3_free(zOutput);
sqlite3_result_error_nomem(p);
return;
}
zOutput = zNew;
status = U_ZERO_ERROR;
if( sqlite3_user_data(p) ){
nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
}else{
nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
}
if( !U_SUCCESS(status) ){
if( status==U_BUFFER_OVERFLOW_ERROR ) continue;
icuFunctionError(p,
sqlite3_user_data(p) ? "u_strToUpper" : "u_strToLower", status);
return;
}
if( sqlite3_user_data(p) ){
u_strToUpper(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
}else{
u_strToLower(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
}
sqlite3_result_text16(p, zOutput, nOut, xFree);
if( !U_SUCCESS(status) ){
icuFunctionError(p, "u_strToLower()/u_strToUpper", status);
return;
}
sqlite3_result_text16(p, zOutput, -1, xFree);
}
/*
+5 -34
View File
@@ -31,11 +31,7 @@ SQLITE_EXTENSION_INIT1
#include <stdlib.h>
#include <stdarg.h>
/* Mark a function parameter as unused, to suppress nuisance compiler
** warnings. */
#ifndef UNUSED_PARAM
# define UNUSED_PARAM(X) (void)(X)
#endif
#define UNUSED_PARAM(X) (void)(X)
#ifndef LARGEST_INT64
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
@@ -280,33 +276,10 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
p->zBuf[p->nUsed++] = '"';
for(i=0; i<N; i++){
unsigned char c = ((unsigned const char*)zIn)[i];
char c = zIn[i];
if( c=='"' || c=='\\' ){
json_simple_escape:
if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
}else if( c<=0x1f ){
static const char aSpecial[] = {
0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
assert( sizeof(aSpecial)==32 );
assert( aSpecial['\b']=='b' );
assert( aSpecial['\f']=='f' );
assert( aSpecial['\n']=='n' );
assert( aSpecial['\r']=='r' );
assert( aSpecial['\t']=='t' );
if( aSpecial[c] ){
c = aSpecial[c];
goto json_simple_escape;
}
if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
p->zBuf[p->nUsed++] = 'u';
p->zBuf[p->nUsed++] = '0';
p->zBuf[p->nUsed++] = '0';
p->zBuf[p->nUsed++] = '0' + (c>>4);
c = "0123456789abcdef"[c&0xf];
}
p->zBuf[p->nUsed++] = c;
}
@@ -347,7 +320,7 @@ static void jsonAppendValue(
default: {
if( p->bErr==0 ){
sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
p->bErr = 2;
p->bErr = 1;
jsonReset(p);
}
break;
@@ -1556,7 +1529,6 @@ static void jsonArrayStep(
sqlite3_value **argv
){
JsonString *pStr;
UNUSED_PARAM(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
@@ -1576,7 +1548,7 @@ static void jsonArrayFinal(sqlite3_context *ctx){
pStr->pCtx = ctx;
jsonAppendChar(pStr, ']');
if( pStr->bErr ){
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
sqlite3_result_error_nomem(ctx);
assert( pStr->bStatic );
}else{
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
@@ -1602,7 +1574,6 @@ static void jsonObjectStep(
JsonString *pStr;
const char *z;
u32 n;
UNUSED_PARAM(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
@@ -1625,7 +1596,7 @@ static void jsonObjectFinal(sqlite3_context *ctx){
if( pStr ){
jsonAppendChar(pStr, '}');
if( pStr->bErr ){
if( pStr->bErr==0 ) sqlite3_result_error_nomem(ctx);
sqlite3_result_error_nomem(ctx);
assert( pStr->bStatic );
}else{
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
+4 -12
View File
@@ -217,14 +217,6 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
}
}
/* True to cause run-time checking of the start=, stop=, and/or step=
** parameters. The only reason to do this is for testing the
** constraint checking logic for virtual tables in the SQLite core.
*/
#ifndef SQLITE_SERIES_CONSTRAINT_VERIFY
# define SQLITE_SERIES_CONSTRAINT_VERIFY 0
#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
@@ -332,20 +324,20 @@ static int seriesBestIndex(
}
if( startIdx>=0 ){
pIdxInfo->aConstraintUsage[startIdx].argvIndex = ++nArg;
pIdxInfo->aConstraintUsage[startIdx].omit= !SQLITE_SERIES_CONSTRAINT_VERIFY;
pIdxInfo->aConstraintUsage[startIdx].omit = 1;
}
if( stopIdx>=0 ){
pIdxInfo->aConstraintUsage[stopIdx].argvIndex = ++nArg;
pIdxInfo->aConstraintUsage[stopIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
pIdxInfo->aConstraintUsage[stopIdx].omit = 1;
}
if( stepIdx>=0 ){
pIdxInfo->aConstraintUsage[stepIdx].argvIndex = ++nArg;
pIdxInfo->aConstraintUsage[stepIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
pIdxInfo->aConstraintUsage[stepIdx].omit = 1;
}
if( (idxNum & 3)==3 ){
/* Both start= and stop= boundaries are available. This is the
** the preferred case */
pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
pIdxInfo->estimatedCost = (double)1;
pIdxInfo->estimatedRows = 1000;
if( pIdxInfo->nOrderBy==1 ){
if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8;
+18 -24
View File
@@ -186,7 +186,7 @@ static const unsigned char className[] = ".ABCDHLRMY9 ?";
** Return NULL if memory allocation fails.
*/
static unsigned char *phoneticHash(const unsigned char *zIn, int nIn){
unsigned char *zOut = sqlite3_malloc64( nIn + 1 );
unsigned char *zOut = sqlite3_malloc( nIn + 1 );
int i;
int nOut = 0;
char cPrev = 0x77;
@@ -413,7 +413,7 @@ static int editdist1(const char *zA, const char *zB, int *pnMatch){
if( nB<(sizeof(mStack)*4)/(sizeof(mStack[0])*5) ){
m = mStack;
}else{
m = toFree = sqlite3_malloc64( (nB+1)*5*sizeof(m[0])/4 );
m = toFree = sqlite3_malloc( (nB+1)*5*sizeof(m[0])/4 );
if( m==0 ) return -3;
}
cx = (char*)&m[nB+1];
@@ -687,7 +687,7 @@ static int editDist3ConfigLoad(
if( iCost<0 ) continue;
if( pLang==0 || iLang!=iLangPrev ){
EditDist3Lang *pNew;
pNew = sqlite3_realloc64(p->a, (p->nLang+1)*sizeof(p->a[0]));
pNew = sqlite3_realloc(p->a, (p->nLang+1)*sizeof(p->a[0]));
if( pNew==0 ){ rc = SQLITE_NOMEM; break; }
p->a = pNew;
pLang = &p->a[p->nLang];
@@ -709,7 +709,7 @@ static int editDist3ConfigLoad(
EditDist3Cost *pCost;
int nExtra = nFrom + nTo - 4;
if( nExtra<0 ) nExtra = 0;
pCost = sqlite3_malloc64( sizeof(*pCost) + nExtra );
pCost = sqlite3_malloc( sizeof(*pCost) + nExtra );
if( pCost==0 ){ rc = SQLITE_NOMEM; break; }
pCost->nFrom = nFrom;
pCost->nTo = nTo;
@@ -808,7 +808,7 @@ static EditDist3FromString *editDist3FromStringNew(
if( z==0 ) return 0;
if( n<0 ) n = (int)strlen(z);
pStr = sqlite3_malloc64( sizeof(*pStr) + sizeof(pStr->a[0])*n + n + 1 );
pStr = sqlite3_malloc( sizeof(*pStr) + sizeof(pStr->a[0])*n + n + 1 );
if( pStr==0 ) return 0;
pStr->a = (EditDist3From*)&pStr[1];
memset(pStr->a, 0, sizeof(pStr->a[0])*n);
@@ -833,13 +833,13 @@ static EditDist3FromString *editDist3FromStringNew(
if( i+p->nFrom>n ) continue;
if( matchFrom(p, z+i, n-i)==0 ) continue;
if( p->nTo==0 ){
apNew = sqlite3_realloc64(pFrom->apDel,
apNew = sqlite3_realloc(pFrom->apDel,
sizeof(*apNew)*(pFrom->nDel+1));
if( apNew==0 ) break;
pFrom->apDel = apNew;
apNew[pFrom->nDel++] = p;
}else{
apNew = sqlite3_realloc64(pFrom->apSubst,
apNew = sqlite3_realloc(pFrom->apSubst,
sizeof(*apNew)*(pFrom->nSubst+1));
if( apNew==0 ) break;
pFrom->apSubst = apNew;
@@ -925,7 +925,7 @@ static int editDist3Core(
m = stackSpace;
pToFree = 0;
}else{
m = pToFree = sqlite3_malloc64( nByte );
m = pToFree = sqlite3_malloc( nByte );
if( m==0 ) return -1; /* Out of memory */
}
a2 = (EditDist3To*)&m[n];
@@ -940,7 +940,7 @@ static int editDist3Core(
if( i2+p->nTo>n2 ) continue;
if( matchTo(p, z2+i2, n2-i2)==0 ) continue;
a2[i2].nIns++;
apNew = sqlite3_realloc64(a2[i2].apIns, sizeof(*apNew)*a2[i2].nIns);
apNew = sqlite3_realloc(a2[i2].apIns, sizeof(*apNew)*a2[i2].nIns);
if( apNew==0 ){
res = -1; /* Out of memory */
goto editDist3Abort;
@@ -1118,7 +1118,7 @@ static void editDist3SqlFunc(
*/
static int editDist3Install(sqlite3 *db){
int rc;
EditDist3Config *pConfig = sqlite3_malloc64( sizeof(*pConfig) );
EditDist3Config *pConfig = sqlite3_malloc( sizeof(*pConfig) );
if( pConfig==0 ) return SQLITE_NOMEM;
memset(pConfig, 0, sizeof(*pConfig));
rc = sqlite3_create_function_v2(db, "editdist3",
@@ -1607,7 +1607,7 @@ static const struct {
** should be freed by the caller.
*/
static unsigned char *transliterate(const unsigned char *zIn, int nIn){
unsigned char *zOut = sqlite3_malloc64( nIn*4 + 1 );
unsigned char *zOut = sqlite3_malloc( nIn*4 + 1 );
int c, sz, nOut;
if( zOut==0 ) return 0;
nOut = 0;
@@ -1734,7 +1734,6 @@ static void scriptCodeSqlFunc(
int c, sz;
int scriptMask = 0;
int res;
int seenDigit = 0;
# define SCRIPT_LATIN 0x0001
# define SCRIPT_CYRILLIC 0x0002
# define SCRIPT_GREEK 0x0004
@@ -1745,12 +1744,8 @@ static void scriptCodeSqlFunc(
c = utf8Read(zIn, nIn, &sz);
zIn += sz;
nIn -= sz;
if( c<0x02af ){
if( c>=0x80 || midClass[c&0x7f]<CCLASS_DIGIT ){
scriptMask |= SCRIPT_LATIN;
}else if( c>='0' && c<='9' ){
seenDigit = 1;
}
if( c<0x02af && (c>=0x80 || midClass[c&0x7f]<CCLASS_DIGIT) ){
scriptMask |= SCRIPT_LATIN;
}else if( c>=0x0400 && c<=0x04ff ){
scriptMask |= SCRIPT_CYRILLIC;
}else if( c>=0x0386 && c<=0x03ce ){
@@ -1761,7 +1756,6 @@ static void scriptCodeSqlFunc(
scriptMask |= SCRIPT_ARABIC;
}
}
if( scriptMask==0 && seenDigit ) scriptMask = SCRIPT_LATIN;
switch( scriptMask ){
case 0: res = 999; break;
case SCRIPT_LATIN: res = 215; break;
@@ -1781,7 +1775,7 @@ static void scriptCodeSqlFunc(
*/
/* Maximum length of a phonehash used for querying the shadow table */
#define SPELLFIX_MX_HASH 32
#define SPELLFIX_MX_HASH 8
/* Maximum number of hash strings to examine per query */
#define SPELLFIX_MX_RUN 1
@@ -1936,7 +1930,7 @@ static int spellfix1Init(
int i;
nDbName = (int)strlen(zDbName);
pNew = sqlite3_malloc64( sizeof(*pNew) + nDbName + 1);
pNew = sqlite3_malloc( sizeof(*pNew) + nDbName + 1);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -2050,7 +2044,7 @@ static void spellfix1ResetCursor(spellfix1_cursor *pCur){
static void spellfix1ResizeCursor(spellfix1_cursor *pCur, int N){
struct spellfix1_row *aNew;
assert( N>=pCur->nRow );
aNew = sqlite3_realloc64(pCur->a, sizeof(pCur->a[0])*N);
aNew = sqlite3_realloc(pCur->a, sizeof(pCur->a[0])*N);
if( aNew==0 && N>0 ){
spellfix1ResetCursor(pCur);
sqlite3_free(pCur->a);
@@ -2209,7 +2203,7 @@ static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
static int spellfix1Open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
spellfix1_vtab *p = (spellfix1_vtab*)pVTab;
spellfix1_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;
@@ -2423,7 +2417,7 @@ static int spellfix1FilterForMatch(
/* Load the cost table if we have not already done so */
if( p->zCostTable!=0 && p->pConfig3==0 ){
p->pConfig3 = sqlite3_malloc64( sizeof(p->pConfig3[0]) );
p->pConfig3 = sqlite3_malloc( sizeof(p->pConfig3[0]) );
if( p->pConfig3==0 ) return SQLITE_NOMEM;
memset(p->pConfig3, 0, sizeof(p->pConfig3[0]));
rc = editDist3ConfigLoad(p->pConfig3, p->db, p->zCostTable);
+1 -1
View File
@@ -611,7 +611,7 @@ foreach {tn3 create_vfs destroy_vfs} {
9 {
CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
CREATE TABLE rbu.data_t1(a, b, rbu_control);
INSERT INTO rbu.data_t1 VALUES(1, 2, 3);
INSERT INTO rbu.data_t1 VALUES(1, 2, 2);
} {SQLITE_ERROR - invalid rbu_control value}
10 {
-142
View File
@@ -1,142 +0,0 @@
# 2016 March 7
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# Tests for RBU focused on the REPLACE operation (rbu_control column
# contains integer value 2).
#
source [file join [file dirname [info script]] rbu_common.tcl]
set ::testprefix rbuC
#-------------------------------------------------------------------------
# This test is actually of an UPDATE directive. Just to establish that
# these work with UNIQUE indexes before preceding to REPLACE.
#
do_execsql_test 1.0 {
CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b, c UNIQUE);
INSERT INTO t1 VALUES(1, 'a', 'b', 'c');
}
forcedelete rbu.db
do_execsql_test 1.1 {
ATTACH 'rbu.db' AS rbu;
CREATE TABLE rbu.data_t1(i, a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(1, 'a', 'b', 'c', '.xxx');
}
do_test 1.2 {
step_rbu test.db rbu.db
} {SQLITE_DONE}
do_execsql_test 1.3 {
SELECT * FROM t1
} {
1 a b c
}
#-------------------------------------------------------------------------
#
foreach {tn schema} {
1 {
CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b, c UNIQUE);
CREATE INDEX t1a ON t1(a);
}
2 {
CREATE TABLE t1(i PRIMARY KEY, a, b, c UNIQUE);
CREATE INDEX t1a ON t1(a);
}
3 {
CREATE TABLE t1(i PRIMARY KEY, a, b, c UNIQUE) WITHOUT ROWID;
CREATE INDEX t1a ON t1(a);
}
} {
reset_db
forcedelete rbu.db
execsql $schema
do_execsql_test 2.$tn.0 {
INSERT INTO t1 VALUES(1, 'a', 'b', 'c');
INSERT INTO t1 VALUES(2, 'b', 'c', 'd');
INSERT INTO t1 VALUES(3, 'c', 'd', 'e');
}
do_execsql_test 2.$tn.1 {
ATTACH 'rbu.db' AS rbu;
CREATE TABLE rbu.data_t1(i, a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(1, 1, 2, 3, 2);
INSERT INTO data_t1 VALUES(3, 'c', 'd', 'e', 2);
INSERT INTO data_t1 VALUES(4, 'd', 'e', 'f', 2);
}
do_test 2.$tn.2 {
step_rbu test.db rbu.db
} {SQLITE_DONE}
do_execsql_test 2.$tn.3 {
SELECT * FROM t1 ORDER BY i
} {
1 1 2 3
2 b c d
3 c d e
4 d e f
}
integrity_check 2.$tn.4
}
foreach {tn schema} {
1 {
CREATE TABLE t1(a, b, c UNIQUE);
CREATE INDEX t1a ON t1(a);
}
2 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
}
} {
if {$tn==2} { ifcapable !fts5 break }
reset_db
forcedelete rbu.db
execsql $schema
do_execsql_test 3.$tn.0 {
INSERT INTO t1 VALUES('a', 'b', 'c');
INSERT INTO t1 VALUES('b', 'c', 'd');
INSERT INTO t1 VALUES('c', 'd', 'e');
}
do_execsql_test 3.$tn.1 {
ATTACH 'rbu.db' AS rbu;
CREATE TABLE rbu.data_t1(rbu_rowid, a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(1, 1, 2, 3, 2);
INSERT INTO data_t1 VALUES(3, 'c', 'd', 'e', 2);
INSERT INTO data_t1 VALUES(4, 'd', 'e', 'f', 2);
}
do_test 3.$tn.2 {
step_rbu test.db rbu.db
} {SQLITE_DONE}
do_execsql_test 3.$tn.3 {
SELECT rowid, * FROM t1 ORDER BY 1
} {
1 1 2 3
2 b c d
3 c d e
4 d e f
}
integrity_check 3.$tn.4
}
finish_test
+10 -23
View File
@@ -18,7 +18,16 @@ if {![info exists testdir]} {
source $testdir/tester.tcl
set testprefix rbudiff
set PROG [test_find_sqldiff]
if {$tcl_platform(platform)=="windows"} {
set PROG "sqldiff.exe"
} else {
set PROG "./sqldiff"
}
if {![file exe $PROG]} {
puts "rbudiff.test cannot run because $PROG is not available"
finish_test
return
}
db close
proc get_rbudiff_sql {db1 db2} {
@@ -36,7 +45,6 @@ proc step_rbu {target rbu} {
}
proc apply_rbudiff {sql target} {
test_rbucount $sql
forcedelete rbu.db
sqlite3 rbudb rbu.db
rbudb eval $sql
@@ -44,27 +52,6 @@ proc apply_rbudiff {sql target} {
step_rbu $target rbu.db
}
# The only argument is the output of an [sqldiff -rbu] run. This command
# tests that the contents of the rbu_count table is correct. An exception
# is thrown if it is not.
#
proc test_rbucount {sql} {
sqlite3 tmpdb ""
tmpdb eval $sql
tmpdb eval {
SELECT name FROM sqlite_master WHERE name LIKE 'data%' AND type='table'
} {
set a [tmpdb eval "SELECT count(*) FROM $name"]
set b [tmpdb eval {SELECT cnt FROM rbu_count WHERE tbl = $name}]
if {$a != $b} {
tmpdb close
error "rbu_count error - tbl = $name"
}
}
tmpdb close
return ""
}
proc rbudiff_cksum {db1} {
set txt ""
-415
View File
@@ -1,415 +0,0 @@
# 2016 March 18
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
source [file join [file dirname [info script]] rbu_common.tcl]
set ::testprefix rbuprogress
proc create_db_file {filename sql} {
forcedelete $filename
sqlite3 tmpdb $filename
tmpdb eval $sql
tmpdb close
}
# Create a simple RBU database. That expects to write to a table:
#
# CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
#
proc create_rbu1 {filename} {
create_db_file $filename {
CREATE TABLE data_t1(a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(1, 2, 3, 0);
INSERT INTO data_t1 VALUES(2, 'two', 'three', 0);
INSERT INTO data_t1 VALUES(3, NULL, 8.2, 0);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data_t1', 3);
}
return $filename
}
do_execsql_test 1.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
}
do_test 1.1 {
create_rbu1 rbu.db
sqlite3rbu rbu test.db rbu.db
rbu bp_progress
} {0 0}
do_test 1.2 { rbu step ; rbu bp_progress } {3333 0}
do_test 1.3 { rbu step ; rbu bp_progress } {6666 0}
do_test 1.4 { rbu step ; rbu bp_progress } {10000 0}
do_test 1.5 { rbu step ; rbu bp_progress } {10000 0}
do_test 1.6 { rbu step ; rbu bp_progress } {10000 0}
do_test 1.7 { rbu step ; rbu bp_progress } {10000 5000}
do_test 1.8 { rbu step ; rbu bp_progress } {10000 10000}
do_test 1.9 { rbu step ; rbu bp_progress } {10000 10000}
do_test 1.10 {
rbu close
} {SQLITE_DONE}
#-------------------------------------------------------------------------
#
proc do_sp_test {tn bReopen target rbu reslist} {
uplevel [list do_test $tn [subst -nocommands {
if {$bReopen==0} { sqlite3rbu rbu $target $rbu }
set res [list]
while 1 {
if {$bReopen} { sqlite3rbu rbu $target $rbu }
set rc [rbu step]
if {[set rc] != "SQLITE_OK"} { rbu close ; error "error 1" }
lappend res [lindex [rbu bp_progress] 0]
if {[lindex [set res] end]==10000} break
if {$bReopen} { rbu close }
}
if {[set res] != [list $reslist]} {
rbu close
error "1. reslist incorrect (expect=$reslist got=[set res])"
}
# One step to clean up the temporary tables used to update the only
# target table in the rbu database. And one more to move the *-oal
# file to *-wal. After each of these steps, the progress remains
# at "10000 0".
#
if {[lindex [list $reslist] 0]!=-1} {
rbu step
set res [rbu bp_progress]
if {[set res] != [list 10000 0]} {
rbu close
error "2. reslist incorrect (expect=10000 0 got=[set res])"
}
}
rbu step
set res [rbu bp_progress]
if {[set res] != [list 10000 0]} {
rbu close
error "3. reslist incorrect (expect=10000 0 got=[set res])"
}
# Do the checkpoint.
while {[rbu step]=="SQLITE_OK"} {
foreach {a b} [rbu bp_progress] {}
if {[set a]!=10000 || [set b]<=0 || [set b]>10000} {
rbu close
error "4. reslist incorrect (expect=10000 1..10000 got=[set a] [set b])"
}
}
set res [rbu bp_progress]
if {[set res] != [list 10000 10000]} {
rbu close
error "5. reslist is incorrect (expect=10000 10000 got=[set res])"
}
rbu close
}] {SQLITE_DONE}]
}
foreach {bReopen} { 0 1 } {
reset_db
do_test 2.$bReopen.1.0 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
}
create_db_file rbu.db {
CREATE TABLE data_t1(a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(4, 4, 4, 0);
INSERT INTO data_t1 VALUES(5, 5, 5, 0);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data_t1', 2);
}
} {}
do_sp_test 2.$bReopen.1.1 $bReopen test.db rbu.db {5000 10000}
reset_db
do_test 2.$bReopen.2.0 {
execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
create_rbu1 rbu.db
} {rbu.db}
do_sp_test 2.$bReopen.2.1 $bReopen test.db rbu.db {3333 6666 10000}
reset_db
do_test 2.$bReopen.3.0 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX i1 ON t1(b);
INSERT INTO t1 VALUES(1, 1, 1);
INSERT INTO t1 VALUES(2, 2, 2);
INSERT INTO t1 VALUES(3, 3, 3);
}
create_db_file rbu.db {
CREATE TABLE data_t1(a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(4, 4, 4, 0);
INSERT INTO data_t1 VALUES(2, NULL, NULL, 1);
INSERT INTO data_t1 VALUES(5, NULL, NULL, 1);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data_t1', 3);
}
} {}
do_sp_test 2.$bReopen.3.1 $bReopen test.db rbu.db {1666 3333 6000 8000 10000}
reset_db
do_test 2.$bReopen.4.0 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX i1 ON t1(b);
INSERT INTO t1 VALUES(1, 1, 1);
INSERT INTO t1 VALUES(2, 2, 2);
INSERT INTO t1 VALUES(3, 3, 3);
}
create_db_file rbu.db {
CREATE TABLE data_t1(a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(2, 4, 4, '.xx');
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data_t1', 1);
}
} {}
do_sp_test 2.$bReopen.4.1 $bReopen test.db rbu.db {3333 6666 10000}
reset_db
do_test 2.$bReopen.5.0 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX i1 ON t1(b);
INSERT INTO t1 VALUES(1, 1, 1);
INSERT INTO t1 VALUES(2, 2, 2);
INSERT INTO t1 VALUES(3, 3, 3);
}
create_db_file rbu.db {
CREATE TABLE data_t1(a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(4, NULL, 4, '.xx');
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data_t1', 1);
}
} {}
do_sp_test 2.$bReopen.5.1 $bReopen test.db rbu.db {10000}
reset_db
do_test 2.$bReopen.6.0 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX i1 ON t1(b);
INSERT INTO t1 VALUES(1, 1, 1);
INSERT INTO t1 VALUES(2, 2, 2);
INSERT INTO t1 VALUES(3, 3, 3);
}
create_db_file rbu.db {
CREATE TABLE data_t1(a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(4, 4, 4, 0);
INSERT INTO data_t1 VALUES(2, NULL, NULL, 1);
INSERT INTO data_t1 VALUES(5, NULL, NULL, 1);
}
} {}
do_sp_test 2.$bReopen.6.1 $bReopen test.db rbu.db {-1 -1 -1 -1 -1 10000}
}
#-------------------------------------------------------------------------
# The following tests verify that the API works when resuming an update
# during the incremental checkpoint stage.
#
proc do_phase2_test {tn bReopen target rbu nStep} {
uplevel [list do_test $tn [subst -nocommands {
# Build the OAL/WAL file:
sqlite3rbu rbu $target $rbu
while {[lindex [rbu bp_progress] 0]<10000} {
set rc [rbu step]
if {"SQLITE_OK" != [set rc]} { rbu close }
}
# Clean up the temp tables and move the *-oal file to *-wal.
rbu step
rbu step
for {set i 0} {[set i] < $nStep} {incr i} {
if {$bReopen} {
rbu close
sqlite3rbu rbu $target $rbu
}
rbu step
set res [rbu bp_progress]
set expect [expr (1 + [set i]) * 10000 / $nStep]
if {[lindex [set res] 1] != [set expect]} {
error "Have [set res], expected 10000 [set expect]"
}
}
set rc [rbu step]
if {[set rc] != "SQLITE_DONE"} {
error "Have [set rc], expected SQLITE_DONE"
}
rbu close
}] {SQLITE_DONE}]
}
foreach bReopen {0 1} {
do_test 3.$bReopen.1.0 {
reset_db
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
}
create_db_file rbu.db {
CREATE TABLE data_t1(a, b, rbu_control);
CREATE TABLE data_t2(a, b, rbu_control);
CREATE TABLE data_t3(a, b, rbu_control);
CREATE TABLE data_t4(a, b, rbu_control);
INSERT INTO data_t1 VALUES(1, 2, 0);
INSERT INTO data_t2 VALUES(1, 2, 0);
INSERT INTO data_t3 VALUES(1, 2, 0);
INSERT INTO data_t4 VALUES(1, 2, 0);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data_t1', 1);
INSERT INTO rbu_count VALUES('data_t2', 1);
INSERT INTO rbu_count VALUES('data_t3', 1);
INSERT INTO rbu_count VALUES('data_t4', 1);
}
} {}
do_phase2_test 3.$bReopen.1.1 $bReopen test.db rbu.db 5
}
foreach {bReopen} { 0 1 } {
foreach {tn tbl} {
ipk { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
wr { CREATE TABLE t1(a INT PRIMARY KEY, b, c) WITHOUT ROWID }
pk { CREATE TABLE t1(a INT PRIMARY KEY, b, c) }
} {
foreach {tn2 rbusql r1 r3} {
1 {
CREATE TABLE data0_t1(a, b, c, rbu_control);
INSERT INTO data0_t1 VALUES(15, 15, 15, 0);
INSERT INTO data0_t1 VALUES(20, 20, 20, 0);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data0_t1', 2);
}
{2500 5000 7500 10000}
{1666 3333 5000 6666 8333 10000}
2 {
CREATE TABLE data0_t1(a, b, c, rbu_control);
INSERT INTO data0_t1 VALUES(10, 10, 10, 2);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data0_t1', 1);
}
{3333 6666 10000}
{2000 4000 6000 8000 10000}
3 {
CREATE TABLE data0_t1(a, b, c, rbu_control);
INSERT INTO data0_t1 VALUES(7, 7, 7, 2);
INSERT INTO data0_t1 VALUES(10, 10, 10, 2);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data0_t1', 2);
}
{2500 4000 6000 8000 10000}
{1666 2500 3750 5000 6250 7500 8750 10000}
} {
reset_db ; execsql $tbl
do_test 4.$tn.$bReopen.$tn2.0 {
execsql {
CREATE INDEX t1c ON t1(c);
INSERT INTO t1 VALUES(1, 1, 1);
INSERT INTO t1 VALUES(5, 5, 5);
INSERT INTO t1 VALUES(10, 10, 10);
}
create_db_file rbu.db $rbusql
} {}
set R(ipk) $r1
set R(wr) $r1
set R(pk) $r3
do_sp_test 4.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn)
}
}
}
foreach {bReopen} { 0 1 } {
foreach {tn tbl} {
nopk {
CREATE TABLE t1(a, b, c);
CREATE INDEX t1c ON t1(c);
}
vtab {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
}
} {
foreach {tn2 rbusql r1 r2} {
1 {
CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control);
INSERT INTO data0_t1 VALUES(15, 15, 15, 4, 0);
INSERT INTO data0_t1 VALUES(20, 20, 20, 5, 0);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data0_t1', 2);
}
{2500 5000 7500 10000}
{5000 10000}
2 {
CREATE TABLE data0_t1(rbu_rowid, a, b, c, rbu_control);
INSERT INTO data0_t1 VALUES(0, 7, 7, 7, 2);
INSERT INTO data0_t1 VALUES(2, 10, 10, 10, 2);
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data0_t1', 2);
}
{2500 4000 6000 8000 10000}
{5000 10000}
3 {
CREATE TABLE data0_t1(rbu_rowid, a, b, c, rbu_control);
INSERT INTO data0_t1 VALUES(1, NULL, NULL, NULL, 1);
INSERT INTO data0_t1 VALUES(2, NULL, NULL, 7, '..x');
CREATE TABLE rbu_count(tbl, cnt);
INSERT INTO rbu_count VALUES('data0_t1', 2);
}
{2500 4000 6000 8000 10000}
{5000 10000}
} {
reset_db ; execsql $tbl
do_test 5.$tn.$bReopen.$tn2.0 {
execsql {
INSERT INTO t1 VALUES(1, 1, 1);
INSERT INTO t1 VALUES(5, 5, 5);
INSERT INTO t1 VALUES(10, 10, 10);
}
create_db_file rbu.db $rbusql
} {}
set R(nopk) $r1
set R(vtab) $r2
do_sp_test 5.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn)
}
}
}
finish_test
+88 -310
View File
@@ -147,15 +147,14 @@
** RBU_STATE_OALSZ:
** Valid if STAGE==1. The size in bytes of the *-oal file.
*/
#define RBU_STATE_STAGE 1
#define RBU_STATE_TBL 2
#define RBU_STATE_IDX 3
#define RBU_STATE_ROW 4
#define RBU_STATE_PROGRESS 5
#define RBU_STATE_CKPT 6
#define RBU_STATE_COOKIE 7
#define RBU_STATE_OALSZ 8
#define RBU_STATE_PHASEONESTEP 9
#define RBU_STATE_STAGE 1
#define RBU_STATE_TBL 2
#define RBU_STATE_IDX 3
#define RBU_STATE_ROW 4
#define RBU_STATE_PROGRESS 5
#define RBU_STATE_CKPT 6
#define RBU_STATE_COOKIE 7
#define RBU_STATE_OALSZ 8
#define RBU_STAGE_OAL 1
#define RBU_STAGE_MOVE 2
@@ -201,7 +200,6 @@ struct RbuState {
i64 nProgress;
u32 iCookie;
i64 iOalSz;
i64 nPhaseOneStep;
};
struct RbuUpdateStmt {
@@ -246,7 +244,6 @@ struct RbuObjIter {
int iTnum; /* Root page of current object */
int iPkTnum; /* If eType==EXTERNAL, root of PK index */
int bUnique; /* Current index is unique */
int nIndex; /* Number of aux. indexes on table zTbl */
/* Statements created by rbuObjIterPrepareAll() */
int nCol; /* Number of columns in current object */
@@ -283,11 +280,10 @@ struct RbuObjIter {
*/
#define RBU_INSERT 1 /* Insert on a main table b-tree */
#define RBU_DELETE 2 /* Delete a row from a main table b-tree */
#define RBU_REPLACE 3 /* Delete and then insert a row */
#define RBU_IDX_DELETE 4 /* Delete a row from an aux. index b-tree */
#define RBU_IDX_INSERT 5 /* Insert on an aux. index b-tree */
#define RBU_IDX_DELETE 3 /* Delete a row from an aux. index b-tree */
#define RBU_IDX_INSERT 4 /* Insert on an aux. index b-tree */
#define RBU_UPDATE 5 /* Update a row in a main table b-tree */
#define RBU_UPDATE 6 /* Update a row in a main table b-tree */
/*
** A single step of an incremental checkpoint - frame iWalFrame of the wal
@@ -300,43 +296,6 @@ struct RbuFrame {
/*
** RBU handle.
**
** nPhaseOneStep:
** If the RBU database contains an rbu_count table, this value is set to
** a running estimate of the number of b-tree operations required to
** finish populating the *-oal file. This allows the sqlite3_bp_progress()
** API to calculate the permyriadage progress of populating the *-oal file
** using the formula:
**
** permyriadage = (10000 * nProgress) / nPhaseOneStep
**
** nPhaseOneStep is initialized to the sum of:
**
** nRow * (nIndex + 1)
**
** for all source tables in the RBU database, where nRow is the number
** of rows in the source table and nIndex the number of indexes on the
** corresponding target database table.
**
** This estimate is accurate if the RBU update consists entirely of
** INSERT operations. However, it is inaccurate if:
**
** * the RBU update contains any UPDATE operations. If the PK specified
** for an UPDATE operation does not exist in the target table, then
** no b-tree operations are required on index b-trees. Or if the
** specified PK does exist, then (nIndex*2) such operations are
** required (one delete and one insert on each index b-tree).
**
** * the RBU update contains any DELETE operations for which the specified
** PK does not exist. In this case no operations are required on index
** b-trees.
**
** * the RBU update contains REPLACE operations. These are similar to
** UPDATE operations.
**
** nPhaseOneStep is updated to account for the conditions above during the
** first pass of each source table. The updated nPhaseOneStep value is
** stored in the rbu_state table if the RBU update is suspended.
*/
struct sqlite3rbu {
int eStage; /* Value of RBU_STATE_STAGE field */
@@ -354,7 +313,6 @@ struct sqlite3rbu {
const char *zVfsName; /* Name of automatically created rbu vfs */
rbu_file *pTargetFd; /* File handle open on target db */
i64 iOalSz;
i64 nPhaseOneStep;
/* The following state variables are used as part of the incremental
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
@@ -1185,7 +1143,6 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
);
}
pIter->nIndex = 0;
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
sqlite3_stmt *pXInfo = 0;
@@ -1199,12 +1156,6 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
}
rbuFinalize(p, pXInfo);
bIndex = 1;
pIter->nIndex++;
}
if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
/* "PRAGMA index_list" includes the main PK b-tree */
pIter->nIndex--;
}
rbuFinalize(p, pList);
@@ -1318,7 +1269,6 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
rbuFinalize(p, pStmt);
rbuObjIterCacheIndexedCols(p, pIter);
assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 );
assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 );
}
return p->rc;
@@ -1872,14 +1822,6 @@ static void rbuTmpInsertFunc(
int rc = SQLITE_OK;
int i;
assert( sqlite3_value_int(apVal[0])!=0
|| p->objiter.eType==RBU_PK_EXTERNAL
|| p->objiter.eType==RBU_PK_NONE
);
if( sqlite3_value_int(apVal[0])!=0 ){
p->nPhaseOneStep += p->objiter.nIndex;
}
for(i=0; rc==SQLITE_OK && i<nVal; i++){
rc = sqlite3_bind_value(p->objiter.pTmpInsert, i+1, apVal[i]);
}
@@ -1967,13 +1909,13 @@ static int rbuObjIterPrepareAll(
);
}else{
zSql = sqlite3_mprintf(
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
"UNION ALL "
"SELECT %s, rbu_control FROM '%q' "
"WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
"UNION ALL "
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
"ORDER BY %s%s",
zCollist, p->zStateDb, pIter->zDataTbl,
zCollist, pIter->zDataTbl,
zCollist, p->zStateDb, pIter->zDataTbl,
zCollist, zLimit
);
}
@@ -2039,17 +1981,17 @@ static int rbuObjIterPrepareAll(
rbuMPrintfExec(p, p->dbMain,
"CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" "
"BEGIN "
" SELECT rbu_tmp_insert(3, %s);"
" SELECT rbu_tmp_insert(2, %s);"
"END;"
"CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" "
"BEGIN "
" SELECT rbu_tmp_insert(3, %s);"
" SELECT rbu_tmp_insert(2, %s);"
"END;"
"CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" "
"BEGIN "
" SELECT rbu_tmp_insert(4, %s);"
" SELECT rbu_tmp_insert(3, %s);"
"END;",
zWrite, zTbl, zOldlist,
zWrite, zTbl, zOldlist,
@@ -2567,12 +2509,14 @@ static int rbuStepType(sqlite3rbu *p, const char **pzMask){
switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
case SQLITE_INTEGER: {
int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
switch( iVal ){
case 0: res = RBU_INSERT; break;
case 1: res = RBU_DELETE; break;
case 2: res = RBU_REPLACE; break;
case 3: res = RBU_IDX_DELETE; break;
case 4: res = RBU_IDX_INSERT; break;
if( iVal==0 ){
res = RBU_INSERT;
}else if( iVal==1 ){
res = RBU_DELETE;
}else if( iVal==2 ){
res = RBU_IDX_DELETE;
}else if( iVal==3 ){
res = RBU_IDX_INSERT;
}
break;
}
@@ -2611,78 +2555,6 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
# define assertColumnName(x,y,z)
#endif
/*
** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
** RBU_IDX_DELETE. This function performs the work of a single
** sqlite3rbu_step() call for the type of operation specified by eType.
*/
static void rbuStepOneOp(sqlite3rbu *p, int eType){
RbuObjIter *pIter = &p->objiter;
sqlite3_value *pVal;
sqlite3_stmt *pWriter;
int i;
assert( p->rc==SQLITE_OK );
assert( eType!=RBU_DELETE || pIter->zIdx==0 );
assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
|| eType==RBU_INSERT || eType==RBU_IDX_INSERT
);
/* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
** statement below does actually delete a row, nPhaseOneStep will be
** incremented by the same amount when SQL function rbu_tmp_insert()
** is invoked by the trigger. */
if( eType==RBU_DELETE ){
p->nPhaseOneStep -= p->objiter.nIndex;
}
if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
pWriter = pIter->pDelete;
}else{
pWriter = pIter->pInsert;
}
for(i=0; i<pIter->nCol; i++){
/* If this is an INSERT into a table b-tree and the table has an
** explicit INTEGER PRIMARY KEY, check that this is not an attempt
** to write a NULL into the IPK column. That is not permitted. */
if( eType==RBU_INSERT
&& pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
&& sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
){
p->rc = SQLITE_MISMATCH;
p->zErrmsg = sqlite3_mprintf("datatype mismatch");
return;
}
if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
continue;
}
pVal = sqlite3_column_value(pIter->pSelect, i);
p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
if( p->rc ) return;
}
if( pIter->zIdx==0
&& (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
){
/* For a virtual table, or a table with no primary key, the
** SELECT statement is:
**
** SELECT <cols>, rbu_control, rbu_rowid FROM ....
**
** Hence column_value(pIter->nCol+1).
*/
assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
}
if( p->rc==SQLITE_OK ){
sqlite3_step(pWriter);
p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
}
}
/*
** This function does the work for an sqlite3rbu_step() call.
**
@@ -2697,36 +2569,78 @@ static void rbuStepOneOp(sqlite3rbu *p, int eType){
static int rbuStep(sqlite3rbu *p){
RbuObjIter *pIter = &p->objiter;
const char *zMask = 0;
int i;
int eType = rbuStepType(p, &zMask);
if( eType ){
assert( eType==RBU_INSERT || eType==RBU_DELETE
|| eType==RBU_REPLACE || eType==RBU_IDX_DELETE
|| eType==RBU_IDX_INSERT || eType==RBU_UPDATE
);
assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
if( pIter->zIdx==0 && eType==RBU_IDX_DELETE ){
rbuBadControlError(p);
}
else if( eType==RBU_REPLACE ){
if( pIter->zIdx==0 ){
p->nPhaseOneStep += p->objiter.nIndex;
rbuStepOneOp(p, RBU_DELETE);
else if(
eType==RBU_INSERT
|| eType==RBU_DELETE
|| eType==RBU_IDX_DELETE
|| eType==RBU_IDX_INSERT
){
sqlite3_value *pVal;
sqlite3_stmt *pWriter;
assert( eType!=RBU_UPDATE );
assert( eType!=RBU_DELETE || pIter->zIdx==0 );
if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
pWriter = pIter->pDelete;
}else{
pWriter = pIter->pInsert;
}
if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
}
else if( eType!=RBU_UPDATE ){
rbuStepOneOp(p, eType);
}
else{
for(i=0; i<pIter->nCol; i++){
/* If this is an INSERT into a table b-tree and the table has an
** explicit INTEGER PRIMARY KEY, check that this is not an attempt
** to write a NULL into the IPK column. That is not permitted. */
if( eType==RBU_INSERT
&& pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
&& sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
){
p->rc = SQLITE_MISMATCH;
p->zErrmsg = sqlite3_mprintf("datatype mismatch");
goto step_out;
}
if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
continue;
}
pVal = sqlite3_column_value(pIter->pSelect, i);
p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
if( p->rc ) goto step_out;
}
if( pIter->zIdx==0
&& (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
){
/* For a virtual table, or a table with no primary key, the
** SELECT statement is:
**
** SELECT <cols>, rbu_control, rbu_rowid FROM ....
**
** Hence column_value(pIter->nCol+1).
*/
assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
}
if( p->rc==SQLITE_OK ){
sqlite3_step(pWriter);
p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
}
}else{
sqlite3_value *pVal;
sqlite3_stmt *pUpdate = 0;
assert( eType==RBU_UPDATE );
p->nPhaseOneStep -= p->objiter.nIndex;
rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
if( pUpdate ){
int i;
for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
char c = zMask[pIter->aiSrcOrder[i]];
pVal = sqlite3_column_value(pIter->pSelect, i);
@@ -2749,6 +2663,8 @@ static int rbuStep(sqlite3rbu *p){
}
}
}
step_out:
return p->rc;
}
@@ -2801,7 +2717,6 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
"(%d, %d), "
"(%d, %lld), "
"(%d, %lld), "
"(%d, %lld), "
"(%d, %lld) ",
p->zStateDb,
RBU_STATE_STAGE, eStage,
@@ -2811,8 +2726,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
RBU_STATE_PROGRESS, p->nProgress,
RBU_STATE_CKPT, p->iWalCksum,
RBU_STATE_COOKIE, (i64)p->pTargetFd->iCookie,
RBU_STATE_OALSZ, p->iOalSz,
RBU_STATE_PHASEONESTEP, p->nPhaseOneStep
RBU_STATE_OALSZ, p->iOalSz
)
);
assert( pInsert==0 || rc==SQLITE_OK );
@@ -2999,10 +2913,6 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
break;
case RBU_STATE_PHASEONESTEP:
pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
break;
default:
rc = SQLITE_CORRUPT;
break;
@@ -3110,100 +3020,6 @@ static void rbuDeleteVfs(sqlite3rbu *p){
}
}
/*
** This user-defined SQL function is invoked with a single argument - the
** name of a table expected to appear in the target database. It returns
** the number of auxilliary indexes on the table.
*/
static void rbuIndexCntFunc(
sqlite3_context *pCtx,
int nVal,
sqlite3_value **apVal
){
sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
sqlite3_stmt *pStmt = 0;
char *zErrmsg = 0;
int rc;
assert( nVal==1 );
rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg,
sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
"WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
);
if( rc!=SQLITE_OK ){
sqlite3_result_error(pCtx, zErrmsg, -1);
}else{
int nIndex = 0;
if( SQLITE_ROW==sqlite3_step(pStmt) ){
nIndex = sqlite3_column_int(pStmt, 0);
}
rc = sqlite3_finalize(pStmt);
if( rc==SQLITE_OK ){
sqlite3_result_int(pCtx, nIndex);
}else{
sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
}
}
sqlite3_free(zErrmsg);
}
/*
** If the RBU database contains the rbu_count table, use it to initialize
** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
** is assumed to contain the same columns as:
**
** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
**
** There should be one row in the table for each data_xxx table in the
** database. The 'tbl' column should contain the name of a data_xxx table,
** and the cnt column the number of rows it contains.
**
** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
** for all rows in the rbu_count table, where nIndex is the number of
** indexes on the corresponding target database table.
*/
static void rbuInitPhaseOneSteps(sqlite3rbu *p){
if( p->rc==SQLITE_OK ){
sqlite3_stmt *pStmt = 0;
int bExists = 0; /* True if rbu_count exists */
p->nPhaseOneStep = -1;
p->rc = sqlite3_create_function(p->dbRbu,
"rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
);
/* Check for the rbu_count table. If it does not exist, or if an error
** occurs, nPhaseOneStep will be left set to -1. */
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
"SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
);
}
if( p->rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pStmt) ){
bExists = 1;
}
p->rc = sqlite3_finalize(pStmt);
}
if( p->rc==SQLITE_OK && bExists ){
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
"SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
"FROM rbu_count"
);
if( p->rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pStmt) ){
p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
}
p->rc = sqlite3_finalize(pStmt);
}
}
}
}
/*
** Open and return a new RBU handle.
*/
@@ -3249,11 +3065,9 @@ sqlite3rbu *sqlite3rbu_open(
if( pState->eStage==0 ){
rbuDeleteOalFile(p);
rbuInitPhaseOneSteps(p);
p->eStage = RBU_STAGE_OAL;
}else{
p->eStage = pState->eStage;
p->nPhaseOneStep = pState->nPhaseOneStep;
}
p->nProgress = pState->nProgress;
p->iOalSz = pState->iOalSz;
@@ -3417,42 +3231,6 @@ sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){
return pRbu->nProgress;
}
/*
** Return permyriadage progress indications for the two main stages of
** an RBU update.
*/
void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
const int MAX_PROGRESS = 10000;
switch( p->eStage ){
case RBU_STAGE_OAL:
if( p->nPhaseOneStep>0 ){
*pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
}else{
*pnOne = -1;
}
*pnTwo = 0;
break;
case RBU_STAGE_MOVE:
*pnOne = MAX_PROGRESS;
*pnTwo = 0;
break;
case RBU_STAGE_CKPT:
*pnOne = MAX_PROGRESS;
*pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
break;
case RBU_STAGE_DONE:
*pnOne = MAX_PROGRESS;
*pnTwo = MAX_PROGRESS;
break;
default:
assert( 0 );
}
}
int sqlite3rbu_savestate(sqlite3rbu *p){
int rc = p->rc;
@@ -3926,7 +3704,7 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
rbu_file *pDb;
sqlite3_mutex_enter(pRbuVfs->mutex);
for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext);
sqlite3_mutex_leave(pRbuVfs->mutex);
return pDb;
}
-42
View File
@@ -400,48 +400,6 @@ int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
*/
sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
/*
** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
** progress indications for the two stages of an RBU update. This API may
** be useful for driving GUI progress indicators and similar.
**
** An RBU update is divided into two stages:
**
** * Stage 1, in which changes are accumulated in an oal/wal file, and
** * Stage 2, in which the contents of the wal file are copied into the
** main database.
**
** The update is visible to non-RBU clients during stage 2. During stage 1
** non-RBU reader clients may see the original database.
**
** If this API is called during stage 2 of the update, output variable
** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
** to a value between 0 and 10000 to indicate the permyriadage progress of
** stage 2. A value of 5000 indicates that stage 2 is half finished,
** 9000 indicates that it is 90% finished, and so on.
**
** If this API is called during stage 1 of the update, output variable
** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
** value to which (*pnOne) is set depends on whether or not the RBU
** database contains an "rbu_count" table. The rbu_count table, if it
** exists, must contain the same columns as the following:
**
** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
**
** There must be one row in the table for each source (data_xxx) table within
** the RBU database. The 'tbl' column should contain the name of the source
** table. The 'cnt' column should contain the number of rows within the
** source table.
**
** If the rbu_count table is present and populated correctly and this
** API is called during stage 1, the *pnOne output variable is set to the
** permyriadage progress of the same stage. If the rbu_count table does
** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count
** table exists but is not correctly populated, the value of the *pnOne
** output variable during stage 1 is undefined.
*/
void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
/*
** Create an RBU VFS named zName that accesses the underlying file-system
** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
-13
View File
@@ -66,7 +66,6 @@ static int test_sqlite3rbu_cmd(
{"create_rbu_delta", 2, ""}, /* 2 */
{"savestate", 2, ""}, /* 3 */
{"dbMain_eval", 3, "SQL"}, /* 4 */
{"bp_progress", 2, ""}, /* 5 */
{0,0,0}
};
int iCmd;
@@ -137,18 +136,6 @@ static int test_sqlite3rbu_cmd(
break;
}
case 5: /* bp_progress */ {
int one, two;
Tcl_Obj *pObj;
sqlite3rbu_bp_progress(pRbu, &one, &two);
pObj = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, pObj, Tcl_NewIntObj(one));
Tcl_ListObjAppendElement(interp, pObj, Tcl_NewIntObj(two));
Tcl_SetObjResult(interp, pObj);
break;
}
default: /* seems unlikely */
assert( !"cannot happen" );
break;
+1 -1
View File
@@ -1741,7 +1741,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
return SQLITE_NOMEM;
}
nRow = pRtree->nRowEst >> (iIdx/2);
nRow = pRtree->nRowEst / (iIdx + 1);
pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
setEstimatedRows(pIdxInfo, nRow);
+9 -22
View File
@@ -61,7 +61,7 @@ LIBOBJ+= vdbe.o parse.o \
fts3_tokenize_vtab.o \
fts3_unicode.o fts3_unicode2.o \
fts3_write.o fts5.o func.o global.o hash.o \
icu.o insert.o json1.o legacy.o loadext.o \
icu.o insert.o journal.o json1.o legacy.o loadext.o \
main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
memjournal.o \
mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \
@@ -104,6 +104,7 @@ SRC = \
$(TOP)/src/hash.h \
$(TOP)/src/hwtime.h \
$(TOP)/src/insert.c \
$(TOP)/src/journal.c \
$(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \
$(TOP)/src/main.c \
@@ -284,7 +285,6 @@ TESTSRC = \
$(TOP)/src/test_autoext.c \
$(TOP)/src/test_async.c \
$(TOP)/src/test_backup.c \
$(TOP)/src/test_bestindex.c \
$(TOP)/src/test_blob.c \
$(TOP)/src/test_btree.c \
$(TOP)/src/test_config.c \
@@ -480,12 +480,6 @@ sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
$(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \
$(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB)
srcck1$(EXE): $(TOP)/tool/srcck1.c
$(BCC) -o srcck1$(EXE) $(TOP)/tool/srcck1.c
sourcetest: srcck1$(EXE) sqlite3.c
./srcck1 sqlite3.c
fuzzershell$(EXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
$(TCCX) -o fuzzershell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
$(FUZZERSHELL_OPT) $(TOP)/tool/fuzzershell.c sqlite3.c \
@@ -500,9 +494,10 @@ mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c
$(TCCX) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \
$(TLIBS) $(THREADLIB)
MPTEST1=./mptester$(EXE) mptest1.db $(TOP)/mptest/crash01.test --repeat 20
MPTEST2=./mptester$(EXE) mptest2.db $(TOP)/mptest/multiwrite01.test --repeat 20
MPTEST1=./mptester$(EXE) mptest.db $(TOP)/mptest/crash01.test --repeat 20
MPTEST2=./mptester$(EXE) mptest.db $(TOP)/mptest/multiwrite01.test --repeat 20
mptest: mptester$(EXE)
rm -f mptest.db
$(MPTEST1) --journalmode DELETE
$(MPTEST2) --journalmode WAL
$(MPTEST1) --journalmode WAL
@@ -725,9 +720,7 @@ sqlite3_analyzer$(EXE): sqlite3_analyzer.c
# Rules to build the 'testfixture' application.
#
TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
@@ -775,7 +768,7 @@ quicktest: ./testfixture$(EXE)
# The default test case. Runs most of the faster standard TCL tests,
# and fuzz tests, and sqlite3_analyzer and sqldiff tests.
#
test: $(TESTPROGS) sourcetest fastfuzztest
test: $(TESTPROGS) fastfuzztest
./testfixture$(EXE) $(TOP)/test/veryquick.test $(TESTOPTS)
# Run a test using valgrind. This can take a really long time
@@ -864,15 +857,10 @@ loadfts: $(TOP)/tool/loadfts.c libsqlite3.a
checksymbols: sqlite3.o
nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0
# Build the amalgamation-autoconf package. The amalamgation-tarball target builds
# a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz.
# The snapshot-tarball target builds a tarball named by the SHA1 hash
# Build the amalgamation-autoconf package.
#
amalgamation-tarball: sqlite3.c
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
snapshot-tarball: sqlite3.c
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh
# Standard install and cleanup targets
@@ -905,7 +893,6 @@ clean:
rm -f speedtest1 speedtest1.exe
rm -f wordcount wordcount.exe
rm -f rbu rbu.exe
rm -f srcck1 srcck1.exe
rm -f sqlite3.c sqlite3-*.c fts?amal.c tclsqlite3.c
rm -f sqlite3rc.h
rm -f shell.c sqlite3ext.h
+309 -346
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
92dc59fd5ad66f646666042eb04195e3a61a9e8e
ec653cbcae74ecab4ec9df0548d5836e81dc5d14
+1 -31
View File
@@ -41,7 +41,6 @@
#else
# include <unistd.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -1245,19 +1244,6 @@ static void usage(const char *argv0){
if( isDirSep(argv0[i]) ) zTail = argv0+i+1;
}
fprintf(stderr,"Usage: %s DATABASE ?OPTIONS? ?SCRIPT?\n", zTail);
fprintf(stderr,
"Options:\n"
" --errlog FILENAME Write errors to FILENAME\n"
" --journalmode MODE Use MODE as the journal_mode\n"
" --log FILENAME Log messages to FILENAME\n"
" --quiet Suppress unnecessary output\n"
" --vfs NAME Use NAME as the VFS\n"
" --repeat N Repeat the test N times\n"
" --sqltrace Enable SQL tracing\n"
" --sync Enable synchronous disk writes\n"
" --timeout MILLISEC Busy timeout is MILLISEC\n"
" --trace BOOLEAN Enable or disable tracing\n"
);
exit(1);
}
@@ -1289,8 +1275,6 @@ int SQLITE_CDECL main(int argc, char **argv){
const char *zJMode;
const char *zNRep;
int nRep = 1, iRep;
int iTmout = 0; /* Default: no timeout */
const char *zTmout;
g.argv0 = argv[0];
g.iTrace = 1;
@@ -1317,8 +1301,6 @@ int SQLITE_CDECL main(int argc, char **argv){
zTrace = findOption(argv+2, &n, "trace", 1);
if( zTrace ) g.iTrace = atoi(zTrace);
if( findOption(argv+2, &n, "quiet", 0)!=0 ) g.iTrace = 0;
zTmout = findOption(argv+2, &n, "timeout", 1);
if( zTmout ) iTmout = atoi(zTmout);
g.bSqlTrace = findOption(argv+2, &n, "sqltrace", 0)!=0;
g.bSync = findOption(argv+2, &n, "sync", 0)!=0;
if( g.zErrLog ){
@@ -1339,7 +1321,6 @@ int SQLITE_CDECL main(int argc, char **argv){
sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.client%02d",
GETPID(), iClient);
}else{
int nTry = 0;
if( g.iTrace>0 ){
printf("BEGIN: %s", argv[0]);
for(i=1; i<argc; i++) printf(" %s", argv[i]);
@@ -1351,22 +1332,11 @@ int SQLITE_CDECL main(int argc, char **argv){
fflush(stdout);
}
iClient = 0;
do{
if( (nTry%5)==4 ) printf("... %strying to unlink '%s'\n",
nTry>5 ? "still " : "", g.zDbFile);
rc = unlink(g.zDbFile);
if( rc && errno==ENOENT ) rc = 0;
}while( rc!=0 && (++nTry)<60 && sqlite3_sleep(1000)>0 );
if( rc!=0 ){
fatalError("unable to unlink '%s' after %d attempts\n",
g.zDbFile, nTry);
}
unlink(g.zDbFile);
openFlags |= SQLITE_OPEN_CREATE;
}
rc = sqlite3_open_v2(g.zDbFile, &g.db, openFlags, g.zVfs);
if( rc ) fatalError("cannot open [%s]", g.zDbFile);
if( iTmout>0 ) sqlite3_busy_timeout(g.db, iTmout);
if( zJMode ){
#if defined(_WIN32)
if( sqlite3_stricmp(zJMode,"persist")==0
+43 -16
View File
@@ -229,7 +229,7 @@ static void renameTriggerFunc(
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(void){
static FuncDef aAlterTableFuncs[] = {
static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
#ifndef SQLITE_OMIT_TRIGGER
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
@@ -238,7 +238,13 @@ void sqlite3AlterFunctions(void){
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
#endif
};
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
for(i=0; i<ArraySize(aAlterTableFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
}
/*
@@ -582,6 +588,33 @@ exit_rename_table:
db->flags = savedDbFlags;
}
/*
** Generate code to make sure the file format number is at least minFormat.
** The generated code will increase the file format number if necessary.
*/
void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
Vdbe *v;
v = sqlite3GetVdbe(pParse);
/* The VDBE should have been allocated before this routine is called.
** If that allocation failed, we would have quit before reaching this
** point */
if( ALWAYS(v) ){
int r1 = sqlite3GetTempReg(pParse);
int r2 = sqlite3GetTempReg(pParse);
int addr1;
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
addr1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
sqlite3VdbeJumpHere(v, addr1);
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
}
/*
** This function is called after an "ALTER TABLE ... ADD" statement
** has been parsed. Argument pColDef contains the text of the new
@@ -600,11 +633,9 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
Column *pCol; /* The new column */
Expr *pDflt; /* Default value for the new column */
sqlite3 *db; /* The database connection; */
Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
db = pParse->db;
if( pParse->nErr || db->mallocFailed ) return;
assert( v!=0 );
pNew = pParse->pNewTable;
assert( pNew );
@@ -628,8 +659,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** literal NULL, then set pDflt to 0. This simplifies checking
** for an SQL NULL default below.
*/
assert( pDflt==0 || pDflt->op==TK_SPAN );
if( pDflt && pDflt->pLeft->op==TK_NULL ){
if( pDflt && pDflt->op==TK_NULL ){
pDflt = 0;
}
@@ -665,7 +695,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
if( rc!=SQLITE_OK ){
assert( db->mallocFailed == 1 );
db->mallocFailed = 1;
return;
}
if( !pVal ){
@@ -695,16 +725,11 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
db->flags = savedDbFlags;
}
/* If the default value of the new column is NULL, then the file
/* If the default value of the new column is NULL, then set the file
** format to 2. If the default value of the new column is not NULL,
** the file format be 3. Back when this feature was first added
** in 2006, we went to the trouble to upgrade the file format to the
** minimum support values. But 10-years on, we can assume that all
** extent versions of SQLite support file-format 4, so we always and
** unconditionally upgrade to 4.
** the file format becomes 3.
*/
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT,
SQLITE_MAX_FILE_FORMAT);
sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
/* Reload the schema of the modified table. */
reloadTableSchema(pParse, pTab, pTab->zName);
@@ -778,7 +803,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName);
if( !pNew->aCol || !pNew->zName ){
assert( db->mallocFailed );
db->mallocFailed = 1;
goto exit_begin_add_column;
}
memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
@@ -786,7 +811,9 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
Column *pCol = &pNew->aCol[i];
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
pCol->zColl = 0;
pCol->zType = 0;
pCol->pDflt = 0;
pCol->zDflt = 0;
}
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset;
+20 -16
View File
@@ -313,7 +313,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
assert( db!=0 );
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
p->u.aRowid = sqlite3DbMallocRawNN(db, n);
p->u.aRowid = sqlite3DbMallocRaw(db, n);
if( p->u.aRowid ){
p->nRowid = n;
memcpy(p->u.aRowid, pData, n);
@@ -481,7 +481,8 @@ static const FuncDef statInitFuncdef = {
statInit, /* xSFunc */
0, /* xFinalize */
"stat_init", /* zName */
{0}
0, /* pHash */
0 /* pDestructor */
};
#ifdef SQLITE_ENABLE_STAT4
@@ -780,7 +781,8 @@ static const FuncDef statPushFuncdef = {
statPush, /* xSFunc */
0, /* xFinalize */
"stat_push", /* zName */
{0}
0, /* pHash */
0 /* pDestructor */
};
#define STAT_GET_STAT1 0 /* "stat" column of stat1 table */
@@ -925,7 +927,8 @@ static const FuncDef statGetFuncdef = {
statGet, /* xSFunc */
0, /* xFinalize */
"stat_get", /* zName */
{0}
0, /* pHash */
0 /* pDestructor */
};
static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
@@ -1112,7 +1115,7 @@ static void analyzeOneTable(
if( nColTest>0 ){
int endDistinctTest = sqlite3VdbeMakeLabel(v);
int *aGotoChng; /* Array of jump instruction addresses */
aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest);
aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest);
if( aGotoChng==0 ) continue;
/*
@@ -1520,7 +1523,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
** the old data with the new instead of allocating a new array. */
if( pIndex->aiRowEst==0 ){
pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol);
if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db);
if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1;
}
aiRowEst = pIndex->aiRowEst;
#endif
@@ -1667,10 +1670,10 @@ static int loadStatTbl(
Index *pPrevIdx = 0; /* Previous index in the loop */
IndexSample *pSample; /* A slot in pIdx->aSample[] */
assert( db->lookaside.bDisable );
assert( db->lookaside.bEnabled==0 );
zSql = sqlite3MPrintf(db, zSql1, zDb);
if( !zSql ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
@@ -1710,7 +1713,7 @@ static int loadStatTbl(
pIdx->aSample = sqlite3DbMallocZero(db, nByte);
if( pIdx->aSample==0 ){
sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
@@ -1726,7 +1729,7 @@ static int loadStatTbl(
zSql = sqlite3MPrintf(db, zSql2, zDb);
if( !zSql ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
@@ -1764,7 +1767,7 @@ static int loadStatTbl(
pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
if( pSample->p==0 ){
sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
pIdx->nSample++;
@@ -1781,7 +1784,7 @@ static int loadStatTbl(
static int loadStat4(sqlite3 *db, const char *zDb){
int rc = SQLITE_OK; /* Result codes from subroutines */
assert( db->lookaside.bDisable );
assert( db->lookaside.bEnabled==0 );
if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
rc = loadStatTbl(db, 0,
"SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
@@ -1853,7 +1856,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
zSql = sqlite3MPrintf(db,
"SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
if( zSql==0 ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
sqlite3DbFree(db, zSql);
@@ -1863,9 +1866,10 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
db->lookaside.bDisable++;
int lookasideEnabled = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
rc = loadStat4(db, sInfo.zDatabase);
db->lookaside.bDisable--;
db->lookaside.bEnabled = lookasideEnabled;
}
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
@@ -1875,7 +1879,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
#endif
if( rc==SQLITE_NOMEM ){
sqlite3OomFault(db);
db->mallocFailed = 1;
}
return rc;
}
+11 -10
View File
@@ -109,7 +109,7 @@ static void attachFunc(
** hash tables.
*/
if( db->aDb==db->aDbStatic ){
aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 );
if( aNew==0 ) return;
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
@@ -127,7 +127,7 @@ static void attachFunc(
flags = db->openFlags;
rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
return;
@@ -144,7 +144,7 @@ static void attachFunc(
Pager *pPager;
aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
if( !aNew->pSchema ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
zErrDyn = sqlite3MPrintf(db,
"attached databases must use the same text encoding as main database");
@@ -156,15 +156,14 @@ static void attachFunc(
sqlite3BtreeSecureDelete(aNew->pBt,
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
sqlite3BtreeSetPagerFlags(aNew->pBt,
PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK));
sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
#endif
sqlite3BtreeLeave(aNew->pBt);
}
aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
aNew->safety_level = 3;
aNew->zName = sqlite3DbStrDup(db, zName);
if( rc==SQLITE_OK && aNew->zName==0 ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}
@@ -230,7 +229,7 @@ static void attachFunc(
sqlite3ResetAllSchemasOfConnection(db);
db->nDb = iDb;
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db);
db->mallocFailed = 1;
sqlite3DbFree(db, zErrDyn);
zErrDyn = sqlite3MPrintf(db, "out of memory");
}else if( zErrDyn==0 ){
@@ -392,7 +391,8 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
detachFunc, /* xSFunc */
0, /* xFinalize */
"sqlite_detach", /* zName */
{0}
0, /* pHash */
0 /* pDestructor */
};
codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
}
@@ -411,7 +411,8 @@ void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
attachFunc, /* xSFunc */
0, /* xFinalize */
"sqlite_attach", /* zName */
{0}
0, /* pHash */
0 /* pDestructor */
};
codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
}
+3 -3
View File
@@ -88,7 +88,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
if( pParse==0 ){
sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory");
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}else{
pParse->db = pDb;
if( sqlite3OpenTempDatabase(pParse) ){
@@ -182,7 +182,7 @@ sqlite3_backup *sqlite3_backup_init(
** sqlite3_backup_finish(). */
p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
if( !p ){
sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT);
sqlite3Error(pDestDb, SQLITE_NOMEM);
}
}
@@ -581,7 +581,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
}
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}
p->rc = rc;
}
+2 -2
View File
@@ -177,7 +177,7 @@ int sqlite3BitvecSet(Bitvec *p, u32 i){
i = i%p->iDivisor;
if( p->u.apSub[bin]==0 ){
p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT;
if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
}
p = p->u.apSub[bin];
}
@@ -212,7 +212,7 @@ bitvec_set_rehash:
int rc;
u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
if( aiValues==0 ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}else{
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
memset(p->u.apSub, 0, sizeof(p->u.apSub));
+68 -76
View File
@@ -350,7 +350,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
if( !pLock ){
pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock));
if( !pLock ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
pLock->iTable = iTable;
pLock->pBtree = p;
@@ -553,7 +553,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
assert( pgno<=pBt->nPage );
pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
if( !pBt->pHasContent ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}
}
if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){
@@ -632,7 +632,7 @@ static int saveCursorKey(BtCursor *pCur){
sqlite3_free(pKey);
}
}else{
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}
}
assert( !pCur->curIntKey || !pCur->pKey );
@@ -764,7 +764,7 @@ static int btreeMoveto(
pIdxKey = sqlite3VdbeAllocUnpackedRecord(
pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
);
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
if( pIdxKey==0 ) return SQLITE_NOMEM;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
sqlite3DbFree(pCur->pKeyInfo->db, pFree);
@@ -2176,7 +2176,7 @@ int sqlite3BtreeOpen(
}
p = sqlite3MallocZero(sizeof(Btree));
if( !p ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
p->inTrans = TRANS_NONE;
p->db = db;
@@ -2200,7 +2200,7 @@ int sqlite3BtreeOpen(
p->sharable = 1;
if( !zFullPathname ){
sqlite3_free(p);
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
if( isMemdb ){
memcpy(zFullPathname, zFilename, nFilename);
@@ -2268,7 +2268,7 @@ int sqlite3BtreeOpen(
pBt = sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
goto btree_open_out;
}
rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
@@ -2337,7 +2337,8 @@ int sqlite3BtreeOpen(
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
if( pBt->mutex==0 ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
db->mallocFailed = 0;
goto btree_open_out;
}
}
@@ -2360,12 +2361,12 @@ int sqlite3BtreeOpen(
for(i=0; i<db->nDb; i++){
if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
while( pSib->pPrev ){ pSib = pSib->pPrev; }
if( (uptr)p->pBt<(uptr)pSib->pBt ){
if( p->pBt<pSib->pBt ){
p->pNext = pSib;
p->pPrev = 0;
pSib->pPrev = p;
}else{
while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){
while( pSib->pNext && pSib->pNext->pBt<p->pBt ){
pSib = pSib->pNext;
}
p->pNext = pSib->pNext;
@@ -2619,6 +2620,21 @@ int sqlite3BtreeSetPagerFlags(
}
#endif
/*
** Return TRUE if the given btree is set to safety level 1. In other
** words, return TRUE if no sync() occurs on the disk files.
*/
int sqlite3BtreeSyncDisabled(Btree *p){
BtShared *pBt = p->pBt;
int rc;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
assert( pBt && pBt->pPager );
rc = sqlite3PagerNosync(pBt->pPager);
sqlite3BtreeLeave(p);
return rc;
}
/*
** Change the default pages size and the number of reserved bytes per page.
** Or, if the page size has already been fixed, return SQLITE_READONLY
@@ -2864,25 +2880,9 @@ static int lockBtree(BtShared *pBt){
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
goto page1_init_failed;
}else{
#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
sqlite3 *db;
Db *pDb;
if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
if( pDb->bSyncSet==0
&& pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1
){
pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1;
sqlite3PagerSetFlags(pBt->pPager,
pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
}
}
#endif
if( isOpen==0 ){
releasePage(pPage1);
return SQLITE_OK;
}
}else if( isOpen==0 ){
releasePage(pPage1);
return SQLITE_OK;
}
rc = SQLITE_NOTADB;
}
@@ -4115,7 +4115,7 @@ static int btreeCursor(
if( wrFlag ){
allocateTempSpace(pBt);
if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM;
}
if( iTable==1 && btreePagecount(pBt)==0 ){
assert( wrFlag==0 );
@@ -4472,13 +4472,8 @@ static int accessPayload(
#endif
assert( offset+amt <= pCur->info.nPayload );
assert( aPayload > pPage->aData );
if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
/* Trying to read or write past the end of the data is an error. The
** conditional above is really:
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
** but is recast into its current form to avoid integer overflow problems
*/
if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){
/* Trying to read or write past the end of the data is an error */
return SQLITE_CORRUPT_BKPT;
}
@@ -4518,7 +4513,7 @@ static int accessPayload(
pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
if( aNew==0 ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}else{
pCur->nOvflAlloc = nOvfl*2;
pCur->aOverflow = aNew;
@@ -5223,7 +5218,7 @@ int sqlite3BtreeMovetoUnpacked(
}
pCellKey = sqlite3Malloc( nCell+18 );
if( pCellKey==0 ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
goto moveto_finish;
}
pCur->aiIdx[pCur->iPage] = (u16)idx;
@@ -6154,7 +6149,7 @@ static int fillInCell(
{
CellInfo info;
pPage->xParseCell(pPage, pCell, &info);
assert( nHeader==(int)(info.pPayload - pCell) );
assert( nHeader=(int)(info.pPayload - pCell) );
assert( info.nKey==nKey );
assert( *pnSize == info.nSize );
assert( spaceLeft == info.nLocal );
@@ -7042,7 +7037,7 @@ static int balance_nonroot(
assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
if( !aOvflSpace ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
/* Find the sibling pages to balance. Also locate the cells in pParent
@@ -7142,7 +7137,7 @@ static int balance_nonroot(
assert( szScratch<=6*(int)pBt->pageSize );
b.apCell = sqlite3ScratchMalloc( szScratch );
if( b.apCell==0 ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
goto balance_cleanup;
}
b.szCell = (u16*)&b.apCell[nMaxCells];
@@ -7577,9 +7572,9 @@ static int balance_nonroot(
** any cell). But it is important to pass the correct size to
** insertCell(), so reparse the cell now.
**
** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
** and WITHOUT ROWID tables with exactly one column which is the
** primary key.
** Note that this can never happen in an SQLite data file, as all
** cells are at least 4 bytes. It only happens in b-trees used
** to evaluate "IN (SELECT ...)" and similar clauses.
*/
if( b.szCell[j]==4 ){
assert(leafCorrection==4);
@@ -7813,8 +7808,8 @@ static int balance(BtCursor *pCur){
u8 aBalanceQuickSpace[13];
u8 *pFree = 0;
VVA_ONLY( int balance_quick_called = 0 );
VVA_ONLY( int balance_deeper_called = 0 );
TESTONLY( int balance_quick_called = 0 );
TESTONLY( int balance_deeper_called = 0 );
do {
int iPage = pCur->iPage;
@@ -7827,8 +7822,7 @@ static int balance(BtCursor *pCur){
** and copy the current contents of the root-page to it. The
** next iteration of the do-loop will balance the child page.
*/
assert( balance_deeper_called==0 );
VVA_ONLY( balance_deeper_called++ );
assert( (balance_deeper_called++)==0 );
rc = balance_deeper(pPage, &pCur->apPage[1]);
if( rc==SQLITE_OK ){
pCur->iPage = 1;
@@ -7867,8 +7861,7 @@ static int balance(BtCursor *pCur){
** function. If this were not verified, a subtle bug involving reuse
** of the aBalanceQuickSpace[] might sneak in.
*/
assert( balance_quick_called==0 );
VVA_ONLY( balance_quick_called++ );
assert( (balance_quick_called++)==0 );
rc = balance_quick(pParent, pPage, aBalanceQuickSpace);
}else
#endif
@@ -8140,28 +8133,6 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
pPage = pCur->apPage[iCellDepth];
pCell = findCell(pPage, iCellIdx);
/* If the bPreserve flag is set to true, then the cursor position must
** be preserved following this delete operation. If the current delete
** will cause a b-tree rebalance, then this is done by saving the cursor
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
** returning.
**
** Or, if the current delete will not cause a rebalance, then the cursor
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
** before or after the deleted entry. In this case set bSkipnext to true. */
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
){
/* A b-tree rebalance will be required after deleting this entry.
** Save the cursor key. */
rc = saveCursorKey(pCur);
if( rc ) return rc;
}else{
bSkipnext = 1;
}
}
/* If the page containing the entry to delete is not a leaf page, move
** the cursor to the largest entry in the tree that is smaller than
** the entry being deleted. This cell will replace the cell being deleted
@@ -8188,6 +8159,28 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
}
/* If the bPreserve flag is set to true, then the cursor position must
** be preserved following this delete operation. If the current delete
** will cause a b-tree rebalance, then this is done by saving the cursor
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
** returning.
**
** Or, if the current delete will not cause a rebalance, then the cursor
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
** before or after the deleted entry. In this case set bSkipnext to true. */
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
){
/* A b-tree rebalance will be required after deleting this entry.
** Save the cursor key. */
rc = saveCursorKey(pCur);
if( rc ) return rc;
}else{
bSkipnext = 1;
}
}
/* Make the page containing the entry to be deleted writable. Then free any
** overflow pages associated with the entry and finally remove the cell
** itself from within the page. */
@@ -8246,7 +8239,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
if( rc==SQLITE_OK ){
if( bSkipnext ){
assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB );
assert( pPage==pCur->apPage[pCur->iPage] );
assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
pCur->eState = CURSOR_SKIPNEXT;
if( iCellIdx>=pPage->nCell ){
@@ -9335,8 +9328,7 @@ char *sqlite3BtreeIntegrityCheck(
sqlite3BtreeEnter(p);
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
assert( nRef>=0 );
assert( (nRef = sqlite3PagerRefcount(pBt->pPager))>=0 );
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = btreePagecount(sCheck.pBt);
+1
View File
@@ -68,6 +68,7 @@ int sqlite3BtreeSetSpillSize(Btree*,int);
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
#endif
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
int sqlite3BtreeGetPageSize(Btree*);
int sqlite3BtreeMaxPageCount(Btree*,int);
+110 -119
View File
@@ -78,7 +78,7 @@ void sqlite3TableLock(
p->zName = zName;
}else{
pToplevel->nTableLock = 0;
sqlite3OomFault(pToplevel->db);
pToplevel->db->mallocFailed = 1;
}
}
@@ -571,6 +571,8 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
for(i=0; i<pTable->nCol; i++, pCol++){
sqlite3DbFree(db, pCol->zName);
sqlite3ExprDelete(db, pCol->pDflt);
sqlite3DbFree(db, pCol->zDflt);
sqlite3DbFree(db, pCol->zType);
sqlite3DbFree(db, pCol->zColl);
}
sqlite3DbFree(db, pTable->aCol);
@@ -708,8 +710,12 @@ int sqlite3FindDbName(sqlite3 *db, const char *zName){
int i = -1; /* Database number */
if( zName ){
Db *pDb;
int n = sqlite3Strlen30(zName);
for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
if( 0==sqlite3StrICmp(pDb->zName, zName) ) break;
if( (!OMIT_TEMPDB || i!=1 ) && n==sqlite3Strlen30(pDb->zName) &&
0==sqlite3StrICmp(pDb->zName, zName) ){
break;
}
}
}
return i;
@@ -920,8 +926,8 @@ void sqlite3StartTable(
pTable = sqlite3DbMallocZero(db, sizeof(Table));
if( pTable==0 ){
assert( db->mallocFailed );
pParse->rc = SQLITE_NOMEM_BKPT;
db->mallocFailed = 1;
pParse->rc = SQLITE_NOMEM;
pParse->nErr++;
goto begin_table_error;
}
@@ -977,8 +983,10 @@ void sqlite3StartTable(
addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
1 : SQLITE_MAX_FILE_FORMAT;
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db));
sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3);
sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3);
sqlite3VdbeJumpHere(v, addr1);
/* This just creates a place-holder record in the sqlite_master table.
@@ -1037,11 +1045,10 @@ void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
** first to get things going. Then this routine is called for each
** column.
*/
void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
void sqlite3AddColumn(Parse *pParse, Token *pName){
Table *p;
int i;
char *z;
char *zType;
Column *pCol;
sqlite3 *db = pParse->db;
if( (p = pParse->pNewTable)==0 ) return;
@@ -1051,11 +1058,8 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
return;
}
#endif
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
z = sqlite3NameFromToken(db, pName);
if( z==0 ) return;
memcpy(z, pName->z, pName->n);
z[pName->n] = 0;
sqlite3Dequote(z);
for(i=0; i<p->nCol; i++){
if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
@@ -1077,21 +1081,13 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
pCol->zName = z;
sqlite3ColumnPropertiesFromName(p, pCol);
if( pType->n==0 ){
/* If there is no type specified, columns have the default affinity
** 'BLOB'. */
pCol->affinity = SQLITE_AFF_BLOB;
pCol->szEst = 1;
}else{
zType = z + sqlite3Strlen30(z) + 1;
memcpy(zType, pType->z, pType->n);
zType[pType->n] = 0;
sqlite3Dequote(zType);
pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
pCol->colFlags |= COLFLAG_HASTYPE;
}
/* If there is no type specified, columns have the default affinity
** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will
** be called next to set pCol->affinity correctly.
*/
pCol->affinity = SQLITE_AFF_BLOB;
pCol->szEst = 1;
p->nCol++;
pParse->constraintName.n = 0;
}
/*
@@ -1137,7 +1133,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
char aff = SQLITE_AFF_NUMERIC;
const char *zChar = 0;
assert( zIn!=0 );
if( zIn==0 ) return aff;
while( zIn[0] ){
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
zIn++;
@@ -1194,6 +1190,28 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
return aff;
}
/*
** This routine is called by the parser while in the middle of
** parsing a CREATE TABLE statement. The pFirst token is the first
** token in the sequence of tokens that describe the type of the
** column currently under construction. pLast is the last token
** in the sequence. Use this information to construct a string
** that contains the typename of the column and store that string
** in zType.
*/
void sqlite3AddColumnType(Parse *pParse, Token *pType){
Table *p;
Column *pCol;
p = pParse->pNewTable;
if( p==0 || NEVER(p->nCol<1) ) return;
pCol = &p->aCol[p->nCol-1];
assert( pCol->zType==0 || CORRUPT_DB );
sqlite3DbFree(pParse->db, pCol->zType);
pCol->zType = sqlite3NameFromToken(pParse->db, pType);
pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
}
/*
** The expression is the default value for the most recently added column
** of the table currently under construction.
@@ -1219,16 +1237,11 @@ void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
** tokens that point to volatile memory. The 'span' of the expression
** is required by pragma table_info.
*/
Expr x;
sqlite3ExprDelete(db, pCol->pDflt);
memset(&x, 0, sizeof(x));
x.op = TK_SPAN;
x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
(int)(pSpan->zEnd - pSpan->zStart));
x.pLeft = pSpan->pExpr;
x.flags = EP_Skip;
pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
sqlite3DbFree(db, x.u.zToken);
pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE);
sqlite3DbFree(db, pCol->zDflt);
pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
(int)(pSpan->zEnd - pSpan->zStart));
}
}
sqlite3ExprDelete(db, pSpan->pExpr);
@@ -1284,7 +1297,7 @@ void sqlite3AddPrimaryKey(
int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
){
Table *pTab = pParse->pNewTable;
Column *pCol = 0;
char *zType = 0;
int iCol = -1, i;
int nTerm;
if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
@@ -1296,8 +1309,8 @@ void sqlite3AddPrimaryKey(
pTab->tabFlags |= TF_HasPrimaryKey;
if( pList==0 ){
iCol = pTab->nCol - 1;
pCol = &pTab->aCol[iCol];
pCol->colFlags |= COLFLAG_PRIMKEY;
pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
zType = pTab->aCol[iCol].zType;
nTerm = 1;
}else{
nTerm = pList->nExpr;
@@ -1309,8 +1322,8 @@ void sqlite3AddPrimaryKey(
const char *zCName = pCExpr->u.zToken;
for(iCol=0; iCol<pTab->nCol; iCol++){
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
pCol = &pTab->aCol[iCol];
pCol->colFlags |= COLFLAG_PRIMKEY;
pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
zType = pTab->aCol[iCol].zType;
break;
}
}
@@ -1318,8 +1331,7 @@ void sqlite3AddPrimaryKey(
}
}
if( nTerm==1
&& pCol
&& sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
&& zType && sqlite3StrICmp(zType, "INTEGER")==0
&& sortOrder!=SQLITE_SO_DESC
){
pTab->iPKey = iCol;
@@ -1459,11 +1471,13 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
** 1 chance in 2^32. So we're safe enough.
*/
void sqlite3ChangeCookie(Parse *pParse, int iDb){
int r1 = sqlite3GetTempReg(pParse);
sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION,
db->aDb[iDb].pSchema->schema_cookie+1);
sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1);
sqlite3ReleaseTempReg(pParse, r1);
}
/*
@@ -1545,7 +1559,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
n += 35 + 6*p->nCol;
zStmt = sqlite3DbMallocRaw(0, n);
if( zStmt==0 ){
sqlite3OomFault(db);
db->mallocFailed = 1;
return 0;
}
sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
@@ -1598,7 +1612,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
assert( pIdx->isResized==0 );
nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
zExtra = sqlite3DbMallocZero(db, nByte);
if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
if( zExtra==0 ) return SQLITE_NOMEM;
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
pIdx->azColl = (const char**)zExtra;
zExtra += sizeof(char*)*N;
@@ -1944,7 +1958,7 @@ void sqlite3EndTable(
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
sqlite3Select(pParse, pSelect, &dest);
sqlite3VdbeEndCoroutine(v, regYield);
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
sqlite3VdbeJumpHere(v, addrTop - 1);
if( pParse->nErr ) return;
pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
@@ -2028,7 +2042,7 @@ void sqlite3EndTable(
pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
sqlite3OomFault(db);
db->mallocFailed = 1;
return;
}
pParse->pNewTable = 0;
@@ -2132,6 +2146,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
sqlite3_xauth xAuth; /* Saved xAuth pointer */
u8 bEnabledLA; /* Saved db->lookaside.bEnabled state */
assert( pTable );
@@ -2177,56 +2192,45 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** statement that defines the view.
*/
assert( pTable->pSelect );
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
db->lookaside.bDisable++;
bEnabledLA = db->lookaside.bEnabled;
if( pTable->pCheck ){
db->lookaside.bEnabled = 0;
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
&pTable->nCol, &pTable->aCol);
}else{
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
db->lookaside.bEnabled = 0;
#ifndef SQLITE_OMIT_AUTHORIZATION
xAuth = db->xAuth;
db->xAuth = 0;
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
db->xAuth = xAuth;
xAuth = db->xAuth;
db->xAuth = 0;
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
db->xAuth = xAuth;
#else
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
#endif
pParse->nTab = n;
if( pTable->pCheck ){
/* CREATE VIEW name(arglist) AS ...
** The names of the columns in the table are taken from
** arglist which is stored in pTable->pCheck. The pCheck field
** normally holds CHECK constraints on an ordinary table, but for
** a VIEW it holds the list of column names.
*/
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
&pTable->nCol, &pTable->aCol);
if( db->mallocFailed==0
&& pParse->nErr==0
&& pTable->nCol==pSel->pEList->nExpr
){
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
pParse->nTab = n;
if( pSelTab ){
assert( pTable->aCol==0 );
pTable->nCol = pSelTab->nCol;
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab);
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
}else{
pTable->nCol = 0;
nErr++;
}
}else if( pSelTab ){
/* CREATE VIEW name AS... without an argument list. Construct
** the column names from the SELECT statement that defines the view.
*/
assert( pTable->aCol==0 );
pTable->nCol = pSelTab->nCol;
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
}else{
pTable->nCol = 0;
sqlite3SelectDelete(db, pSel);
} else {
nErr++;
}
if( pSelTab ) sqlite3DeleteTable(db, pSelTab);
sqlite3SelectDelete(db, pSel);
db->lookaside.bDisable--;
} else {
nErr++;
}
db->lookaside.bEnabled = bEnabledLA;
pTable->pSchema->schemaFlags |= DB_UnresetViews;
#endif /* SQLITE_OMIT_VIEW */
return nErr;
@@ -2692,7 +2696,7 @@ void sqlite3CreateForeignKey(
pFKey->zTo, (void *)pFKey
);
if( pNextTo==pFKey ){
sqlite3OomFault(db);
db->mallocFailed = 1;
goto fk_end;
}
if( pNextTo ){
@@ -3201,20 +3205,6 @@ Index *sqlite3CreateIndex(
sqlite3DefaultRowEst(pIndex);
if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
/* If this index contains every column of its table, then mark
** it as a covering index */
assert( HasRowid(pTab)
|| pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
pIndex->isCovering = 1;
for(j=0; j<pTab->nCol; j++){
if( j==pTab->iPKey ) continue;
if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
pIndex->isCovering = 0;
break;
}
}
if( pTab==pParse->pNewTable ){
/* This routine has been called to create an automatic index as a
** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
@@ -3252,7 +3242,7 @@ Index *sqlite3CreateIndex(
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
z1 = pIdx->azColl[k];
z2 = pIndex->azColl[k];
if( sqlite3StrICmp(z1, z2) ) break;
if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
}
if( k==pIdx->nKeyCol ){
if( pIdx->onError!=pIndex->onError ){
@@ -3288,7 +3278,7 @@ Index *sqlite3CreateIndex(
pIndex->zName, pIndex);
if( p ){
assert( p==pIndex ); /* Malloc must have failed */
sqlite3OomFault(db);
db->mallocFailed = 1;
goto exit_create_index;
}
db->flags |= SQLITE_InternChanges;
@@ -3717,9 +3707,8 @@ SrcList *sqlite3SrcListAppend(
){
struct SrcList_item *pItem;
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
assert( db!=0 );
if( pList==0 ){
pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) );
pList = sqlite3DbMallocRaw(db, sizeof(SrcList) );
if( pList==0 ) return 0;
pList->nAlloc = 1;
pList->nSrc = 0;
@@ -3903,7 +3892,7 @@ void sqlite3SrcListShiftJoinType(SrcList *p){
}
/*
** Generate VDBE code for a BEGIN statement.
** Begin a transaction
*/
void sqlite3BeginTransaction(Parse *pParse, int type){
sqlite3 *db;
@@ -3913,6 +3902,7 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
assert( pParse!=0 );
db = pParse->db;
assert( db!=0 );
/* if( db->aDb[0].pBt==0 ) return; */
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){
return;
}
@@ -3924,11 +3914,11 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
sqlite3VdbeUsesBtree(v, i);
}
}
sqlite3VdbeAddOp0(v, OP_AutoCommit);
sqlite3VdbeAddOp2(v, OP_AutoCommit, 0, 0);
}
/*
** Generate VDBE code for a COMMIT statement.
** Commit a transaction
*/
void sqlite3CommitTransaction(Parse *pParse){
Vdbe *v;
@@ -3940,12 +3930,12 @@ void sqlite3CommitTransaction(Parse *pParse){
}
v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp1(v, OP_AutoCommit, 1);
sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 0);
}
}
/*
** Generate VDBE code for a ROLLBACK statement.
** Rollback a transaction
*/
void sqlite3RollbackTransaction(Parse *pParse){
Vdbe *v;
@@ -4007,7 +3997,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
db->aDb[1].pBt = pBt;
assert( db->aDb[1].pSchema );
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
sqlite3OomFault(db);
db->mallocFailed = 1;
return 1;
}
}
@@ -4382,9 +4372,10 @@ With *sqlite3WithAdd(
}else{
pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
}
assert( (pNew!=0 && zName!=0) || db->mallocFailed );
assert( zName!=0 || pNew==0 );
assert( db->mallocFailed==0 || pNew==0 );
if( db->mallocFailed ){
if( pNew==0 ){
sqlite3ExprListDelete(db, pArglist);
sqlite3SelectDelete(db, pQuery);
sqlite3DbFree(db, zName);
+33 -41
View File
@@ -177,7 +177,7 @@ static CollSeq *findCollSeqEntry(
*/
assert( pDel==0 || pDel==pColl );
if( pDel!=0 ){
sqlite3OomFault(db);
db->mallocFailed = 1;
sqlite3DbFree(db, pDel);
pColl = 0;
}
@@ -284,12 +284,14 @@ static int matchQuality(
** a pointer to the matching FuncDef if found, or 0 if there is no match.
*/
static FuncDef *functionSearch(
FuncDefHash *pHash, /* Hash table to search */
int h, /* Hash of the name */
const char *zFunc /* Name of function */
const char *zFunc, /* Name of function */
int nFunc /* Number of bytes in zFunc */
){
FuncDef *p;
for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
if( sqlite3StrICmp(p->zName, zFunc)==0 ){
for(p=pHash->a[h]; p; p=p->pHash){
if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
return p;
}
}
@@ -299,26 +301,23 @@ static FuncDef *functionSearch(
/*
** Insert a new FuncDef into a FuncDefHash hash table.
*/
void sqlite3InsertBuiltinFuncs(
FuncDef *aDef, /* List of global functions to be inserted */
int nDef /* Length of the apDef[] list */
void sqlite3FuncDefInsert(
FuncDefHash *pHash, /* The hash table into which to insert */
FuncDef *pDef /* The function definition to insert */
){
int i;
for(i=0; i<nDef; i++){
FuncDef *pOther;
const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName);
int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
pOther = functionSearch(h, zName);
if( pOther ){
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
aDef[i].pNext = pOther->pNext;
pOther->pNext = &aDef[i];
}else{
aDef[i].pNext = 0;
aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h];
sqlite3BuiltinFunctions.a[h] = &aDef[i];
}
FuncDef *pOther;
int nName = sqlite3Strlen30(pDef->zName);
u8 c1 = (u8)pDef->zName[0];
int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
pOther = functionSearch(pHash, h, pDef->zName, nName);
if( pOther ){
assert( pOther!=pDef && pOther->pNext!=pDef );
pDef->pNext = pOther->pNext;
pOther->pNext = pDef;
}else{
pDef->pNext = 0;
pDef->pHash = pHash->a[h];
pHash->a[h] = pDef;
}
}
@@ -345,7 +344,8 @@ void sqlite3InsertBuiltinFuncs(
*/
FuncDef *sqlite3FindFunction(
sqlite3 *db, /* An open database */
const char *zName, /* Name of the function. zero-terminated */
const char *zName, /* Name of the function. Not null-terminated */
int nName, /* Number of characters in the name */
int nArg, /* Number of arguments. -1 means any number */
u8 enc, /* Preferred text encoding */
u8 createFlag /* Create new entry if true and does not otherwise exist */
@@ -354,15 +354,14 @@ FuncDef *sqlite3FindFunction(
FuncDef *pBest = 0; /* Best match found so far */
int bestScore = 0; /* Score of best match */
int h; /* Hash value */
int nName; /* Length of the name */
assert( nArg>=(-2) );
assert( nArg>=(-1) || createFlag==0 );
nName = sqlite3Strlen30(zName);
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
/* First search for a match amongst the application-defined functions.
*/
p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName);
p = functionSearch(&db->aFunc, h, zName, nName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -385,9 +384,9 @@ FuncDef *sqlite3FindFunction(
** So we must not search for built-ins when creating a new function.
*/
if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
bestScore = 0;
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
p = functionSearch(h, zName);
p = functionSearch(pHash, h, zName, nName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -404,19 +403,12 @@ FuncDef *sqlite3FindFunction(
*/
if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
FuncDef *pOther;
pBest->zName = (const char*)&pBest[1];
pBest->zName = (char *)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
memcpy((char*)&pBest[1], zName, nName+1);
pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
if( pOther==pBest ){
sqlite3DbFree(db, pBest);
sqlite3OomFault(db);
return 0;
}else{
pBest->pNext = pOther;
}
memcpy(pBest->zName, zName, nName);
pBest->zName[nName] = 0;
sqlite3FuncDefInsert(&db->aFunc, pBest);
}
if( pBest && (pBest->xSFunc || createFlag) ){
@@ -473,7 +465,7 @@ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
}
if( !p ){
sqlite3OomFault(db);
db->mallocFailed = 1;
}else if ( 0==p->file_format ){
sqlite3HashInit(&p->tblHash);
sqlite3HashInit(&p->idxHash);
+1 -1
View File
@@ -281,7 +281,7 @@ int sqlite3_complete16(const void *zSql){
if( zSql8 ){
rc = sqlite3_complete(zSql8);
}else{
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}
sqlite3ValueFree(pVal);
return rc & 0xff;
+9 -3
View File
@@ -967,7 +967,7 @@ static void strftimeFunc(
sqlite3_result_error_toobig(context);
return;
}else{
z = sqlite3DbMallocRawNN(db, (int)n);
z = sqlite3DbMallocRaw(db, (int)n);
if( z==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -1136,7 +1136,7 @@ static void currentTimeFunc(
** external linkage.
*/
void sqlite3RegisterDateTimeFunctions(void){
static FuncDef aDateTimeFuncs[] = {
static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
DFUNCTION(julianday, -1, 0, 0, juliandayFunc ),
DFUNCTION(date, -1, 0, 0, dateFunc ),
@@ -1152,5 +1152,11 @@ void sqlite3RegisterDateTimeFunctions(void){
STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
};
sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
for(i=0; i<ArraySize(aDateTimeFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
}
+10 -10
View File
@@ -162,7 +162,7 @@ static int statConnect(
rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
if( rc==SQLITE_OK ){
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
if( pTab==0 ) rc = SQLITE_NOMEM;
}
assert( rc==SQLITE_OK || pTab==0 );
@@ -243,7 +243,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
if( pCsr==0 ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}else{
memset(pCsr, 0, sizeof(StatCursor));
pCsr->base.pVtab = pVTab;
@@ -349,7 +349,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
sqlite3BtreeLeave(pBt);
p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
if( p->aCell==0 ) return SQLITE_NOMEM;
memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
for(i=0; i<p->nCell; i++){
@@ -382,7 +382,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
pCell->nOvfl = nOvfl;
pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
if( pCell->aOvfl==0 ) return SQLITE_NOMEM;
pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
for(j=1; j<nOvfl; j++){
int rc;
@@ -461,7 +461,7 @@ statNextRestart:
pCsr->aPage[0].iCell = 0;
pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
pCsr->iPage = 0;
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
if( z==0 ) rc = SQLITE_NOMEM;
}else{
pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt);
@@ -496,7 +496,7 @@ statNextRestart:
}
pCell->iOvfl++;
statSizeAndOffset(pCsr);
return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
return z==0 ? SQLITE_NOMEM : SQLITE_OK;
}
if( p->iRightChildPg ) break;
p->iCell++;
@@ -520,7 +520,7 @@ statNextRestart:
p[1].iCell = 0;
p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
p->iCell++;
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
if( z==0 ) rc = SQLITE_NOMEM;
}
@@ -554,7 +554,7 @@ statNextRestart:
pCsr->nUnused = p->nUnused;
pCsr->nMxPayload = p->nMxPayload;
pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
if( z==0 ) rc = SQLITE_NOMEM;
nPayload = 0;
for(i=0; i<p->nCell; i++){
nPayload += p->aCell[i].nLocal;
@@ -588,7 +588,7 @@ static int statFilter(
if( pCsr->iDb<0 ){
sqlite3_free(pCursor->pVtab->zErrMsg);
pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}
}else{
pCsr->iDb = pTab->iDb;
@@ -604,7 +604,7 @@ static int statFilter(
" FROM \"%w\".%s WHERE rootpage!=0"
" ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster);
if( zSql==0 ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}else{
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
sqlite3_free(zSql);
+1 -1
View File
@@ -439,7 +439,7 @@ void sqlite3DeleteFrom(
** one, so just keep it in its register(s) and fall through to the
** delete code. */
nKey = nPk; /* OP_Found will use an unpacked key */
aToOpen = sqlite3DbMallocRawNN(db, nIdx+2);
aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
if( aToOpen==0 ){
sqlite3WhereEnd(pWInfo);
goto delete_from_cleanup;
+69 -93
View File
@@ -453,7 +453,6 @@ Expr *sqlite3ExprAlloc(
int nExtra = 0;
int iValue = 0;
assert( db!=0 );
if( pToken ){
if( op!=TK_INTEGER || pToken->z==0
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
@@ -461,7 +460,7 @@ Expr *sqlite3ExprAlloc(
assert( iValue>=0 );
}
}
pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra);
pNew = sqlite3DbMallocRaw(db, sizeof(Expr)+nExtra);
if( pNew ){
memset(pNew, 0, sizeof(Expr));
pNew->op = (u8)op;
@@ -700,10 +699,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
if( x>pParse->nzVar ){
char **a;
a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
if( a==0 ){
assert( db->mallocFailed ); /* Error reported through mallocFailed */
return;
}
if( a==0 ) return; /* Error reported through db->mallocFailed */
pParse->azVar = a;
memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
pParse->nzVar = x;
@@ -858,7 +854,6 @@ static int dupedExprSize(Expr *p, int flags){
static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
Expr *pNew = 0; /* Value to return */
assert( flags==0 || flags==EXPRDUP_REDUCE );
assert( db!=0 );
if( p ){
const int isReduced = (flags&EXPRDUP_REDUCE);
u8 *zAlloc;
@@ -871,7 +866,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
zAlloc = *pzBuffer;
staticFlag = EP_Static;
}else{
zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, flags));
zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
}
pNew = (Expr *)zAlloc;
@@ -994,13 +989,12 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
assert( db!=0 );
if( p==0 ) return 0;
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nExpr = i = p->nExpr;
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
pNew->a = pItem = sqlite3DbMallocRawNN(db, i*sizeof(p->a[0]) );
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
if( pItem==0 ){
sqlite3DbFree(db, pNew);
return 0;
@@ -1031,10 +1025,9 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
SrcList *pNew;
int i;
int nByte;
assert( db!=0 );
if( p==0 ) return 0;
nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
pNew = sqlite3DbMallocRawNN(db, nByte );
pNew = sqlite3DbMallocRaw(db, nByte );
if( pNew==0 ) return 0;
pNew->nSrc = pNew->nAlloc = p->nSrc;
for(i=0; i<p->nSrc; i++){
@@ -1071,12 +1064,11 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
IdList *pNew;
int i;
assert( db!=0 );
if( p==0 ) return 0;
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nId = p->nId;
pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
sqlite3DbFree(db, pNew);
return 0;
@@ -1094,9 +1086,8 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
}
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
Select *pNew, *pPrior;
assert( db!=0 );
if( p==0 ) return 0;
pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
@@ -1142,14 +1133,13 @@ ExprList *sqlite3ExprListAppend(
Expr *pExpr /* Expression to be appended. Might be NULL */
){
sqlite3 *db = pParse->db;
assert( db!=0 );
if( pList==0 ){
pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) );
pList = sqlite3DbMallocRaw(db, sizeof(ExprList) );
if( pList==0 ){
goto no_mem;
}
pList->nExpr = 0;
pList->a = sqlite3DbMallocRawNN(db, sizeof(pList->a[0]));
pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0]));
if( pList->a==0 ) goto no_mem;
}else if( (pList->nExpr & (pList->nExpr-1))==0 ){
struct ExprList_item *a;
@@ -1283,8 +1273,7 @@ u32 sqlite3ExprListFlags(const ExprList *pList){
if( pList ){
for(i=0; i<pList->nExpr; i++){
Expr *pExpr = pList->a[i].pExpr;
assert( pExpr!=0 );
m |= pExpr->flags;
if( ALWAYS(pExpr) ) m |= pExpr->flags;
}
}
return m;
@@ -1569,22 +1558,23 @@ int sqlite3IsRowid(const char *z){
}
/*
** pX is the RHS of an IN operator. If pX is a SELECT statement
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement. If pX is not a SELECT statement,
** or if the SELECT statement needs to be manifested into a transient
** table, then return NULL.
** Return true if we are able to the IN operator optimization on a
** query of the form
**
** x IN (SELECT ...)
**
** Where the SELECT... clause is as specified by the parameter to this
** routine.
**
** The Select object passed in has already been preprocessed and no
** errors have been found.
*/
#ifndef SQLITE_OMIT_SUBQUERY
static Select *isCandidateForInOpt(Expr *pX){
Select *p;
static int isCandidateForInOpt(Select *p){
SrcList *pSrc;
ExprList *pEList;
Expr *pRes;
Table *pTab;
if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
p = pX->x.pSelect;
if( p==0 ) return 0; /* right-hand side of IN is SELECT */
if( p->pPrior ) return 0; /* Not a compound SELECT */
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
@@ -1600,15 +1590,13 @@ static Select *isCandidateForInOpt(Expr *pX){
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
pTab = pSrc->a[0].pTab;
assert( pTab!=0 );
if( NEVER(pTab==0) ) return 0;
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
pEList = p->pEList;
if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
pRes = pEList->a[0].pExpr;
if( pRes->op!=TK_COLUMN ) return 0; /* Result is a column */
assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
return p;
if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */
return 1;
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -1740,13 +1728,15 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
** satisfy the query. This is preferable to generating a new
** ephemeral table.
*/
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
if( pParse->nErr==0 && isCandidateForInOpt(p) ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table <table>. */
Expr *pExpr; /* Expression <column> */
i16 iCol; /* Index of column <column> */
i16 iDb; /* Database idx for pTab */
assert( p ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
@@ -2888,6 +2878,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
ExprList *pFarg; /* List of function arguments */
int nFarg; /* Number of function arguments */
FuncDef *pDef; /* The function definition object */
int nId; /* Length of the function name in bytes */
const char *zId; /* The function name */
u32 constMask = 0; /* Mask of function arguments that are constant */
int i; /* Loop counter */
@@ -2903,9 +2894,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
nFarg = pFarg ? pFarg->nExpr : 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
if( pDef==0 || pDef->xFinalize!=0 ){
sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
break;
}
@@ -3070,7 +3062,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3ReleaseTempReg(pParse, r4);
break;
}
case TK_SPAN:
case TK_COLLATE:
case TK_UPLUS: {
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
@@ -3549,13 +3540,6 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
case TK_IS:
case TK_ISNOT:
testcase( op==TK_IS );
testcase( op==TK_ISNOT );
op = (op==TK_IS) ? TK_EQ : TK_NE;
jumpIfNull = SQLITE_NULLEQ;
/* Fall thru */
case TK_LT:
case TK_LE:
case TK_GT:
@@ -3571,12 +3555,23 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
}
case TK_IS:
case TK_ISNOT: {
testcase( op==TK_IS );
testcase( op==TK_ISNOT );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
op = (op==TK_IS) ? TK_EQ : TK_NE;
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, SQLITE_NULLEQ);
VdbeCoverageIf(v, op==TK_EQ);
VdbeCoverageIf(v, op==TK_NE);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -3701,13 +3696,6 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
case TK_IS:
case TK_ISNOT:
testcase( pExpr->op==TK_IS );
testcase( pExpr->op==TK_ISNOT );
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
jumpIfNull = SQLITE_NULLEQ;
/* Fall thru */
case TK_LT:
case TK_LE:
case TK_GT:
@@ -3723,12 +3711,23 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
}
case TK_IS:
case TK_ISNOT: {
testcase( pExpr->op==TK_IS );
testcase( pExpr->op==TK_ISNOT );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, SQLITE_NULLEQ);
VdbeCoverageIf(v, op==TK_EQ);
VdbeCoverageIf(v, op==TK_NE);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -4123,7 +4122,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
pItem->iMem = ++pParse->nMem;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
pExpr->u.zToken,
pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken),
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
@@ -4251,26 +4250,3 @@ void sqlite3ClearTempRegCache(Parse *pParse){
pParse->nTempReg = 0;
pParse->nRangeReg = 0;
}
/*
** Validate that no temporary register falls within the range of
** iFirst..iLast, inclusive. This routine is only call from within assert()
** statements.
*/
#ifdef SQLITE_DEBUG
int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
int i;
if( pParse->nRangeReg>0
&& pParse->iRangeReg+pParse->nRangeReg<iLast
&& pParse->iRangeReg>=iFirst
){
return 0;
}
for(i=0; i<pParse->nTempReg; i++){
if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){
return 0;
}
}
return 1;
}
#endif /* SQLITE_DEBUG */
+5 -7
View File
@@ -219,7 +219,7 @@ int sqlite3FkLocateIndex(
}
}else if( paiCol ){
assert( nCol>1 );
aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int));
aiCol = (int *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int));
if( !aiCol ) return 1;
*paiCol = aiCol;
}
@@ -1162,13 +1162,10 @@ static Trigger *fkActionTrigger(
int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
action = pFKey->aAction[iAction];
if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
return 0;
}
pTrigger = pFKey->apTrigger[iAction];
if( action!=OE_None && !pTrigger ){
u8 enableLookaside; /* Copy of db->lookaside.bEnabled */
char const *zFrom; /* Name of child table */
int nFrom; /* Length in bytes of zFrom */
Index *pIdx = 0; /* Parent key index for this FK */
@@ -1277,7 +1274,8 @@ static Trigger *fkActionTrigger(
}
/* Disable lookaside memory allocation */
db->lookaside.bDisable++;
enableLookaside = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
pTrigger = (Trigger *)sqlite3DbMallocZero(db,
sizeof(Trigger) + /* struct Trigger */
@@ -1299,7 +1297,7 @@ static Trigger *fkActionTrigger(
}
/* Re-enable the lookaside buffer, if it was disabled earlier. */
db->lookaside.bDisable--;
db->lookaside.bEnabled = enableLookaside;
sqlite3ExprDelete(db, pWhere);
sqlite3ExprDelete(db, pWhen);
+40 -48
View File
@@ -1611,11 +1611,11 @@ static void groupConcatFinalize(sqlite3_context *context){
** of the built-in functions above are part of the global function set.
** This routine only deals with those that are not global.
*/
void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
int rc = sqlite3_overload_function(db, "MATCH", 2);
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){
sqlite3OomFault(db);
db->mallocFailed = 1;
}
}
@@ -1624,7 +1624,8 @@ void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
*/
static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
FuncDef *pDef;
pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0);
pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
2, SQLITE_UTF8, 0);
if( ALWAYS(pDef) ){
pDef->funcFlags |= flagVal;
}
@@ -1672,7 +1673,9 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
pDef = sqlite3FindFunction(db, pExpr->u.zToken,
sqlite3Strlen30(pExpr->u.zToken),
2, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
@@ -1696,7 +1699,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
**
** After this routine runs
*/
void sqlite3RegisterBuiltinFunctions(void){
void sqlite3RegisterGlobalFunctions(void){
/*
** The following array holds FuncDef structures for all of the functions
** defined in this file.
@@ -1704,27 +1707,8 @@ void sqlite3RegisterBuiltinFunctions(void){
** The array cannot be constant since changes are made to the
** FuncDef.pHash elements at start-time. The elements of this array
** are read-only after initialization is complete.
**
** For peak efficiency, put the most frequently used function last.
*/
static FuncDef aBuiltinFunc[] = {
#ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
VFUNCTION(load_extension, 1, 0, 0, loadExt ),
VFUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif
#if SQLITE_USER_AUTHENTICATION
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
static SQLITE_WSD FuncDef aBuiltinFunc[] = {
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
@@ -1742,6 +1726,8 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
@@ -1752,22 +1738,40 @@ void sqlite3RegisterBuiltinFunctions(void){
#endif
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
#if SQLITE_USER_AUTHENTICATION
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION(quote, 1, 0, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
VFUNCTION(changes, 0, 0, 0, changes ),
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
FUNCTION(replace, 3, 0, 0, replaceFunc ),
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
#ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
VFUNCTION(load_extension, 1, 0, 0, loadExt ),
VFUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
@@ -1785,32 +1789,20 @@ void sqlite3RegisterBuiltinFunctions(void){
LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
#endif
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc);
for(i=0; i<ArraySize(aBuiltinFunc); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3RegisterDateTimeFunctions();
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
#endif
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
sqlite3AnalyzeFunctions();
#endif
sqlite3RegisterDateTimeFunctions();
sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
#if 0 /* Enable to print out how the built-in functions are hashed */
{
int i;
FuncDef *p;
for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
printf("FUNC-HASH %02d:", i);
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){
int n = sqlite3Strlen30(p->zName);
int h = p->zName[0] + n;
printf(" %s(%d)", p->zName, h);
}
printf("\n");
}
}
#endif
}
+1 -14
View File
@@ -159,18 +159,6 @@ const unsigned char sqlite3CtypeMap[256] = {
# define SQLITE_SORTER_PMASZ 250
#endif
/* Statement journals spill to disk when their size exceeds the following
** threashold (in bytes). 0 means that statement journals are created and
** written to disk immediately (the default behavior for SQLite versions
** before 3.12.0). -1 means always keep the entire statement journal in
** memory. (The statement journal is also always held entirely in memory
** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this
** setting.)
*/
#ifndef SQLITE_STMTJRNL_SPILL
# define SQLITE_STMTJRNL_SPILL (64*1024)
#endif
/*
** The following singleton contains the global configuration for
** the SQLite library.
@@ -185,7 +173,6 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* neverCorrupt */
128, /* szLookaside */
500, /* nLookaside */
SQLITE_STMTJRNL_SPILL, /* nStmtSpill */
{0,0,0,0,0,0,0,0}, /* m */
{0,0,0,0,0,0,0,0,0}, /* mutex */
{0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
@@ -232,7 +219,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
** database connections. After initialization, this table is
** read-only.
*/
FuncDefHash sqlite3BuiltinFunctions;
SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
/*
** Constant tokens for values 0 and 1.
+39 -129
View File
@@ -83,7 +83,7 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
Table *pTab = pIdx->pTable;
pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
if( !pIdx->zColAff ){
sqlite3OomFault(db);
db->mallocFailed = 1;
return 0;
}
for(n=0; n<pIdx->nColumn; n++){
@@ -134,7 +134,7 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
sqlite3 *db = sqlite3VdbeDb(v);
zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
if( !zColAff ){
sqlite3OomFault(db);
db->mallocFailed = 1;
return;
}
@@ -230,7 +230,7 @@ static int autoIncBegin(
pInfo = pToplevel->pAinc;
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
if( pInfo==0 ){
pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
if( pInfo==0 ) return 0;
pInfo->pNext = pToplevel->pAinc;
pToplevel->pAinc = pInfo;
@@ -254,6 +254,7 @@ void sqlite3AutoincrementBegin(Parse *pParse){
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* Database only autoinc table */
int memId; /* Register holding max rowid */
int addr; /* A VDBE address */
Vdbe *v = pParse->pVdbe; /* VDBE under construction */
/* This routine is never called during trigger-generation. It is
@@ -263,46 +264,33 @@ void sqlite3AutoincrementBegin(Parse *pParse){
assert( v ); /* We failed long ago if this is not so */
for(p = pParse->pAinc; p; p = p->pNext){
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList autoInc[] = {
/* 0 */ {OP_Null, 0, 0, 0},
/* 1 */ {OP_Rewind, 0, 9, 0},
/* 2 */ {OP_Column, 0, 0, 0},
/* 3 */ {OP_Ne, 0, 7, 0},
/* 4 */ {OP_Rowid, 0, 0, 0},
/* 5 */ {OP_Column, 0, 1, 0},
/* 6 */ {OP_Goto, 0, 9, 0},
/* 7 */ {OP_Next, 0, 2, 0},
/* 8 */ {OP_Integer, 0, 0, 0},
/* 9 */ {OP_Close, 0, 0, 0}
};
VdbeOp *aOp;
pDb = &db->aDb[p->iDb];
memId = p->regCtr;
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
addr = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
if( aOp==0 ) break;
aOp[0].p2 = memId;
aOp[0].p3 = memId+1;
aOp[2].p3 = memId;
aOp[3].p1 = memId-1;
aOp[3].p3 = memId;
aOp[3].p5 = SQLITE_JUMPIFNULL;
aOp[4].p2 = memId+1;
aOp[5].p3 = memId;
aOp[8].p2 = memId;
sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
sqlite3VdbeGoto(v, addr+9);
sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
sqlite3VdbeAddOp0(v, OP_Close);
}
}
/*
** Update the maximum rowid for an autoincrement calculation.
**
** This routine should be called when the regRowid register holds a
** This routine should be called when the top of the stack holds a
** new rowid that is about to be inserted. If that new rowid is
** larger than the maximum rowid in the memId memory cell, then the
** memory cell is updated.
** memory cell is updated. The stack is unchanged.
*/
static void autoIncStep(Parse *pParse, int memId, int regRowid){
if( memId>0 ){
@@ -317,44 +305,31 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
** table (either directly or through triggers) needs to call this
** routine just before the "exit" code.
*/
static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){
void sqlite3AutoincrementEnd(Parse *pParse){
AutoincInfo *p;
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
assert( v );
for(p = pParse->pAinc; p; p = p->pNext){
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList autoIncEnd[] = {
/* 0 */ {OP_NotNull, 0, 2, 0},
/* 1 */ {OP_NewRowid, 0, 0, 0},
/* 2 */ {OP_MakeRecord, 0, 2, 0},
/* 3 */ {OP_Insert, 0, 0, 0},
/* 4 */ {OP_Close, 0, 0, 0}
};
VdbeOp *aOp;
Db *pDb = &db->aDb[p->iDb];
int addr1;
int iRec;
int memId = p->regCtr;
iRec = sqlite3GetTempReg(pParse);
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn);
if( aOp==0 ) break;
aOp[0].p1 = memId+1;
aOp[1].p2 = memId+1;
aOp[2].p1 = memId-1;
aOp[2].p3 = iRec;
aOp[3].p2 = iRec;
aOp[3].p3 = memId+1;
aOp[3].p5 = OPFLAG_APPEND;
addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3VdbeAddOp0(v, OP_Close);
sqlite3ReleaseTempReg(pParse, iRec);
}
}
void sqlite3AutoincrementEnd(Parse *pParse){
if( pParse->pAinc ) autoIncrementEnd(pParse);
}
#else
/*
** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
@@ -685,7 +660,7 @@ void sqlite3Insert(
rc = sqlite3Select(pParse, pSelect, &dest);
regFromSelect = dest.iSdst;
if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
sqlite3VdbeEndCoroutine(v, regYield);
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr;
@@ -787,7 +762,7 @@ void sqlite3Insert(
int nIdx;
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
&iDataCur, &iIdxCur);
aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1));
aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
if( aRegIdx==0 ){
goto insert_cleanup;
}
@@ -995,7 +970,7 @@ void sqlite3Insert(
{
int isReplace; /* Set to true if constraints may cause a replace */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace
);
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
@@ -1077,59 +1052,6 @@ insert_cleanup:
#undef tmask
#endif
/*
** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged()
*/
#define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */
#define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */
/* This is the Walker callback from checkConstraintUnchanged(). Set
** bit 0x01 of pWalker->eCode if
** pWalker->eCode to 0 if this expression node references any of the
** columns that are being modifed by an UPDATE statement.
*/
static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN ){
assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 );
if( pExpr->iColumn>=0 ){
if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){
pWalker->eCode |= CKCNSTRNT_COLUMN;
}
}else{
pWalker->eCode |= CKCNSTRNT_ROWID;
}
}
return WRC_Continue;
}
/*
** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The
** only columns that are modified by the UPDATE are those for which
** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true.
**
** Return true if CHECK constraint pExpr does not use any of the
** changing columns (or the rowid if it is changing). In other words,
** return true if this CHECK constraint can be skipped when validating
** the new row in the UPDATE statement.
*/
static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
Walker w;
memset(&w, 0, sizeof(w));
w.eCode = 0;
w.xExprCallback = checkConstraintExprNode;
w.u.aiCol = aiChng;
sqlite3WalkExpr(&w, pExpr);
if( !chngRowid ){
testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 );
w.eCode &= ~CKCNSTRNT_ROWID;
}
testcase( w.eCode==0 );
testcase( w.eCode==CKCNSTRNT_COLUMN );
testcase( w.eCode==CKCNSTRNT_ROWID );
testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) );
return !w.eCode;
}
/*
** Generate code to do constraint checks prior to an INSERT or an UPDATE
** on table pTab.
@@ -1224,8 +1146,7 @@ void sqlite3GenerateConstraintChecks(
u8 pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
u8 overrideError, /* Override onError to this if not OE_Default */
int ignoreDest, /* Jump to this label on an OE_Ignore resolution */
int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */
int *aiChng /* column i is unchanged if aiChng[i]<0 */
int *pbMayReplace /* OUT: Set to true if constraint may cause a replace */
){
Vdbe *v; /* VDBE under constrution */
Index *pIdx; /* Pointer to one of the indices */
@@ -1271,14 +1192,10 @@ void sqlite3GenerateConstraintChecks(
*/
for(i=0; i<nCol; i++){
if( i==pTab->iPKey ){
continue; /* ROWID is never NULL */
}
if( aiChng && aiChng[i]<0 ){
/* Don't bother checking for NOT NULL on columns that do not change */
continue;
}
onError = pTab->aCol[i].notNull;
if( onError==OE_None ) continue; /* This column is allowed to be NULL */
if( onError==OE_None ) continue;
if( overrideError!=OE_Default ){
onError = overrideError;
}else if( onError==OE_Default ){
@@ -1327,11 +1244,8 @@ void sqlite3GenerateConstraintChecks(
pParse->ckBase = regNewData+1;
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
for(i=0; i<pCheck->nExpr; i++){
int allOk;
Expr *pExpr = pCheck->a[i].pExpr;
if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
allOk = sqlite3VdbeMakeLabel(v);
sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
int allOk = sqlite3VdbeMakeLabel(v);
sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
if( onError==OE_Ignore ){
sqlite3VdbeGoto(v, ignoreDest);
}else{
@@ -1999,15 +1913,11 @@ static int xferOptimization(
return 0; /* tab2 must be NOT NULL if tab1 is */
}
/* Default values for second and subsequent columns need to match. */
if( i>0 ){
assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
|| (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
pSrcCol->pDflt->u.zToken)!=0)
){
return 0; /* Default values must be the same for all columns */
}
if( i>0
&& ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|| (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
){
return 0; /* Default values must be the same for all columns */
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
+256
View File
@@ -0,0 +1,256 @@
/*
** 2007 August 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file implements a special kind of sqlite3_file object used
** by SQLite to create journal files if the atomic-write optimization
** is enabled.
**
** The distinctive characteristic of this sqlite3_file is that the
** actual on disk file is created lazily. When the file is created,
** the caller specifies a buffer size for an in-memory buffer to
** be used to service read() and write() requests. The actual file
** on disk is not created or populated until either:
**
** 1) The in-memory representation grows too large for the allocated
** buffer, or
** 2) The sqlite3JournalCreate() function is called.
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#include "sqliteInt.h"
/*
** A JournalFile object is a subclass of sqlite3_file used by
** as an open file handle for journal files.
*/
struct JournalFile {
sqlite3_io_methods *pMethod; /* I/O methods on journal files */
int nBuf; /* Size of zBuf[] in bytes */
char *zBuf; /* Space to buffer journal writes */
int iSize; /* Amount of zBuf[] currently used */
int flags; /* xOpen flags */
sqlite3_vfs *pVfs; /* The "real" underlying VFS */
sqlite3_file *pReal; /* The "real" underlying file descriptor */
const char *zJournal; /* Name of the journal file */
};
typedef struct JournalFile JournalFile;
/*
** If it does not already exists, create and populate the on-disk file
** for JournalFile p.
*/
static int createFile(JournalFile *p){
int rc = SQLITE_OK;
if( !p->pReal ){
sqlite3_file *pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
if( rc==SQLITE_OK ){
p->pReal = pReal;
if( p->iSize>0 ){
assert(p->iSize<=p->nBuf);
rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
}
if( rc!=SQLITE_OK ){
/* If an error occurred while writing to the file, close it before
** returning. This way, SQLite uses the in-memory journal data to
** roll back changes made to the internal page-cache before this
** function was called. */
sqlite3OsClose(pReal);
p->pReal = 0;
}
}
}
return rc;
}
/*
** Close the file.
*/
static int jrnlClose(sqlite3_file *pJfd){
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
sqlite3OsClose(p->pReal);
}
sqlite3_free(p->zBuf);
return SQLITE_OK;
}
/*
** Read data from the file.
*/
static int jrnlRead(
sqlite3_file *pJfd, /* The journal file from which to read */
void *zBuf, /* Put the results here */
int iAmt, /* Number of bytes to read */
sqlite_int64 iOfst /* Begin reading at this offset */
){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
}else if( (iAmt+iOfst)>p->iSize ){
rc = SQLITE_IOERR_SHORT_READ;
}else{
memcpy(zBuf, &p->zBuf[iOfst], iAmt);
}
return rc;
}
/*
** Write data to the file.
*/
static int jrnlWrite(
sqlite3_file *pJfd, /* The journal file into which to write */
const void *zBuf, /* Take data to be written from here */
int iAmt, /* Number of bytes to write */
sqlite_int64 iOfst /* Begin writing at this offset into the file */
){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
rc = createFile(p);
}
if( rc==SQLITE_OK ){
if( p->pReal ){
rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}else{
memcpy(&p->zBuf[iOfst], zBuf, iAmt);
if( p->iSize<(iOfst+iAmt) ){
p->iSize = (iOfst+iAmt);
}
}
}
return rc;
}
/*
** Truncate the file.
*/
static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsTruncate(p->pReal, size);
}else if( size<p->iSize ){
p->iSize = size;
}
return rc;
}
/*
** Sync the file.
*/
static int jrnlSync(sqlite3_file *pJfd, int flags){
int rc;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsSync(p->pReal, flags);
}else{
rc = SQLITE_OK;
}
return rc;
}
/*
** Query the size of the file in bytes.
*/
static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsFileSize(p->pReal, pSize);
}else{
*pSize = (sqlite_int64) p->iSize;
}
return rc;
}
/*
** Table of methods for JournalFile sqlite3_file object.
*/
static struct sqlite3_io_methods JournalFileMethods = {
1, /* iVersion */
jrnlClose, /* xClose */
jrnlRead, /* xRead */
jrnlWrite, /* xWrite */
jrnlTruncate, /* xTruncate */
jrnlSync, /* xSync */
jrnlFileSize, /* xFileSize */
0, /* xLock */
0, /* xUnlock */
0, /* xCheckReservedLock */
0, /* xFileControl */
0, /* xSectorSize */
0, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0 /* xShmUnmap */
};
/*
** Open a journal file.
*/
int sqlite3JournalOpen(
sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
const char *zName, /* Name of the journal file */
sqlite3_file *pJfd, /* Preallocated, blank file handle */
int flags, /* Opening flags */
int nBuf /* Bytes buffered before opening the file */
){
JournalFile *p = (JournalFile *)pJfd;
memset(p, 0, sqlite3JournalSize(pVfs));
if( nBuf>0 ){
p->zBuf = sqlite3MallocZero(nBuf);
if( !p->zBuf ){
return SQLITE_NOMEM;
}
}else{
return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
}
p->pMethod = &JournalFileMethods;
p->nBuf = nBuf;
p->flags = flags;
p->zJournal = zName;
p->pVfs = pVfs;
return SQLITE_OK;
}
/*
** If the argument p points to a JournalFile structure, and the underlying
** file has not yet been created, create it now.
*/
int sqlite3JournalCreate(sqlite3_file *p){
if( p->pMethods!=&JournalFileMethods ){
return SQLITE_OK;
}
return createFile((JournalFile *)p);
}
/*
** The file-handle passed as the only argument is guaranteed to be an open
** file. It may or may not be of class JournalFile. If the file is a
** JournalFile, and the underlying file on disk has not yet been opened,
** return 0. Otherwise, return 1.
*/
int sqlite3JournalExists(sqlite3_file *p){
return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
}
/*
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
*/
int sqlite3JournalSize(sqlite3_vfs *pVfs){
return (pVfs->szOsFile+sizeof(JournalFile));
}
#endif
+2 -2
View File
@@ -90,7 +90,7 @@ int sqlite3_exec(
for(i=0; i<nCol; i++){
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
sqlite3OomFault(db);
db->mallocFailed = 1;
goto exec_out;
}
}
@@ -131,7 +131,7 @@ exec_out:
if( *pzErrMsg ){
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}else{
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
sqlite3Error(db, SQLITE_NOMEM);
}
}else if( pzErrMsg ){
+5 -7
View File
@@ -414,9 +414,7 @@ static const sqlite3_api_routines sqlite3Apis = {
/* Version 3.10.0 and later */
sqlite3_status64,
sqlite3_strlike,
sqlite3_db_cacheflush,
/* Version 3.12.0 and later */
sqlite3_system_errno
sqlite3_db_cacheflush
};
/*
@@ -480,7 +478,7 @@ static int sqlite3LoadExtension(
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
if( zAltFile==0 ) return SQLITE_NOMEM;
handle = sqlite3OsDlOpen(pVfs, zAltFile);
sqlite3_free(zAltFile);
}
@@ -516,7 +514,7 @@ static int sqlite3LoadExtension(
zAltEntry = sqlite3_malloc64(ncFile+30);
if( zAltEntry==0 ){
sqlite3OsDlClose(pVfs, handle);
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
memcpy(zAltEntry, "sqlite3_", 8);
for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
@@ -559,7 +557,7 @@ static int sqlite3LoadExtension(
/* Append the new shared library handle to the db->aExtension array. */
aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
if( aHandle==0 ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
if( db->nExtension>0 ){
memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
@@ -681,7 +679,7 @@ int sqlite3_auto_extension(void (*xInit)(void)){
void (**aNew)(void);
aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
if( aNew==0 ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}else{
wsdAutoext.aExt = aNew;
wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
+60 -74
View File
@@ -187,7 +187,7 @@ int sqlite3_initialize(void){
sqlite3GlobalConfig.pInitMutex =
sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}
}
}
@@ -218,6 +218,7 @@ int sqlite3_initialize(void){
*/
sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
sqlite3GlobalConfig.inProgress = 1;
#ifdef SQLITE_ENABLE_SQLLOG
{
@@ -225,8 +226,8 @@ int sqlite3_initialize(void){
sqlite3_init_sqllog();
}
#endif
memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions));
sqlite3RegisterBuiltinFunctions();
memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
sqlite3RegisterGlobalFunctions();
if( sqlite3GlobalConfig.isPCacheInit==0 ){
rc = sqlite3PcacheInitialize();
}
@@ -633,11 +634,6 @@ int sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_STMTJRNL_SPILL: {
sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int);
break;
}
default: {
rc = SQLITE_ERROR;
break;
@@ -702,12 +698,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
p = (LookasideSlot*)&((u8*)p)[sz];
}
db->lookaside.pEnd = p;
db->lookaside.bDisable = 0;
db->lookaside.bEnabled = 1;
db->lookaside.bMalloced = pBuf==0 ?1:0;
}else{
db->lookaside.pStart = db;
db->lookaside.pEnd = db;
db->lookaside.bDisable = 1;
db->lookaside.bEnabled = 0;
db->lookaside.bMalloced = 0;
}
#endif /* SQLITE_OMIT_LOOKASIDE */
@@ -801,9 +797,8 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
int op; /* The opcode */
u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */
} aFlagOp[] = {
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -963,7 +958,7 @@ void sqlite3CloseSavepoints(sqlite3 *db){
** with SQLITE_ANY as the encoding.
*/
static void functionDestroy(sqlite3 *db, FuncDef *p){
FuncDestructor *pDestructor = p->u.pDestructor;
FuncDestructor *pDestructor = p->pDestructor;
if( pDestructor ){
pDestructor->nRef--;
if( pDestructor->nRef==0 ){
@@ -1145,17 +1140,18 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
*/
sqlite3ConnectionClosed(db);
for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
FuncDef *pNext, *p;
p = sqliteHashData(i);
do{
functionDestroy(db, p);
pNext = p->pNext;
sqlite3DbFree(db, p);
p = pNext;
}while( p );
for(j=0; j<ArraySize(db->aFunc.a); j++){
FuncDef *pNext, *pHash, *p;
for(p=db->aFunc.a[j]; p; p=pHash){
pHash = p->pHash;
while( p ){
functionDestroy(db, p);
pNext = p->pNext;
sqlite3DbFree(db, p);
p = pNext;
}
}
}
sqlite3HashClear(&db->aFunc);
for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i);
/* Invoke any destructors registered for collation sequence user data. */
@@ -1634,7 +1630,7 @@ int sqlite3CreateFunc(
** is being overridden/deleted but there are no active VMs, allow the
** operation to continue but invalidate all precompiled statements.
*/
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
@@ -1646,10 +1642,10 @@ int sqlite3CreateFunc(
}
}
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 1);
assert(p || db->mallocFailed);
if( !p ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
/* If an older version of the function with a configured destructor is
@@ -1659,7 +1655,7 @@ int sqlite3CreateFunc(
if( pDestructor ){
pDestructor->nRef++;
}
p->u.pDestructor = pDestructor;
p->pDestructor = pDestructor;
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
p->xSFunc = xSFunc ? xSFunc : xStep;
@@ -1774,6 +1770,7 @@ int sqlite3_overload_function(
const char *zName,
int nArg
){
int nName = sqlite3Strlen30(zName);
int rc = SQLITE_OK;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -1782,7 +1779,7 @@ int sqlite3_overload_function(
}
#endif
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
0, sqlite3InvalidFunction, 0, 0, 0);
}
@@ -2152,14 +2149,14 @@ int sqlite3TempInMemory(const sqlite3 *db){
const char *sqlite3_errmsg(sqlite3 *db){
const char *z;
if( !db ){
return sqlite3ErrStr(SQLITE_NOMEM_BKPT);
return sqlite3ErrStr(SQLITE_NOMEM);
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return sqlite3ErrStr(SQLITE_MISUSE_BKPT);
}
sqlite3_mutex_enter(db->mutex);
if( db->mallocFailed ){
z = sqlite3ErrStr(SQLITE_NOMEM_BKPT);
z = sqlite3ErrStr(SQLITE_NOMEM);
}else{
testcase( db->pErr==0 );
z = (char*)sqlite3_value_text(db->pErr);
@@ -2211,7 +2208,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
** be cleared before returning. Do this directly, instead of via
** sqlite3ApiExit(), to avoid setting the database handle error message.
*/
sqlite3OomClear(db);
db->mallocFailed = 0;
}
sqlite3_mutex_leave(db->mutex);
return z;
@@ -2227,7 +2224,7 @@ int sqlite3_errcode(sqlite3 *db){
return SQLITE_MISUSE_BKPT;
}
if( !db || db->mallocFailed ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
return db->errCode & db->errMask;
}
@@ -2236,13 +2233,10 @@ int sqlite3_extended_errcode(sqlite3 *db){
return SQLITE_MISUSE_BKPT;
}
if( !db || db->mallocFailed ){
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
return db->errCode;
}
int sqlite3_system_errno(sqlite3 *db){
return db ? db->iSysErrno : 0;
}
/*
** Return a string that describes the kind of error specified in the
@@ -2319,7 +2313,7 @@ static int createCollation(
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
if( pColl==0 ) return SQLITE_NOMEM_BKPT;
if( pColl==0 ) return SQLITE_NOMEM;
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
pColl->xDel = xDel;
@@ -2367,8 +2361,8 @@ static const int aHardLimit[] = {
#if SQLITE_MAX_VDBE_OP<40
# error SQLITE_MAX_VDBE_OP must be at least 40
#endif
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
#endif
#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
# error SQLITE_MAX_ATTACHED must be between 0 and 125
@@ -2498,7 +2492,7 @@ int sqlite3ParseUri(
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
zFile = sqlite3_malloc64(nByte);
if( !zFile ) return SQLITE_NOMEM_BKPT;
if( !zFile ) return SQLITE_NOMEM;
iIn = 5;
#ifdef SQLITE_ALLOW_URI_AUTHORITY
@@ -2664,7 +2658,7 @@ int sqlite3ParseUri(
}else{
zFile = sqlite3_malloc64(nUri+2);
if( !zFile ) return SQLITE_NOMEM_BKPT;
if( !zFile ) return SQLITE_NOMEM;
memcpy(zFile, zUri, nUri);
zFile[nUri] = '\0';
zFile[nUri+1] = '\0';
@@ -2820,9 +2814,6 @@ static int openDatabase(
#endif
#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
| SQLITE_CellSizeCk
#endif
#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
| SQLITE_Fts3Tokenizer
#endif
;
sqlite3HashInit(&db->aCollSeq);
@@ -2855,7 +2846,7 @@ static int openDatabase(
db->openFlags = flags;
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
sqlite3_free(zErrMsg);
goto opendb_out;
@@ -2866,7 +2857,7 @@ static int openDatabase(
flags | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}
sqlite3Error(db, rc);
goto opendb_out;
@@ -2877,13 +2868,13 @@ static int openDatabase(
sqlite3BtreeLeave(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
/* The default safety_level for the main database is FULL; for the temp
** database it is OFF. This matches the pager layer defaults.
/* The default safety_level for the main database is 'full'; for the temp
** database it is 'NONE'. This matches the pager layer defaults.
*/
db->aDb[0].zName = "main";
db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
db->aDb[0].safety_level = 3;
db->aDb[1].zName = "temp";
db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
db->aDb[1].safety_level = 1;
db->magic = SQLITE_MAGIC_OPEN;
if( db->mallocFailed ){
@@ -2895,7 +2886,7 @@ static int openDatabase(
** is accessed.
*/
sqlite3Error(db, SQLITE_OK);
sqlite3RegisterPerConnectionBuiltinFunctions(db);
sqlite3RegisterBuiltinFunctions(db);
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
@@ -3069,7 +3060,7 @@ int sqlite3_open16(
SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
}
}else{
rc = SQLITE_NOMEM_BKPT;
rc = SQLITE_NOMEM;
}
sqlite3ValueFree(pVal);
@@ -3214,7 +3205,7 @@ int sqlite3_get_autocommit(sqlite3 *db){
/*
** The following routines are substitutes for constants SQLITE_CORRUPT,
** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error
** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
** constants. They serve two purposes:
**
** 1. Serve as a convenient place to set a breakpoint in a debugger
@@ -3223,33 +3214,28 @@ int sqlite3_get_autocommit(sqlite3 *db){
** 2. Invoke sqlite3_log() to provide the source code location where
** a low-level error is first detected.
*/
static int reportError(int iErr, int lineno, const char *zType){
sqlite3_log(iErr, "%s at line %d of [%.10s]",
zType, lineno, 20+sqlite3_sourceid());
return iErr;
}
int sqlite3CorruptError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_CORRUPT, lineno, "database corruption");
sqlite3_log(SQLITE_CORRUPT,
"database corruption at line %d of [%.10s]",
lineno, 20+sqlite3_sourceid());
return SQLITE_CORRUPT;
}
int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_MISUSE, lineno, "misuse");
sqlite3_log(SQLITE_MISUSE,
"misuse at line %d of [%.10s]",
lineno, 20+sqlite3_sourceid());
return SQLITE_MISUSE;
}
int sqlite3CantopenError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_CANTOPEN, lineno, "cannot open file");
sqlite3_log(SQLITE_CANTOPEN,
"cannot open file at line %d of [%.10s]",
lineno, 20+sqlite3_sourceid());
return SQLITE_CANTOPEN;
}
#ifdef SQLITE_DEBUG
int sqlite3NomemError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_NOMEM, lineno, "OOM");
}
int sqlite3IoerrnomemError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
}
#endif
#ifndef SQLITE_OMIT_DEPRECATED
/*
@@ -3343,7 +3329,7 @@ int sqlite3_table_column_metadata(
** explicitly declared column. Copy meta information from *pCol.
*/
if( pCol ){
zDataType = sqlite3ColumnType(pCol,0);
zDataType = pCol->zType;
zCollSeq = pCol->zColl;
notnull = pCol->notNull!=0;
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
@@ -3580,7 +3566,7 @@ int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_ASSERT: {
volatile int x = 0;
assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
assert( (x = va_arg(ap,int))!=0 );
rc = x;
break;
}
+49 -102
View File
@@ -575,24 +575,10 @@ void *sqlite3MallocZero(u64 n){
** the mallocFailed flag in the connection pointer.
*/
void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
void *p;
testcase( db==0 );
p = sqlite3DbMallocRaw(db, n);
if( p ) memset(p, 0, (size_t)n);
return p;
}
/* Finish the work of sqlite3DbMallocRawNN for the unusual and
** slower case when the allocation cannot be fulfilled using lookaside.
*/
static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
void *p;
assert( db!=0 );
p = sqlite3Malloc(n);
if( !p ) sqlite3OomFault(db);
sqlite3MemdebugSetType(p,
(db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
void *p = sqlite3DbMallocRaw(db, n);
if( p ){
memset(p, 0, (size_t)n);
}
return p;
}
@@ -614,73 +600,67 @@ static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
**
** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
** that all prior mallocs (ex: "a") worked too.
**
** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is
** not a NULL pointer.
*/
static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n);
void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
void *p;
if( db ) return sqlite3DbMallocRawNN(db, n);
p = sqlite3Malloc(n);
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
return p;
}
void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
assert( db==0 || db->pnBytesFreed==0 );
#ifndef SQLITE_OMIT_LOOKASIDE
LookasideSlot *pBuf;
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
assert( db->pnBytesFreed==0 );
if( db->lookaside.bDisable==0 ){
assert( db->mallocFailed==0 );
if( n>db->lookaside.sz ){
db->lookaside.anStat[1]++;
}else if( (pBuf = db->lookaside.pFree)==0 ){
db->lookaside.anStat[2]++;
}else{
db->lookaside.pFree = pBuf->pNext;
db->lookaside.nOut++;
db->lookaside.anStat[0]++;
if( db->lookaside.nOut>db->lookaside.mxOut ){
db->lookaside.mxOut = db->lookaside.nOut;
}
return (void*)pBuf;
if( db ){
LookasideSlot *pBuf;
if( db->mallocFailed ){
return 0;
}
if( db->lookaside.bEnabled ){
if( n>db->lookaside.sz ){
db->lookaside.anStat[1]++;
}else if( (pBuf = db->lookaside.pFree)==0 ){
db->lookaside.anStat[2]++;
}else{
db->lookaside.pFree = pBuf->pNext;
db->lookaside.nOut++;
db->lookaside.anStat[0]++;
if( db->lookaside.nOut>db->lookaside.mxOut ){
db->lookaside.mxOut = db->lookaside.nOut;
}
return (void*)pBuf;
}
}
}else if( db->mallocFailed ){
return 0;
}
#else
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
assert( db->pnBytesFreed==0 );
if( db->mallocFailed ){
if( db && db->mallocFailed ){
return 0;
}
#endif
return dbMallocRawFinish(db, n);
}
/* Forward declaration */
static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n);
static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
void *p = sqlite3Malloc(n);
if( !p && db ){
db->mallocFailed = 1;
}
sqlite3MemdebugSetType(p,
(db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
return p;
}
/*
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag in the connection object.
*/
void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
assert( db!=0 );
if( p==0 ) return sqlite3DbMallocRawNN(db, n);
assert( sqlite3_mutex_held(db->mutex) );
if( isLookaside(db,p) && n<=db->lookaside.sz ) return p;
return dbReallocFinish(db, p, n);
}
static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
void *pNew = 0;
assert( db!=0 );
assert( p!=0 );
assert( sqlite3_mutex_held(db->mutex) );
if( db->mallocFailed==0 ){
if( p==0 ){
return sqlite3DbMallocRaw(db, n);
}
if( isLookaside(db, p) ){
pNew = sqlite3DbMallocRawNN(db, n);
if( n<=db->lookaside.sz ){
return p;
}
pNew = sqlite3DbMallocRaw(db, n);
if( pNew ){
memcpy(pNew, p, db->lookaside.sz);
sqlite3DbFree(db, p);
@@ -691,10 +671,10 @@ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
pNew = sqlite3_realloc64(p, n);
if( !pNew ){
sqlite3OomFault(db);
db->mallocFailed = 1;
}
sqlite3MemdebugSetType(pNew,
(db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
(db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
}
}
return pNew;
@@ -736,12 +716,11 @@ char *sqlite3DbStrDup(sqlite3 *db, const char *z){
}
char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
char *zNew;
assert( db!=0 );
if( z==0 ){
return 0;
}
assert( (n&0x7fffffff)==n );
zNew = sqlite3DbMallocRawNN(db, n+1);
zNew = sqlite3DbMallocRaw(db, n+1);
if( zNew ){
memcpy(zNew, z, (size_t)n);
zNew[n] = 0;
@@ -757,45 +736,13 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
*pz = sqlite3DbStrDup(db, zNew);
}
/*
** Call this routine to record the fact that an OOM (out-of-memory) error
** has happened. This routine will set db->mallocFailed, and also
** temporarily disable the lookaside memory allocator and interrupt
** any running VDBEs.
*/
void sqlite3OomFault(sqlite3 *db){
if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
db->mallocFailed = 1;
if( db->nVdbeExec>0 ){
db->u1.isInterrupted = 1;
}
db->lookaside.bDisable++;
}
}
/*
** This routine reactivates the memory allocator and clears the
** db->mallocFailed flag as necessary.
**
** The memory allocator is not restarted if there are running
** VDBEs.
*/
void sqlite3OomClear(sqlite3 *db){
if( db->mallocFailed && db->nVdbeExec==0 ){
db->mallocFailed = 0;
db->u1.isInterrupted = 0;
assert( db->lookaside.bDisable>0 );
db->lookaside.bDisable--;
}
}
/*
** Take actions at the end of an API call to indicate an OOM error
*/
static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
sqlite3OomClear(db);
db->mallocFailed = 0;
sqlite3Error(db, SQLITE_NOMEM);
return SQLITE_NOMEM_BKPT;
return SQLITE_NOMEM;
}
/*
+79 -233
View File
@@ -21,28 +21,24 @@ typedef struct MemJournal MemJournal;
typedef struct FilePoint FilePoint;
typedef struct FileChunk FileChunk;
/* Space to hold the rollback journal is allocated in increments of
** this many bytes.
**
** The size chosen is a little less than a power of two. That way,
** the FileChunk object will have a size that almost exactly fills
** a power-of-two allocation. This minimizes wasted space in power-of-two
** memory allocators.
*/
#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
/*
** The rollback journal is composed of a linked list of these structures.
**
** The zChunk array is always at least 8 bytes in size - usually much more.
** Its actual size is stored in the MemJournal.nChunkSize variable.
*/
struct FileChunk {
FileChunk *pNext; /* Next chunk in the journal */
u8 zChunk[8]; /* Content of this chunk */
u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
};
/*
** By default, allocate this many bytes of memory for each FileChunk object.
*/
#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024
/*
** For chunk size nChunkSize, return the number of bytes that should
** be allocated for each FileChunk structure.
*/
#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8))
/*
** An instance of this object serves as a cursor into the rollback journal.
** The cursor can be either for reading or writing.
@@ -53,22 +49,14 @@ struct FilePoint {
};
/*
** This structure is a subclass of sqlite3_file. Each open memory-journal
** This subclass is a subclass of sqlite3_file. Each open memory-journal
** is an instance of this class.
*/
struct MemJournal {
const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
int nChunkSize; /* In-memory chunk-size */
int nSpill; /* Bytes of data before flushing */
int nSize; /* Bytes of data currently in memory */
sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
FileChunk *pFirst; /* Head of in-memory chunk-list */
FilePoint endpoint; /* Pointer to the end of the file */
FilePoint readpoint; /* Pointer to the end of the last xRead() */
int flags; /* xOpen flags */
sqlite3_vfs *pVfs; /* The "real" underlying VFS */
const char *zJournal; /* Name of the journal file */
};
/*
@@ -87,94 +75,36 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
#endif
/* SQLite never tries to read past the end of a rollback journal file */
assert( iOfst+iAmt<=p->endpoint.iOffset );
assert( (iAmt+iOfst)<=p->endpoint.iOffset );
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
for(pChunk=p->pFirst;
ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
pChunk=pChunk->pNext
){
iOff += p->nChunkSize;
iOff += JOURNAL_CHUNKSIZE;
}
}else{
pChunk = p->readpoint.pChunk;
assert( pChunk!=0 );
}
iChunkOffset = (int)(iOfst%p->nChunkSize);
iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
do {
int iSpace = p->nChunkSize - iChunkOffset;
int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
zOut += nCopy;
nRead -= iSpace;
iChunkOffset = 0;
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
p->readpoint.iOffset = iOfst+iAmt;
p->readpoint.pChunk = pChunk;
return SQLITE_OK;
}
/*
** Free the list of FileChunk structures headed at MemJournal.pFirst.
*/
static void memjrnlFreeChunks(MemJournal *p){
FileChunk *pIter;
FileChunk *pNext;
for(pIter=p->pFirst; pIter; pIter=pNext){
pNext = pIter->pNext;
sqlite3_free(pIter);
}
p->pFirst = 0;
}
/*
** Flush the contents of memory to a real file on disk.
*/
static int memjrnlCreateFile(MemJournal *p){
int rc;
sqlite3_file *pReal = (sqlite3_file*)p;
MemJournal copy = *p;
memset(p, 0, sizeof(MemJournal));
rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
if( rc==SQLITE_OK ){
int nChunk = copy.nChunkSize;
i64 iOff = 0;
FileChunk *pIter;
for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
if( iOff + nChunk > copy.endpoint.iOffset ){
nChunk = copy.endpoint.iOffset - iOff;
}
rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
if( rc ) break;
iOff += nChunk;
}
if( rc==SQLITE_OK ){
/* No error has occurred. Free the in-memory buffers. */
memjrnlFreeChunks(&copy);
}
}
if( rc!=SQLITE_OK ){
/* If an error occurred while creating or writing to the file, restore
** the original before returning. This way, SQLite uses the in-memory
** journal data to roll back changes made to the internal page-cache
** before this function was called. */
sqlite3OsClose(pReal);
*p = copy;
}
return rc;
}
/*
** Write data to the file.
*/
@@ -188,62 +118,38 @@ static int memjrnlWrite(
int nWrite = iAmt;
u8 *zWrite = (u8 *)zBuf;
/* If the file should be created now, create it and write the new data
** into the file on disk. */
if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
int rc = memjrnlCreateFile(p);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
}
return rc;
}
/* An in-memory journal file should only ever be appended to. Random
** access writes are not required by sqlite.
*/
assert( iOfst==p->endpoint.iOffset );
UNUSED_PARAMETER(iOfst);
/* If the contents of this write should be stored in memory */
else{
/* An in-memory journal file should only ever be appended to. Random
** access writes are not required. The only exception to this is when
** the in-memory journal is being used by a connection using the
** atomic-write optimization. In this case the first 28 bytes of the
** journal file may be written as part of committing the transaction. */
assert( iOfst==p->endpoint.iOffset || iOfst==0 );
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
}else
#else
assert( iOfst>0 || p->pFirst==0 );
#endif
{
while( nWrite>0 ){
FileChunk *pChunk = p->endpoint.pChunk;
int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
while( nWrite>0 ){
FileChunk *pChunk = p->endpoint.pChunk;
int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
if( iChunkOffset==0 ){
/* New chunk is required to extend the file. */
FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
if( !pNew ){
return SQLITE_IOERR_NOMEM_BKPT;
}
pNew->pNext = 0;
if( pChunk ){
assert( p->pFirst );
pChunk->pNext = pNew;
}else{
assert( !p->pFirst );
p->pFirst = pNew;
}
p->endpoint.pChunk = pNew;
}
memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace);
zWrite += iSpace;
nWrite -= iSpace;
p->endpoint.iOffset += iSpace;
if( iChunkOffset==0 ){
/* New chunk is required to extend the file. */
FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
if( !pNew ){
return SQLITE_IOERR_NOMEM;
}
p->nSize = iAmt + iOfst;
pNew->pNext = 0;
if( pChunk ){
assert( p->pFirst );
pChunk->pNext = pNew;
}else{
assert( !p->pFirst );
p->pFirst = pNew;
}
p->endpoint.pChunk = pNew;
}
memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
zWrite += iSpace;
nWrite -= iSpace;
p->endpoint.iOffset += iSpace;
}
return SQLITE_OK;
@@ -251,21 +157,19 @@ static int memjrnlWrite(
/*
** Truncate the file.
**
** If the journal file is already on disk, truncate it there. Or, if it
** is still in main memory but is being truncated to zero bytes in size,
** ignore
*/
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd;
if( ALWAYS(size==0) ){
memjrnlFreeChunks(p);
p->nSize = 0;
p->endpoint.pChunk = 0;
p->endpoint.iOffset = 0;
p->readpoint.pChunk = 0;
p->readpoint.iOffset = 0;
FileChunk *pChunk;
assert(size==0);
UNUSED_PARAMETER(size);
pChunk = p->pFirst;
while( pChunk ){
FileChunk *pTmp = pChunk;
pChunk = pChunk->pNext;
sqlite3_free(pTmp);
}
sqlite3MemJournalOpen(pJfd);
return SQLITE_OK;
}
@@ -273,19 +177,21 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
** Close the file.
*/
static int memjrnlClose(sqlite3_file *pJfd){
MemJournal *p = (MemJournal *)pJfd;
memjrnlFreeChunks(p);
memjrnlTruncate(pJfd, 0);
return SQLITE_OK;
}
/*
** Sync the file.
**
** If the real file has been created, call its xSync method. Otherwise,
** syncing an in-memory journal is a no-op.
** Syncing an in-memory journal is a no-op. And, in fact, this routine
** is never called in a working implementation. This implementation
** exists purely as a contingency, in case some malfunction in some other
** part of SQLite causes Sync to be called by mistake.
*/
static int memjrnlSync(sqlite3_file *pJfd, int flags){
UNUSED_PARAMETER2(pJfd, flags);
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return SQLITE_OK;
}
@@ -324,86 +230,26 @@ static const struct sqlite3_io_methods MemJournalMethods = {
};
/*
** Open a journal file.
**
** The behaviour of the journal file depends on the value of parameter
** nSpill. If nSpill is 0, then the journal file is always create and
** accessed using the underlying VFS. If nSpill is less than zero, then
** all content is always stored in main-memory. Finally, if nSpill is a
** positive value, then the journal file is initially created in-memory
** but may be flushed to disk later on. In this case the journal file is
** flushed to disk either when it grows larger than nSpill bytes in size,
** or when sqlite3JournalCreate() is called.
*/
int sqlite3JournalOpen(
sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
const char *zName, /* Name of the journal file */
sqlite3_file *pJfd, /* Preallocated, blank file handle */
int flags, /* Opening flags */
int nSpill /* Bytes buffered before opening the file */
){
MemJournal *p = (MemJournal*)pJfd;
/* Zero the file-handle object. If nSpill was passed zero, initialize
** it using the sqlite3OsOpen() function of the underlying VFS. In this
** case none of the code in this module is executed as a result of calls
** made on the journal file-handle. */
memset(p, 0, sizeof(MemJournal));
if( nSpill==0 ){
return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
}
if( nSpill>0 ){
p->nChunkSize = nSpill;
}else{
p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
}
p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
p->nSpill = nSpill;
p->flags = flags;
p->zJournal = zName;
p->pVfs = pVfs;
return SQLITE_OK;
}
/*
** Open an in-memory journal file.
** Open a journal file.
*/
void sqlite3MemJournalOpen(sqlite3_file *pJfd){
sqlite3JournalOpen(0, 0, pJfd, 0, -1);
MemJournal *p = (MemJournal *)pJfd;
assert( EIGHT_BYTE_ALIGNMENT(p) );
memset(p, 0, sqlite3MemJournalSize());
p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
}
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
/*
** If the argument p points to a MemJournal structure that is not an
** in-memory-only journal file (i.e. is one that was opened with a +ve
** nSpill parameter), and the underlying file has not yet been created,
** create it now.
** Return true if the file-handle passed as an argument is
** an in-memory journal
*/
int sqlite3JournalCreate(sqlite3_file *p){
int rc = SQLITE_OK;
if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
rc = memjrnlCreateFile((MemJournal*)p);
}
return rc;
}
#endif
/*
** The file-handle passed as the only argument is open on a journal file.
** Return true if this "journal file" is currently stored in heap memory,
** or false otherwise.
*/
int sqlite3JournalIsInMemory(sqlite3_file *p){
return p->pMethods==&MemJournalMethods;
int sqlite3IsMemJournal(sqlite3_file *pJfd){
return pJfd->pMethods==&MemJournalMethods;
}
/*
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
** Return the number of bytes required to store a MemJournal file descriptor.
*/
int sqlite3JournalSize(sqlite3_vfs *pVfs){
return MAX(pVfs->szOsFile, (int)sizeof(MemJournal));
int sqlite3MemJournalSize(void){
return sizeof(MemJournal);
}
+20 -47
View File
@@ -17,28 +17,6 @@
#include "sqliteInt.h"
#undef _SQLITE_OS_C_
/*
** If we compile with the SQLITE_TEST macro set, then the following block
** of code will give us the ability to simulate a disk I/O error. This
** is used for testing the I/O recovery logic.
*/
#if defined(SQLITE_TEST)
int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
int sqlite3_io_error_benign = 0; /* True if errors are benign */
int sqlite3_diskfull_pending = 0;
int sqlite3_diskfull = 0;
#endif /* defined(SQLITE_TEST) */
/*
** When testing, also keep a count of the number of open files.
*/
#if defined(SQLITE_TEST)
int sqlite3_open_file_count = 0;
#endif /* defined(SQLITE_TEST) */
/*
** The default SQLite sqlite3_vfs implementations do not allocate
** memory (actually, os_unix.c allocates a small amount of memory
@@ -46,7 +24,7 @@ int sqlite3_open_file_count = 0;
** So we test the effects of a malloc() failing and the sqlite3OsXXX()
** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
**
** The following functions are instrumented for malloc() failure
** The following functions are instrumented for malloc() failure
** testing:
**
** sqlite3OsRead()
@@ -66,9 +44,9 @@ int sqlite3_open_file_count = 0;
#if defined(SQLITE_TEST)
int sqlite3_memdebug_vfs_oom_test = 1;
#define DO_OS_MALLOC_TEST(x) \
if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \
if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
void *pTstAlloc = sqlite3Malloc(10); \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT; \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
sqlite3_free(pTstAlloc); \
}
#else
@@ -132,8 +110,8 @@ int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
#ifdef SQLITE_TEST
if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
** but the transaction is committed anyway.
**
@@ -202,10 +180,10 @@ int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
** VFS methods.
*/
int sqlite3OsOpen(
sqlite3_vfs *pVfs,
const char *zPath,
sqlite3_file *pFile,
int flags,
sqlite3_vfs *pVfs,
const char *zPath,
sqlite3_file *pFile,
int flags,
int *pFlagsOut
){
int rc;
@@ -224,18 +202,18 @@ int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return pVfs->xDelete(pVfs, zPath, dirSync);
}
int sqlite3OsAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
DO_OS_MALLOC_TEST(0);
return pVfs->xAccess(pVfs, zPath, flags, pResOut);
}
int sqlite3OsFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nPathOut,
sqlite3_vfs *pVfs,
const char *zPath,
int nPathOut,
char *zPathOut
){
DO_OS_MALLOC_TEST(0);
@@ -262,9 +240,6 @@ int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
int sqlite3OsGetLastError(sqlite3_vfs *pVfs){
return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0;
}
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
int rc;
/* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
@@ -284,13 +259,13 @@ int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
}
int sqlite3OsOpenMalloc(
sqlite3_vfs *pVfs,
const char *zFile,
sqlite3_file **ppFile,
sqlite3_vfs *pVfs,
const char *zFile,
sqlite3_file **ppFile,
int flags,
int *pOutFlags
){
int rc;
int rc = SQLITE_NOMEM;
sqlite3_file *pFile;
pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
if( pFile ){
@@ -300,8 +275,6 @@ int sqlite3OsOpenMalloc(
}else{
*ppFile = pFile;
}
}else{
rc = SQLITE_NOMEM_BKPT;
}
return rc;
}
@@ -321,7 +294,7 @@ int sqlite3OsCloseFree(sqlite3_file *pFile){
*/
int sqlite3OsInit(void){
void *p = sqlite3_malloc(10);
if( p==0 ) return SQLITE_NOMEM_BKPT;
if( p==0 ) return SQLITE_NOMEM;
sqlite3_free(p);
return sqlite3_os_init();
}

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