Compare commits
146 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff9fcd5a14 | |||
| 6b98d67b2b | |||
| 8e86b6a3df | |||
| ff0bc8f9f7 | |||
| e9afc3f279 | |||
| 3c559a8d3c | |||
| 48dd1d8e28 | |||
| a3bc66a3f5 | |||
| 3fb6730699 | |||
| f53b4ad0f9 | |||
| b7231a8cf0 | |||
| c2070c7d96 | |||
| 1529908001 | |||
| 736932c1eb | |||
| 5609baf35e | |||
| 68c121534c | |||
| f97dad8849 | |||
| 6a8ac852aa | |||
| cde81d5fd0 | |||
| 935850ef75 | |||
| e96f2df3dd | |||
| 43ae8f6f4d | |||
| e48ae7157a | |||
| 6044f31d13 | |||
| c9bbb01180 | |||
| 781597feca | |||
| 27f2468422 | |||
| 83e05b814e | |||
| 02c1e264a9 | |||
| 77a90ce811 | |||
| 4bd855fae5 | |||
| e82384817d | |||
| c007f61bb0 | |||
| a7b9e7d2d9 | |||
| df2c52f728 | |||
| 157c957a65 | |||
| 5b34f15a82 | |||
| a0b7ca90b7 | |||
| 9e83e465eb | |||
| c0caea21de | |||
| a5e2b50d0a | |||
| 548ff8f491 | |||
| 6bb9889ef0 | |||
| 0f710546e7 | |||
| 796407395e | |||
| 1273614191 | |||
| d9b3c549b3 | |||
| 52c40a89bb | |||
| 4712c21287 | |||
| 2e7be08152 | |||
| 9ee8810be2 | |||
| 8009c9b439 | |||
| d2d8ca600e | |||
| faecf50504 | |||
| 86a1119133 | |||
| eacc050f30 | |||
| 731dc0cb0e | |||
| 6451c2b04e | |||
| 62e603a904 | |||
| f253813b40 | |||
| 6117272e03 | |||
| f574259a64 | |||
| 441aa095ed | |||
| 897f6833fc | |||
| 75cc2f7a14 | |||
| 7dd9fb65e2 | |||
| 220942b757 | |||
| 2347e3b1bb | |||
| 44a3ba7123 | |||
| f6a2342651 | |||
| 1a8a0d3f1a | |||
| c254ff62c1 | |||
| bd6e51c0f9 | |||
| 0e56c52e1d | |||
| fdf9f045b7 | |||
| 72de9addc7 | |||
| b91ca38514 | |||
| 4a11505be9 | |||
| a153643b07 | |||
| e724d3d26a | |||
| 3852413246 | |||
| c5f246eb37 | |||
| e03d76254c | |||
| 57fe136b23 | |||
| 48cdabcb1a | |||
| d1ae96d39e | |||
| fb4c9242a5 | |||
| 5da73e1a09 | |||
| 4243e27f22 | |||
| 8164722c58 | |||
| 75525cbe24 | |||
| 4a6b8a05cd | |||
| 253666e520 | |||
| 224155dd1c | |||
| 264d2b97a9 | |||
| e4618fb30d | |||
| 09e1df6c00 | |||
| 67a03cfd6e | |||
| 7de2a1faf6 | |||
| 42685f211e | |||
| 65e6b0dd12 | |||
| 6b6828625b | |||
| 9881d60d17 | |||
| b51926e67c | |||
| e3bfbb7284 | |||
| 440e6ff3b0 | |||
| 2dd3cdcfab | |||
| 1f8bb4b0a8 | |||
| 453e0261df | |||
| 9940e2aa45 | |||
| 8ad1d8ba38 | |||
| b79c718f1a | |||
| cfc9df76e1 | |||
| 9dfaf621d1 | |||
| a01c7c70fd | |||
| aa9933c115 | |||
| f34a9fef4c | |||
| 9df245b073 | |||
| 0bf8277196 | |||
| e756bfb363 | |||
| f0582f43dd | |||
| 374cd78c1d | |||
| b355c2cc12 | |||
| 71794dbaeb | |||
| 00b638bb6f | |||
| 2cf4acbd9f | |||
| 65b9ac5224 | |||
| d249090450 | |||
| 87744513e7 | |||
| d83cad235a | |||
| 48e080b26c | |||
| a38c9516e8 | |||
| 4c417181c2 | |||
| e4529c5724 | |||
| 9bc21b535e | |||
| 926345e027 | |||
| 036dbec01c | |||
| 5a500afd57 | |||
| 14eec74a5b | |||
| 835c19bb9a | |||
| 491451dead | |||
| 2e72791781 | |||
| f74b9e0965 | |||
| 9598ae2c11 | |||
| f3a4c7c2c7 | |||
| 8bc5262915 |
@@ -239,8 +239,10 @@ SRC = \
|
||||
$(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 \
|
||||
$(TOP)/src/os_win.h \
|
||||
$(TOP)/src/pager.c \
|
||||
$(TOP)/src/pager.h \
|
||||
$(TOP)/src/parse.y \
|
||||
@@ -457,6 +459,8 @@ HDR = \
|
||||
opcodes.h \
|
||||
$(TOP)/src/os.h \
|
||||
$(TOP)/src/os_common.h \
|
||||
$(TOP)/src/os_setup.h \
|
||||
$(TOP)/src/os_win.h \
|
||||
$(TOP)/src/pager.h \
|
||||
$(TOP)/src/pcache.h \
|
||||
parse.h \
|
||||
|
||||
+105
-29
@@ -1,6 +1,9 @@
|
||||
#
|
||||
# nmake Makefile for SQLite
|
||||
#
|
||||
###############################################################################
|
||||
############################## START OF OPTIONS ###############################
|
||||
###############################################################################
|
||||
|
||||
# The toplevel directory of the source tree. This is the directory
|
||||
# that contains this "Makefile.msc".
|
||||
@@ -13,6 +16,13 @@ TOP = .
|
||||
USE_AMALGAMATION = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to use the library paths and other options necessary for
|
||||
# Windows Phone 8.1.
|
||||
#
|
||||
!IFNDEF USE_WP81_OPTS
|
||||
USE_WP81_OPTS = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to split the SQLite amalgamation file into chunks to
|
||||
# be used for debugging with Visual Studio.
|
||||
#
|
||||
@@ -116,6 +126,25 @@ DEBUG = 0
|
||||
OPTIMIZATIONS = 2
|
||||
!ENDIF
|
||||
|
||||
# These are the "standard" SQLite compilation options used when compiling for
|
||||
# the Windows platform.
|
||||
#
|
||||
!IFNDEF OPT_FEATURE_FLAGS
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
!ENDIF
|
||||
|
||||
###############################################################################
|
||||
############################### END OF OPTIONS ################################
|
||||
###############################################################################
|
||||
|
||||
# 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.
|
||||
#
|
||||
PROGRAMFILES_X86 = $(VCINSTALLDIR)\..\..
|
||||
PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\)
|
||||
|
||||
# Check for the predefined command macro CC. This should point to the compiler
|
||||
# binary for the target platform. If it is not defined, simply define it to
|
||||
# the legacy default value 'cl.exe'.
|
||||
@@ -140,6 +169,15 @@ LD = link.exe
|
||||
RC = rc.exe
|
||||
!ENDIF
|
||||
|
||||
# Check for the MSVC runtime library path macro. Othertise, this value will
|
||||
# default to the 'lib' directory underneath the MSVC installation directory.
|
||||
#
|
||||
!IFNDEF CRTLIBPATH
|
||||
CRTLIBPATH = $(VCINSTALLDIR)\lib
|
||||
!ENDIF
|
||||
|
||||
CRTLIBPATH = $(CRTLIBPATH:\\=\)
|
||||
|
||||
# Check for the command macro NCC. This should point to the compiler binary
|
||||
# for the platform the compilation process is taking place on. If it is not
|
||||
# defined, simply define it to have the same value as the CC macro. When
|
||||
@@ -168,8 +206,8 @@ NCC = $(NCC:\\=\)
|
||||
NCC = $(CC)
|
||||
!ENDIF
|
||||
|
||||
# Check for the MSVC runtime library path macro. Othertise, this
|
||||
# value will default to the 'lib' directory underneath the MSVC
|
||||
# Check for the MSVC native runtime library path macro. Othertise,
|
||||
# this value will default to the 'lib' directory underneath the MSVC
|
||||
# installation directory.
|
||||
#
|
||||
!IFNDEF NCRTLIBPATH
|
||||
@@ -306,7 +344,6 @@ TCC = $(TCC) -DSQLITE_ENABLE_IOTRACE
|
||||
RCC = $(RCC) -DSQLITE_ENABLE_IOTRACE
|
||||
!ENDIF
|
||||
|
||||
#
|
||||
# Prevent warnings about "insecure" MSVC runtime library functions
|
||||
# being used.
|
||||
#
|
||||
@@ -314,28 +351,24 @@ TCC = $(TCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS
|
||||
BCC = $(BCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS
|
||||
RCC = $(RCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#
|
||||
# Prevent warnings about "deprecated" POSIX functions being used.
|
||||
#
|
||||
TCC = $(TCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS
|
||||
BCC = $(BCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS
|
||||
RCC = $(RCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS
|
||||
|
||||
#
|
||||
# Use the SQLite debugging heap subsystem?
|
||||
#
|
||||
!IF $(MEMDEBUG)!=0
|
||||
TCC = $(TCC) -DSQLITE_MEMDEBUG=1
|
||||
RCC = $(RCC) -DSQLITE_MEMDEBUG=1
|
||||
|
||||
#
|
||||
# Use native Win32 heap subsystem instead of malloc/free?
|
||||
#
|
||||
!ELSEIF $(WIN32HEAP)!=0
|
||||
TCC = $(TCC) -DSQLITE_WIN32_MALLOC=1
|
||||
RCC = $(RCC) -DSQLITE_WIN32_MALLOC=1
|
||||
|
||||
#
|
||||
# Validate the heap on every call into the native Win32 heap subsystem?
|
||||
#
|
||||
!IF $(DEBUG)>2
|
||||
@@ -430,25 +463,25 @@ RCC = $(RCC) -DSQLITE_TEMP_STORE=1
|
||||
# The same set of OMIT and ENABLE flags should be passed to the
|
||||
# LEMON parser generator and the mkkeywordhash tool as well.
|
||||
|
||||
# BEGIN standard options
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
# END standard options
|
||||
# These are the required SQLite compilation options used when compiling for
|
||||
# the Windows platform.
|
||||
#
|
||||
REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS) -DSQLITE_MAX_TRIGGER_DEPTH=100
|
||||
|
||||
# BEGIN required Windows option
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_MAX_TRIGGER_DEPTH=100
|
||||
# END required Windows option
|
||||
# Add the required and optional SQLite compilation options into the command
|
||||
# lines used to invoke the MSVC code and resource compilers.
|
||||
#
|
||||
TCC = $(TCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS)
|
||||
RCC = $(RCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS)
|
||||
|
||||
TCC = $(TCC) $(OPT_FEATURE_FLAGS)
|
||||
RCC = $(RCC) $(OPT_FEATURE_FLAGS)
|
||||
|
||||
# Add in any optional parameters specified on the make commane line
|
||||
# ie. make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1".
|
||||
# Add in any optional parameters specified on the commane line, e.g.
|
||||
# nmake /f Makefile.msc all "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1"
|
||||
#
|
||||
TCC = $(TCC) $(OPTS)
|
||||
RCC = $(RCC) $(OPTS)
|
||||
|
||||
# If compiling for debugging, add some defines.
|
||||
#
|
||||
!IF $(DEBUG)>0
|
||||
TCC = $(TCC) -D_DEBUG
|
||||
BCC = $(BCC) -D_DEBUG
|
||||
@@ -457,6 +490,7 @@ RCC = $(RCC) -D_DEBUG
|
||||
|
||||
# If optimizations are enabled or disabled (either implicitly or
|
||||
# explicitly), add the necessary flags.
|
||||
#
|
||||
!IF $(DEBUG)>0 || $(OPTIMIZATIONS)==0
|
||||
TCC = $(TCC) -Od
|
||||
BCC = $(BCC) -Od
|
||||
@@ -472,12 +506,14 @@ BCC = $(BCC) -O1
|
||||
!ENDIF
|
||||
|
||||
# If symbols are enabled (or compiling for debugging), enable PDBs.
|
||||
#
|
||||
!IF $(DEBUG)>0 || $(SYMBOLS)!=0
|
||||
TCC = $(TCC) -Zi
|
||||
BCC = $(BCC) -Zi
|
||||
!ENDIF
|
||||
|
||||
# If ICU support is enabled, add the compiler options for it.
|
||||
#
|
||||
!IF $(USE_ICU)!=0
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_ICU=1
|
||||
RCC = $(RCC) -DSQLITE_ENABLE_ICU=1
|
||||
@@ -489,6 +525,7 @@ RCC = $(RCC) -I$(ICUINCDIR)
|
||||
|
||||
# Command line prefixes for compiling code, compiling resources,
|
||||
# linking, etc.
|
||||
#
|
||||
LTCOMPILE = $(TCC) -Fo$@
|
||||
LTRCOMPILE = $(RCC) -r
|
||||
LTLIB = lib.exe
|
||||
@@ -510,36 +547,71 @@ LTLIBOPTS = /MACHINE:$(PLATFORM)
|
||||
!IF $(FOR_WINRT)!=0
|
||||
LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER
|
||||
!IF "$(VISUALSTUDIOVERSION)"=="12.0"
|
||||
!IFNDEF STORELIBPATH
|
||||
!IF "$(PLATFORM)"=="x86"
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(VCINSTALLDIR)\lib\store"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store
|
||||
!ELSEIF "$(PLATFORM)"=="x64"
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(VCINSTALLDIR)\lib\store\amd64"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store\amd64
|
||||
!ELSEIF "$(PLATFORM)"=="ARM"
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(VCINSTALLDIR)\lib\store\arm"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store\arm
|
||||
!ELSE
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(VCINSTALLDIR)\lib\store"
|
||||
STORELIBPATH = $(CRTLIBPATH)\store
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
STORELIBPATH = $(STORELIBPATH:\\=\)
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(STORELIBPATH)"
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# When compiling for Windows Phone 8.1, an extra library path is
|
||||
# required.
|
||||
#
|
||||
!IF $(USE_WP81_OPTS)!=0
|
||||
!IFNDEF WP81LIBPATH
|
||||
!IF "$(PLATFORM)"=="x86"
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
|
||||
!ELSEIF "$(PLATFORM)"=="ARM"
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\ARM
|
||||
!ELSE
|
||||
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# When compiling for Windows Phone 8.1, some extra linker options
|
||||
# are also required.
|
||||
#
|
||||
!IF $(USE_WP81_OPTS)!=0
|
||||
!IFDEF WP81LIBPATH
|
||||
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
|
||||
!ENDIF
|
||||
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
|
||||
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
|
||||
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
|
||||
!ENDIF
|
||||
|
||||
# If either debugging or symbols are enabled, enable PDBs.
|
||||
#
|
||||
!IF $(DEBUG)>0 || $(SYMBOLS)!=0
|
||||
LDFLAGS = /DEBUG
|
||||
!ENDIF
|
||||
|
||||
# Start with the Tcl related linker options.
|
||||
#
|
||||
!IF $(NO_TCL)==0
|
||||
LTLIBPATHS = /LIBPATH:$(TCLLIBDIR)
|
||||
LTLIBS = $(LIBTCL)
|
||||
!ENDIF
|
||||
|
||||
# If ICU support is enabled, add the linker options for it.
|
||||
#
|
||||
!IF $(USE_ICU)!=0
|
||||
LTLIBPATHS = $(LTLIBPATHS) /LIBPATH:$(ICULIBDIR)
|
||||
LTLIBS = $(LTLIBS) $(LIBICU)
|
||||
!ENDIF
|
||||
|
||||
# nawk compatible awk.
|
||||
#
|
||||
!IFNDEF NAWK
|
||||
NAWK = gawk.exe
|
||||
!ENDIF
|
||||
@@ -637,8 +709,10 @@ SRC = \
|
||||
$(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 \
|
||||
$(TOP)\src\os_win.h \
|
||||
$(TOP)\src\pager.c \
|
||||
$(TOP)\src\pager.h \
|
||||
$(TOP)\src\parse.y \
|
||||
@@ -858,6 +932,8 @@ HDR = \
|
||||
opcodes.h \
|
||||
$(TOP)\src\os.h \
|
||||
$(TOP)\src\os_common.h \
|
||||
$(TOP)\src\os_setup.h \
|
||||
$(TOP)\src\os_win.h \
|
||||
$(TOP)\src\pager.h \
|
||||
$(TOP)\src\pcache.h \
|
||||
parse.h \
|
||||
@@ -954,7 +1030,7 @@ lempar.c: $(TOP)\src\lempar.c
|
||||
copy $(TOP)\src\lempar.c .
|
||||
|
||||
lemon.exe: $(TOP)\tool\lemon.c lempar.c
|
||||
$(BCC) -Daccess=_access -Fe$@ $(TOP)\tool\lemon.c /link $(NLTLIBPATHS)
|
||||
$(BCC) -Daccess=_access -Fe$@ $(TOP)\tool\lemon.c /link $(NLTLINKOPTS) $(NLTLIBPATHS)
|
||||
|
||||
# Rules to build individual *.lo files from generated *.c files. This
|
||||
# applies to:
|
||||
@@ -1214,7 +1290,7 @@ parse.h: parse.c
|
||||
parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\addopcodes.awk
|
||||
del /Q parse.y parse.h parse.h.temp
|
||||
copy $(TOP)\src\parse.y .
|
||||
.\lemon.exe $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
|
||||
move parse.h parse.h.temp
|
||||
$(NAWK) -f $(TOP)\addopcodes.awk parse.h.temp > parse.h
|
||||
|
||||
@@ -1222,7 +1298,7 @@ sqlite3.h: $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION
|
||||
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > sqlite3.h
|
||||
|
||||
mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c
|
||||
$(BCC) -Fe$@ $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c /link $(NLTLIBPATHS)
|
||||
$(BCC) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c /link $(NLTLINKOPTS) $(NLTLIBPATHS)
|
||||
|
||||
keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
|
||||
.\mkkeywordhash.exe > keywordhash.h
|
||||
@@ -1370,8 +1446,8 @@ clean:
|
||||
del /Q *.lo *.ilk *.lib *.obj *.pdb sqlite3.exe libsqlite3.lib
|
||||
del /Q *.cod *.da *.bb *.bbg gmon.out
|
||||
del /Q sqlite3.h opcodes.c opcodes.h
|
||||
del /Q lemon.exe lempar.c parse.*
|
||||
del /Q mkkeywordhash.exe keywordhash.h
|
||||
del /Q lemon.* lempar.c parse.*
|
||||
del /Q mkkeywordhash.* keywordhash.h
|
||||
del /Q notasharedlib.*
|
||||
-rmdir /Q/S .deps
|
||||
-rmdir /Q/S .libs
|
||||
|
||||
@@ -262,8 +262,10 @@ SRC = \
|
||||
$(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 \
|
||||
$(TOP)/src/os_win.h \
|
||||
$(TOP)/src/pager.c \
|
||||
$(TOP)/src/pager.h \
|
||||
$(TOP)/src/parse.y \
|
||||
@@ -416,6 +418,8 @@ HDR = \
|
||||
opcodes.h \
|
||||
$(TOP)/src/os.h \
|
||||
$(TOP)/src/os_common.h \
|
||||
$(TOP)/src/os_setup.h \
|
||||
$(TOP)/src/os_win.h \
|
||||
$(TOP)/src/pager.h \
|
||||
$(TOP)/src/pcache.h \
|
||||
parse.h \
|
||||
|
||||
+9
-4
@@ -1333,7 +1333,7 @@ static int fts3InitVtab(
|
||||
p->bHasStat = isFts4;
|
||||
p->bFts4 = isFts4;
|
||||
p->bDescIdx = bDescIdx;
|
||||
p->bAutoincrmerge = 0xff; /* 0xff means setting unknown */
|
||||
p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */
|
||||
p->zContentTbl = zContent;
|
||||
p->zLanguageid = zLanguageid;
|
||||
zContent = 0;
|
||||
@@ -1376,7 +1376,9 @@ static int fts3InitVtab(
|
||||
int n = (int)strlen(p->azColumn[iCol]);
|
||||
for(i=0; i<nNotindexed; i++){
|
||||
char *zNot = azNotindexed[i];
|
||||
if( zNot && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n) ){
|
||||
if( zNot && n==(int)strlen(zNot)
|
||||
&& 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n)
|
||||
){
|
||||
p->abNotindexed[iCol] = 1;
|
||||
sqlite3_free(zNot);
|
||||
azNotindexed[i] = 0;
|
||||
@@ -3302,7 +3304,10 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
||||
Fts3Table *p = (Fts3Table*)pVtab;
|
||||
int rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
|
||||
if( rc==SQLITE_OK && p->bAutoincrmerge==1 && p->nLeafAdd>(nMinMerge/16) ){
|
||||
if( rc==SQLITE_OK
|
||||
&& p->nLeafAdd>(nMinMerge/16)
|
||||
&& p->nAutoincrmerge && p->nAutoincrmerge!=0xff
|
||||
){
|
||||
int mxLevel = 0; /* Maximum relative level value in db */
|
||||
int A; /* Incr-merge parameter A */
|
||||
|
||||
@@ -3310,7 +3315,7 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
||||
assert( rc==SQLITE_OK || mxLevel==0 );
|
||||
A = p->nLeafAdd * mxLevel;
|
||||
A += (A/2);
|
||||
if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8);
|
||||
if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge);
|
||||
}
|
||||
sqlite3Fts3SegmentsClose(p);
|
||||
return rc;
|
||||
|
||||
+2
-2
@@ -210,13 +210,13 @@ struct Fts3Table {
|
||||
sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */
|
||||
char *zContentTbl; /* content=xxx option, or NULL */
|
||||
char *zLanguageid; /* languageid=xxx option, or NULL */
|
||||
u8 bAutoincrmerge; /* True if automerge=1 */
|
||||
int nAutoincrmerge; /* Value configured by 'automerge' */
|
||||
u32 nLeafAdd; /* Number of leaf blocks added this trans */
|
||||
|
||||
/* Precompiled statements used by the implementation. Each of these
|
||||
** statements is run and reset within a single virtual table API call.
|
||||
*/
|
||||
sqlite3_stmt *aStmt[37];
|
||||
sqlite3_stmt *aStmt[40];
|
||||
|
||||
char *zReadExprlist;
|
||||
char *zWriteExprlist;
|
||||
|
||||
+104
-101
@@ -185,40 +185,23 @@ static int getNextToken(
|
||||
int rc;
|
||||
sqlite3_tokenizer_cursor *pCursor;
|
||||
Fts3Expr *pRet = 0;
|
||||
int nConsumed = 0;
|
||||
int i = 0;
|
||||
|
||||
rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
|
||||
/* Set variable i to the maximum number of bytes of input to tokenize. */
|
||||
for(i=0; i<n; i++){
|
||||
if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break;
|
||||
if( z[i]=='*' || z[i]=='"' ) break;
|
||||
}
|
||||
|
||||
*pnConsumed = i;
|
||||
rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor);
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zToken;
|
||||
int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
|
||||
int nByte; /* total space to allocate */
|
||||
|
||||
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
|
||||
|
||||
if( (rc==SQLITE_OK || rc==SQLITE_DONE) && sqlite3_fts3_enable_parentheses ){
|
||||
int i;
|
||||
if( rc==SQLITE_DONE ) iStart = n;
|
||||
for(i=0; i<iStart; i++){
|
||||
if( z[i]=='(' ){
|
||||
pParse->nNest++;
|
||||
rc = fts3ExprParse(pParse, &z[i+1], n-i-1, &pRet, &nConsumed);
|
||||
if( rc==SQLITE_OK && !pRet ){
|
||||
rc = SQLITE_DONE;
|
||||
}
|
||||
nConsumed = (int)(i + 1 + nConsumed);
|
||||
break;
|
||||
}
|
||||
|
||||
if( z[i]==')' ){
|
||||
rc = SQLITE_DONE;
|
||||
pParse->nNest--;
|
||||
nConsumed = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( nConsumed==0 && rc==SQLITE_OK ){
|
||||
if( rc==SQLITE_OK ){
|
||||
nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
|
||||
pRet = (Fts3Expr *)fts3MallocZero(nByte);
|
||||
if( !pRet ){
|
||||
@@ -252,13 +235,14 @@ static int getNextToken(
|
||||
}
|
||||
|
||||
}
|
||||
nConsumed = iEnd;
|
||||
*pnConsumed = iEnd;
|
||||
}else if( i && rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
pModule->xClose(pCursor);
|
||||
}
|
||||
|
||||
*pnConsumed = nConsumed;
|
||||
*ppExpr = pRet;
|
||||
return rc;
|
||||
}
|
||||
@@ -508,6 +492,21 @@ static int getNextNode(
|
||||
return getNextString(pParse, &zInput[1], ii-1, ppExpr);
|
||||
}
|
||||
|
||||
if( sqlite3_fts3_enable_parentheses ){
|
||||
if( *zInput=='(' ){
|
||||
int nConsumed = 0;
|
||||
pParse->nNest++;
|
||||
rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed);
|
||||
if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; }
|
||||
*pnConsumed = (int)(zInput - z) + 1 + nConsumed;
|
||||
return rc;
|
||||
}else if( *zInput==')' ){
|
||||
pParse->nNest--;
|
||||
*pnConsumed = (int)((zInput - z) + 1);
|
||||
*ppExpr = 0;
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If control flows to this point, this must be a regular token, or
|
||||
** the end of the input. Read a regular token using the sqlite3_tokenizer
|
||||
@@ -626,96 +625,100 @@ static int fts3ExprParse(
|
||||
while( rc==SQLITE_OK ){
|
||||
Fts3Expr *p = 0;
|
||||
int nByte = 0;
|
||||
|
||||
rc = getNextNode(pParse, zIn, nIn, &p, &nByte);
|
||||
assert( nByte>0 || (rc!=SQLITE_OK && p==0) );
|
||||
if( rc==SQLITE_OK ){
|
||||
int isPhrase;
|
||||
if( p ){
|
||||
int isPhrase;
|
||||
|
||||
if( !sqlite3_fts3_enable_parentheses
|
||||
&& p->eType==FTSQUERY_PHRASE && pParse->isNot
|
||||
){
|
||||
/* Create an implicit NOT operator. */
|
||||
Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
|
||||
if( !pNot ){
|
||||
sqlite3Fts3ExprFree(p);
|
||||
rc = SQLITE_NOMEM;
|
||||
goto exprparse_out;
|
||||
}
|
||||
pNot->eType = FTSQUERY_NOT;
|
||||
pNot->pRight = p;
|
||||
p->pParent = pNot;
|
||||
if( pNotBranch ){
|
||||
pNot->pLeft = pNotBranch;
|
||||
pNotBranch->pParent = pNot;
|
||||
}
|
||||
pNotBranch = pNot;
|
||||
p = pPrev;
|
||||
}else{
|
||||
int eType = p->eType;
|
||||
isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);
|
||||
|
||||
/* The isRequirePhrase variable is set to true if a phrase or
|
||||
** an expression contained in parenthesis is required. If a
|
||||
** binary operator (AND, OR, NOT or NEAR) is encounted when
|
||||
** isRequirePhrase is set, this is a syntax error.
|
||||
*/
|
||||
if( !isPhrase && isRequirePhrase ){
|
||||
sqlite3Fts3ExprFree(p);
|
||||
rc = SQLITE_ERROR;
|
||||
goto exprparse_out;
|
||||
}
|
||||
|
||||
if( isPhrase && !isRequirePhrase ){
|
||||
/* Insert an implicit AND operator. */
|
||||
Fts3Expr *pAnd;
|
||||
assert( pRet && pPrev );
|
||||
pAnd = fts3MallocZero(sizeof(Fts3Expr));
|
||||
if( !pAnd ){
|
||||
if( !sqlite3_fts3_enable_parentheses
|
||||
&& p->eType==FTSQUERY_PHRASE && pParse->isNot
|
||||
){
|
||||
/* Create an implicit NOT operator. */
|
||||
Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
|
||||
if( !pNot ){
|
||||
sqlite3Fts3ExprFree(p);
|
||||
rc = SQLITE_NOMEM;
|
||||
goto exprparse_out;
|
||||
}
|
||||
pAnd->eType = FTSQUERY_AND;
|
||||
insertBinaryOperator(&pRet, pPrev, pAnd);
|
||||
pPrev = pAnd;
|
||||
}
|
||||
pNot->eType = FTSQUERY_NOT;
|
||||
pNot->pRight = p;
|
||||
p->pParent = pNot;
|
||||
if( pNotBranch ){
|
||||
pNot->pLeft = pNotBranch;
|
||||
pNotBranch->pParent = pNot;
|
||||
}
|
||||
pNotBranch = pNot;
|
||||
p = pPrev;
|
||||
}else{
|
||||
int eType = p->eType;
|
||||
isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);
|
||||
|
||||
/* This test catches attempts to make either operand of a NEAR
|
||||
** operator something other than a phrase. For example, either of
|
||||
** the following:
|
||||
**
|
||||
** (bracketed expression) NEAR phrase
|
||||
** phrase NEAR (bracketed expression)
|
||||
**
|
||||
** Return an error in either case.
|
||||
*/
|
||||
if( pPrev && (
|
||||
/* The isRequirePhrase variable is set to true if a phrase or
|
||||
** an expression contained in parenthesis is required. If a
|
||||
** binary operator (AND, OR, NOT or NEAR) is encounted when
|
||||
** isRequirePhrase is set, this is a syntax error.
|
||||
*/
|
||||
if( !isPhrase && isRequirePhrase ){
|
||||
sqlite3Fts3ExprFree(p);
|
||||
rc = SQLITE_ERROR;
|
||||
goto exprparse_out;
|
||||
}
|
||||
|
||||
if( isPhrase && !isRequirePhrase ){
|
||||
/* Insert an implicit AND operator. */
|
||||
Fts3Expr *pAnd;
|
||||
assert( pRet && pPrev );
|
||||
pAnd = fts3MallocZero(sizeof(Fts3Expr));
|
||||
if( !pAnd ){
|
||||
sqlite3Fts3ExprFree(p);
|
||||
rc = SQLITE_NOMEM;
|
||||
goto exprparse_out;
|
||||
}
|
||||
pAnd->eType = FTSQUERY_AND;
|
||||
insertBinaryOperator(&pRet, pPrev, pAnd);
|
||||
pPrev = pAnd;
|
||||
}
|
||||
|
||||
/* This test catches attempts to make either operand of a NEAR
|
||||
** operator something other than a phrase. For example, either of
|
||||
** the following:
|
||||
**
|
||||
** (bracketed expression) NEAR phrase
|
||||
** phrase NEAR (bracketed expression)
|
||||
**
|
||||
** Return an error in either case.
|
||||
*/
|
||||
if( pPrev && (
|
||||
(eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE)
|
||||
|| (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR)
|
||||
)){
|
||||
sqlite3Fts3ExprFree(p);
|
||||
rc = SQLITE_ERROR;
|
||||
goto exprparse_out;
|
||||
}
|
||||
|
||||
if( isPhrase ){
|
||||
if( pRet ){
|
||||
assert( pPrev && pPrev->pLeft && pPrev->pRight==0 );
|
||||
pPrev->pRight = p;
|
||||
p->pParent = pPrev;
|
||||
}else{
|
||||
pRet = p;
|
||||
)){
|
||||
sqlite3Fts3ExprFree(p);
|
||||
rc = SQLITE_ERROR;
|
||||
goto exprparse_out;
|
||||
}
|
||||
}else{
|
||||
insertBinaryOperator(&pRet, pPrev, p);
|
||||
|
||||
if( isPhrase ){
|
||||
if( pRet ){
|
||||
assert( pPrev && pPrev->pLeft && pPrev->pRight==0 );
|
||||
pPrev->pRight = p;
|
||||
p->pParent = pPrev;
|
||||
}else{
|
||||
pRet = p;
|
||||
}
|
||||
}else{
|
||||
insertBinaryOperator(&pRet, pPrev, p);
|
||||
}
|
||||
isRequirePhrase = !isPhrase;
|
||||
}
|
||||
isRequirePhrase = !isPhrase;
|
||||
pPrev = p;
|
||||
}
|
||||
assert( nByte>0 );
|
||||
}
|
||||
assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) );
|
||||
nIn -= nByte;
|
||||
zIn += nByte;
|
||||
pPrev = p;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_DONE && pRet && isRequirePhrase ){
|
||||
|
||||
+270
-35
@@ -193,6 +193,7 @@ struct SegmentWriter {
|
||||
int nSize; /* Size of allocation at aData */
|
||||
int nData; /* Bytes of data in aData */
|
||||
char *aData; /* Pointer to block from malloc() */
|
||||
i64 nLeafData; /* Number of bytes of leaf data written */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -268,6 +269,10 @@ struct SegmentNode {
|
||||
#define SQL_SELECT_INDEXES 35
|
||||
#define SQL_SELECT_MXLEVEL 36
|
||||
|
||||
#define SQL_SELECT_LEVEL_RANGE2 37
|
||||
#define SQL_UPDATE_LEVEL_IDX 38
|
||||
#define SQL_UPDATE_LEVEL 39
|
||||
|
||||
/*
|
||||
** This function is used to obtain an SQLite prepared statement handle
|
||||
** for the statement identified by the second argument. If successful,
|
||||
@@ -369,7 +374,18 @@ static int fts3SqlStmt(
|
||||
|
||||
/* SQL_SELECT_MXLEVEL
|
||||
** Return the largest relative level in the FTS index or indexes. */
|
||||
/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'"
|
||||
/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'",
|
||||
|
||||
/* Return segments in order from oldest to newest.*/
|
||||
/* 37 */ "SELECT level, idx, end_block "
|
||||
"FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? "
|
||||
"ORDER BY level DESC, idx ASC",
|
||||
|
||||
/* Update statements used while promoting segments */
|
||||
/* 38 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=-1,idx=? "
|
||||
"WHERE level=? AND idx=?",
|
||||
/* 39 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=? WHERE level=-1"
|
||||
|
||||
};
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pStmt;
|
||||
@@ -1910,6 +1926,7 @@ static int fts3WriteSegdir(
|
||||
sqlite3_int64 iStartBlock, /* Value for "start_block" field */
|
||||
sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */
|
||||
sqlite3_int64 iEndBlock, /* Value for "end_block" field */
|
||||
sqlite3_int64 nLeafData, /* Bytes of leaf data in segment */
|
||||
char *zRoot, /* Blob value for "root" field */
|
||||
int nRoot /* Number of bytes in buffer zRoot */
|
||||
){
|
||||
@@ -1920,7 +1937,13 @@ static int fts3WriteSegdir(
|
||||
sqlite3_bind_int(pStmt, 2, iIdx);
|
||||
sqlite3_bind_int64(pStmt, 3, iStartBlock);
|
||||
sqlite3_bind_int64(pStmt, 4, iLeafEndBlock);
|
||||
sqlite3_bind_int64(pStmt, 5, iEndBlock);
|
||||
if( nLeafData==0 ){
|
||||
sqlite3_bind_int64(pStmt, 5, iEndBlock);
|
||||
}else{
|
||||
char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData);
|
||||
if( !zEnd ) return SQLITE_NOMEM;
|
||||
sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free);
|
||||
}
|
||||
sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_reset(pStmt);
|
||||
@@ -2246,6 +2269,9 @@ static int fts3SegWriterAdd(
|
||||
nDoclist; /* Doclist data */
|
||||
}
|
||||
|
||||
/* Increase the total number of bytes written to account for the new entry. */
|
||||
pWriter->nLeafData += nReq;
|
||||
|
||||
/* If the buffer currently allocated is too small for this entry, realloc
|
||||
** the buffer to make it large enough.
|
||||
*/
|
||||
@@ -2317,13 +2343,13 @@ static int fts3SegWriterFlush(
|
||||
pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts3WriteSegdir(
|
||||
p, iLevel, iIdx, pWriter->iFirst, iLastLeaf, iLast, zRoot, nRoot);
|
||||
rc = fts3WriteSegdir(p, iLevel, iIdx,
|
||||
pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot);
|
||||
}
|
||||
}else{
|
||||
/* The entire tree fits on the root node. Write it to the segdir table. */
|
||||
rc = fts3WriteSegdir(
|
||||
p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData);
|
||||
rc = fts3WriteSegdir(p, iLevel, iIdx,
|
||||
0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData);
|
||||
}
|
||||
p->nLeafAdd++;
|
||||
return rc;
|
||||
@@ -2407,6 +2433,37 @@ static int fts3SegmentMaxLevel(
|
||||
return sqlite3_reset(pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** iAbsLevel is an absolute level that may be assumed to exist within
|
||||
** the database. This function checks if it is the largest level number
|
||||
** within its index. Assuming no error occurs, *pbMax is set to 1 if
|
||||
** iAbsLevel is indeed the largest level, or 0 otherwise, and SQLITE_OK
|
||||
** is returned. If an error occurs, an error code is returned and the
|
||||
** final value of *pbMax is undefined.
|
||||
*/
|
||||
static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){
|
||||
|
||||
/* Set pStmt to the compiled version of:
|
||||
**
|
||||
** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?
|
||||
**
|
||||
** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR).
|
||||
*/
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
sqlite3_bind_int64(pStmt, 1, iAbsLevel+1);
|
||||
sqlite3_bind_int64(pStmt, 2,
|
||||
((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
|
||||
);
|
||||
|
||||
*pbMax = 0;
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
*pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL;
|
||||
}
|
||||
return sqlite3_reset(pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete all entries in the %_segments table associated with the segment
|
||||
** opened with seg-reader pSeg. This function does not affect the contents
|
||||
@@ -2942,6 +2999,140 @@ void sqlite3Fts3SegReaderFinish(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Decode the "end_block" field, selected by column iCol of the SELECT
|
||||
** statement passed as the first argument.
|
||||
**
|
||||
** The "end_block" field may contain either an integer, or a text field
|
||||
** containing the text representation of two non-negative integers separated
|
||||
** by one or more space (0x20) characters. In the first case, set *piEndBlock
|
||||
** to the integer value and *pnByte to zero before returning. In the second,
|
||||
** set *piEndBlock to the first value and *pnByte to the second.
|
||||
*/
|
||||
static void fts3ReadEndBlockField(
|
||||
sqlite3_stmt *pStmt,
|
||||
int iCol,
|
||||
i64 *piEndBlock,
|
||||
i64 *pnByte
|
||||
){
|
||||
const unsigned char *zText = sqlite3_column_text(pStmt, iCol);
|
||||
if( zText ){
|
||||
int i;
|
||||
int iMul = 1;
|
||||
i64 iVal = 0;
|
||||
for(i=0; zText[i]>='0' && zText[i]<='9'; i++){
|
||||
iVal = iVal*10 + (zText[i] - '0');
|
||||
}
|
||||
*piEndBlock = iVal;
|
||||
while( zText[i]==' ' ) i++;
|
||||
iVal = 0;
|
||||
if( zText[i]=='-' ){
|
||||
i++;
|
||||
iMul = -1;
|
||||
}
|
||||
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
|
||||
iVal = iVal*10 + (zText[i] - '0');
|
||||
}
|
||||
*pnByte = (iVal * (i64)iMul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** A segment of size nByte bytes has just been written to absolute level
|
||||
** iAbsLevel. Promote any segments that should be promoted as a result.
|
||||
*/
|
||||
static int fts3PromoteSegments(
|
||||
Fts3Table *p, /* FTS table handle */
|
||||
sqlite3_int64 iAbsLevel, /* Absolute level just updated */
|
||||
sqlite3_int64 nByte /* Size of new segment at iAbsLevel */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pRange;
|
||||
|
||||
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE2, &pRange, 0);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int bOk = 0;
|
||||
i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1;
|
||||
i64 nLimit = (nByte*3)/2;
|
||||
|
||||
/* Loop through all entries in the %_segdir table corresponding to
|
||||
** segments in this index on levels greater than iAbsLevel. If there is
|
||||
** at least one such segment, and it is possible to determine that all
|
||||
** such segments are smaller than nLimit bytes in size, they will be
|
||||
** promoted to level iAbsLevel. */
|
||||
sqlite3_bind_int64(pRange, 1, iAbsLevel+1);
|
||||
sqlite3_bind_int64(pRange, 2, iLast);
|
||||
while( SQLITE_ROW==sqlite3_step(pRange) ){
|
||||
i64 nSize = 0, dummy;
|
||||
fts3ReadEndBlockField(pRange, 2, &dummy, &nSize);
|
||||
if( nSize<=0 || nSize>nLimit ){
|
||||
/* If nSize==0, then the %_segdir.end_block field does not not
|
||||
** contain a size value. This happens if it was written by an
|
||||
** old version of FTS. In this case it is not possible to determine
|
||||
** the size of the segment, and so segment promotion does not
|
||||
** take place. */
|
||||
bOk = 0;
|
||||
break;
|
||||
}
|
||||
bOk = 1;
|
||||
}
|
||||
rc = sqlite3_reset(pRange);
|
||||
|
||||
if( bOk ){
|
||||
int iIdx = 0;
|
||||
sqlite3_stmt *pUpdate1;
|
||||
sqlite3_stmt *pUpdate2;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL, &pUpdate2, 0);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
/* Loop through all %_segdir entries for segments in this index with
|
||||
** levels equal to or greater than iAbsLevel. As each entry is visited,
|
||||
** updated it to set (level = -1) and (idx = N), where N is 0 for the
|
||||
** oldest segment in the range, 1 for the next oldest, and so on.
|
||||
**
|
||||
** In other words, move all segments being promoted to level -1,
|
||||
** setting the "idx" fields as appropriate to keep them in the same
|
||||
** order. The contents of level -1 (which is never used, except
|
||||
** transiently here), will be moved back to level iAbsLevel below. */
|
||||
sqlite3_bind_int64(pRange, 1, iAbsLevel);
|
||||
while( SQLITE_ROW==sqlite3_step(pRange) ){
|
||||
sqlite3_bind_int(pUpdate1, 1, iIdx++);
|
||||
sqlite3_bind_int(pUpdate1, 2, sqlite3_column_int(pRange, 0));
|
||||
sqlite3_bind_int(pUpdate1, 3, sqlite3_column_int(pRange, 1));
|
||||
sqlite3_step(pUpdate1);
|
||||
rc = sqlite3_reset(pUpdate1);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_reset(pRange);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_reset(pRange);
|
||||
}
|
||||
|
||||
/* Move level -1 to level iAbsLevel */
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pUpdate2, 1, iAbsLevel);
|
||||
sqlite3_step(pUpdate2);
|
||||
rc = sqlite3_reset(pUpdate2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Merge all level iLevel segments in the database into a single
|
||||
** iLevel+1 segment. Or, if iLevel<0, merge all segments into a
|
||||
@@ -2966,6 +3157,7 @@ static int fts3SegmentMerge(
|
||||
Fts3SegFilter filter; /* Segment term filter condition */
|
||||
Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */
|
||||
int bIgnoreEmpty = 0; /* True to ignore empty segments */
|
||||
i64 iMaxLevel = 0; /* Max level number for this index/langid */
|
||||
|
||||
assert( iLevel==FTS3_SEGCURSOR_ALL
|
||||
|| iLevel==FTS3_SEGCURSOR_PENDING
|
||||
@@ -2977,6 +3169,11 @@ static int fts3SegmentMerge(
|
||||
rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr);
|
||||
if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished;
|
||||
|
||||
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
|
||||
rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iMaxLevel);
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
}
|
||||
|
||||
if( iLevel==FTS3_SEGCURSOR_ALL ){
|
||||
/* This call is to merge all segments in the database to a single
|
||||
** segment. The level of the new segment is equal to the numerically
|
||||
@@ -2986,21 +3183,21 @@ static int fts3SegmentMerge(
|
||||
rc = SQLITE_DONE;
|
||||
goto finished;
|
||||
}
|
||||
rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iNewLevel);
|
||||
iNewLevel = iMaxLevel;
|
||||
bIgnoreEmpty = 1;
|
||||
|
||||
}else if( iLevel==FTS3_SEGCURSOR_PENDING ){
|
||||
iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, 0);
|
||||
rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, 0, &iIdx);
|
||||
}else{
|
||||
/* This call is to merge all segments at level iLevel. find the next
|
||||
** available segment index at level iLevel+1. The call to
|
||||
** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to
|
||||
** a single iLevel+2 segment if necessary. */
|
||||
rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx);
|
||||
assert( FTS3_SEGCURSOR_PENDING==-1 );
|
||||
iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1);
|
||||
rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx);
|
||||
bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
|
||||
assert( csr.nSegment>0 );
|
||||
assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) );
|
||||
assert( iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL) );
|
||||
@@ -3017,7 +3214,7 @@ static int fts3SegmentMerge(
|
||||
csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
assert( pWriter );
|
||||
assert( pWriter || bIgnoreEmpty );
|
||||
|
||||
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
|
||||
rc = fts3DeleteSegdir(
|
||||
@@ -3025,7 +3222,14 @@ static int fts3SegmentMerge(
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
}
|
||||
rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
|
||||
if( pWriter ){
|
||||
rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iLevel==FTS3_SEGCURSOR_PENDING || iNewLevel<iMaxLevel ){
|
||||
rc = fts3PromoteSegments(p, iNewLevel, pWriter->nLeafData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finished:
|
||||
fts3SegWriterFree(pWriter);
|
||||
@@ -3035,7 +3239,7 @@ static int fts3SegmentMerge(
|
||||
|
||||
|
||||
/*
|
||||
** Flush the contents of pendingTerms to level 0 segments.
|
||||
** Flush the contents of pendingTerms to level 0 segments.
|
||||
*/
|
||||
int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
|
||||
int rc = SQLITE_OK;
|
||||
@@ -3051,14 +3255,19 @@ int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
|
||||
** estimate the number of leaf blocks of content to be written
|
||||
*/
|
||||
if( rc==SQLITE_OK && p->bHasStat
|
||||
&& p->bAutoincrmerge==0xff && p->nLeafAdd>0
|
||||
&& p->nAutoincrmerge==0xff && p->nLeafAdd>0
|
||||
){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
|
||||
rc = sqlite3_step(pStmt);
|
||||
p->bAutoincrmerge = (rc==SQLITE_ROW && sqlite3_column_int(pStmt, 0));
|
||||
if( rc==SQLITE_ROW ){
|
||||
p->nAutoincrmerge = sqlite3_column_int(pStmt, 0);
|
||||
if( p->nAutoincrmerge==1 ) p->nAutoincrmerge = 8;
|
||||
}else if( rc==SQLITE_DONE ){
|
||||
p->nAutoincrmerge = 0;
|
||||
}
|
||||
rc = sqlite3_reset(pStmt);
|
||||
}
|
||||
}
|
||||
@@ -3426,6 +3635,8 @@ struct IncrmergeWriter {
|
||||
int iIdx; /* Index of *output* segment in iAbsLevel+1 */
|
||||
sqlite3_int64 iStart; /* Block number of first allocated block */
|
||||
sqlite3_int64 iEnd; /* Block number of last allocated block */
|
||||
sqlite3_int64 nLeafData; /* Bytes of leaf page data so far */
|
||||
u8 bNoLeafData; /* If true, store 0 for segment size */
|
||||
NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT];
|
||||
};
|
||||
|
||||
@@ -3764,8 +3975,8 @@ static int fts3IncrmergeAppend(
|
||||
nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist;
|
||||
}
|
||||
|
||||
pWriter->nLeafData += nSpace;
|
||||
blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pLeaf->block.n==0 ){
|
||||
pLeaf->block.n = 1;
|
||||
@@ -3864,6 +4075,7 @@ static void fts3IncrmergeRelease(
|
||||
pWriter->iStart, /* start_block */
|
||||
pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */
|
||||
pWriter->iEnd, /* end_block */
|
||||
(pWriter->bNoLeafData==0 ? pWriter->nLeafData : 0), /* end_block */
|
||||
pRoot->block.a, pRoot->block.n /* root */
|
||||
);
|
||||
}
|
||||
@@ -3965,7 +4177,11 @@ static int fts3IncrmergeLoad(
|
||||
if( sqlite3_step(pSelect)==SQLITE_ROW ){
|
||||
iStart = sqlite3_column_int64(pSelect, 1);
|
||||
iLeafEnd = sqlite3_column_int64(pSelect, 2);
|
||||
iEnd = sqlite3_column_int64(pSelect, 3);
|
||||
fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData);
|
||||
if( pWriter->nLeafData<0 ){
|
||||
pWriter->nLeafData = pWriter->nLeafData * -1;
|
||||
}
|
||||
pWriter->bNoLeafData = (pWriter->nLeafData==0);
|
||||
nRoot = sqlite3_column_bytes(pSelect, 4);
|
||||
aRoot = sqlite3_column_blob(pSelect, 4);
|
||||
}else{
|
||||
@@ -4566,11 +4782,11 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
|
||||
/*
|
||||
** Attempt an incremental merge that writes nMerge leaf blocks.
|
||||
**
|
||||
** Incremental merges happen nMin segments at a time. The two
|
||||
** segments to be merged are the nMin oldest segments (the ones with
|
||||
** the smallest indexes) in the highest level that contains at least
|
||||
** nMin segments. Multiple merges might occur in an attempt to write the
|
||||
** quota of nMerge leaf blocks.
|
||||
** Incremental merges happen nMin segments at a time. The segments
|
||||
** to be merged are the nMin oldest segments (the ones with the smallest
|
||||
** values for the _segdir.idx field) in the highest level that contains
|
||||
** at least nMin segments. Multiple merges might occur in an attempt to
|
||||
** write the quota of nMerge leaf blocks.
|
||||
*/
|
||||
int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
int rc; /* Return code */
|
||||
@@ -4595,6 +4811,7 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex;
|
||||
sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */
|
||||
int bUseHint = 0; /* True if attempting to append */
|
||||
int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */
|
||||
|
||||
/* Search the %_segdir table for the absolute level with the smallest
|
||||
** relative level number that contains at least nMin segments, if any.
|
||||
@@ -4648,6 +4865,19 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
** to start work on some other level. */
|
||||
memset(pWriter, 0, nAlloc);
|
||||
pFilter->flags = FTS3_SEGMENT_REQUIRE_POS;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx);
|
||||
assert( bUseHint==1 || bUseHint==0 );
|
||||
if( iIdx==0 || (bUseHint && iIdx==1) ){
|
||||
int bIgnore = 0;
|
||||
rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore);
|
||||
if( bIgnore ){
|
||||
pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr);
|
||||
}
|
||||
@@ -4655,16 +4885,12 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
&& SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter))
|
||||
&& SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr))
|
||||
){
|
||||
int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */
|
||||
rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( bUseHint && iIdx>0 ){
|
||||
const char *zKey = pCsr->zTerm;
|
||||
int nKey = pCsr->nTerm;
|
||||
rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter);
|
||||
}else{
|
||||
rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter);
|
||||
}
|
||||
if( bUseHint && iIdx>0 ){
|
||||
const char *zKey = pCsr->zTerm;
|
||||
int nKey = pCsr->nTerm;
|
||||
rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter);
|
||||
}else{
|
||||
rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && pWriter->nLeafEst ){
|
||||
@@ -4686,7 +4912,13 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
}
|
||||
}
|
||||
|
||||
if( nSeg!=0 ){
|
||||
pWriter->nLeafData = pWriter->nLeafData * -1;
|
||||
}
|
||||
fts3IncrmergeRelease(p, pWriter, &rc);
|
||||
if( nSeg==0 && pWriter->bNoLeafData==0 ){
|
||||
fts3PromoteSegments(p, iAbsLevel+1, pWriter->nLeafData);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3Fts3SegReaderFinish(pCsr);
|
||||
@@ -4773,7 +5005,10 @@ static int fts3DoAutoincrmerge(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
p->bAutoincrmerge = fts3Getint(&zParam)!=0;
|
||||
p->nAutoincrmerge = fts3Getint(&zParam);
|
||||
if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){
|
||||
p->nAutoincrmerge = 8;
|
||||
}
|
||||
if( !p->bHasStat ){
|
||||
assert( p->bFts4==0 );
|
||||
sqlite3Fts3CreateStatTable(&rc, p);
|
||||
@@ -4782,7 +5017,7 @@ static int fts3DoAutoincrmerge(
|
||||
rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
|
||||
if( rc ) return rc;
|
||||
sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
|
||||
sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge);
|
||||
sqlite3_bind_int(pStmt, 2, p->nAutoincrmerge);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_reset(pStmt);
|
||||
return rc;
|
||||
|
||||
+762
-734
File diff suppressed because it is too large
Load Diff
+11
-8
@@ -120,12 +120,13 @@ proc execsql_intout {sql} {
|
||||
# Test that it is possible to open an existing database that contains
|
||||
# r-tree tables.
|
||||
#
|
||||
do_test rtree-1.4.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
|
||||
INSERT INTO t1 VALUES(1, 5.0, 10.0);
|
||||
INSERT INTO t1 VALUES(2, 15.0, 20.0);
|
||||
}
|
||||
do_execsql_test rtree-1.4.1a {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
|
||||
INSERT INTO t1 VALUES(1, 5.0, 10.0);
|
||||
SELECT substr(hex(data),1,40) FROM t1_node;
|
||||
} {00000001000000000000000140A0000041200000}
|
||||
do_execsql_test rtree-1.4.1b {
|
||||
INSERT INTO t1 VALUES(2, 15.0, 20.0);
|
||||
} {}
|
||||
do_test rtree-1.4.2 {
|
||||
db close
|
||||
@@ -435,16 +436,18 @@ do_test rtree-11.2 {
|
||||
# Test on-conflict clause handling.
|
||||
#
|
||||
db_delete_and_reopen
|
||||
do_execsql_test 12.0 {
|
||||
do_execsql_test 12.0.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree_i32(idx, x1, x2, y1, y2);
|
||||
INSERT INTO t1 VALUES(1, 1, 2, 3, 4);
|
||||
SELECT substr(hex(data),1,56) FROM t1_node;
|
||||
} {00000001000000000000000100000001000000020000000300000004}
|
||||
do_execsql_test 12.0.2 {
|
||||
INSERT INTO t1 VALUES(2, 2, 3, 4, 5);
|
||||
INSERT INTO t1 VALUES(3, 3, 4, 5, 6);
|
||||
|
||||
CREATE TABLE source(idx, x1, x2, y1, y2);
|
||||
INSERT INTO source VALUES(5, 8, 8, 8, 8);
|
||||
INSERT INTO source VALUES(2, 7, 7, 7, 7);
|
||||
|
||||
}
|
||||
db_save_and_close
|
||||
foreach {tn sql_template testdata} {
|
||||
|
||||
@@ -57,31 +57,31 @@ do_test rtree6-1.1 {
|
||||
|
||||
do_test rtree6-1.2 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1>10}
|
||||
} {Ea}
|
||||
} {E0}
|
||||
|
||||
do_test rtree6-1.3 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_test rtree6-1.4 {
|
||||
rtree_strategy {SELECT * FROM t1,t2 WHERE k=ii AND x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_test rtree6-1.5 {
|
||||
rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_eqp_test rtree6.2.1 {
|
||||
SELECT * FROM t1,t2 WHERE k=+ii AND x1<10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0}
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
do_eqp_test rtree6.2.2 {
|
||||
SELECT * FROM t1,t2 WHERE k=ii AND x1<10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0}
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ do_eqp_test rtree6.2.3 {
|
||||
do_eqp_test rtree6.2.4 {
|
||||
SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1}
|
||||
0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ do_test rtree6.3.2 {
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5
|
||||
}
|
||||
} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa}
|
||||
} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0}
|
||||
do_test rtree6.3.3 {
|
||||
rtree_strategy {
|
||||
SELECT * FROM t3 WHERE
|
||||
@@ -137,7 +137,7 @@ do_test rtree6.3.3 {
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5
|
||||
}
|
||||
} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa}
|
||||
} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0}
|
||||
|
||||
do_execsql_test rtree6-3.4 {
|
||||
SELECT * FROM t3 WHERE x1>0.5 AND x1>0.8 AND x1>1.1
|
||||
|
||||
@@ -41,7 +41,7 @@ ifcapable rtree_int_only {
|
||||
INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
|
||||
SELECT rtreenode(2, data) FROM t1_node;
|
||||
}
|
||||
} {{{1073741824 0.000000 0.000000 100.000000 100.000000} {2147483646 0.000000 0.000000 200.000000 200.000000} {4294967296 0.000000 0.000000 300.000000 300.000000} {8589934592 20.000000 20.000000 150.000000 150.000000} {9223372036854775807 150.000000 150.000000 400.000000 400.000000}}}
|
||||
} {{{1073741824 0 0 100 100} {2147483646 0 0 200 200} {4294967296 0 0 300 300} {8589934592 20 20 150 150} {9223372036854775807 150 150 400 400}}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -29,7 +29,7 @@ do_eqp_test 1.1 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 1 {SCAN TABLE t}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.2 {
|
||||
@@ -37,7 +37,7 @@ do_eqp_test 1.2 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.3 {
|
||||
@@ -45,7 +45,7 @@ do_eqp_test 1.3 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.5 {
|
||||
@@ -82,7 +82,7 @@ do_eqp_test 2.1 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 1 {SCAN TABLE t}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.2 {
|
||||
@@ -90,7 +90,7 @@ do_eqp_test 2.2 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.3 {
|
||||
@@ -98,7 +98,7 @@ do_eqp_test 2.3 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.5 {
|
||||
@@ -271,4 +271,3 @@ ifcapable rtree {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# 2010 August 28
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file contains tests for the r-tree module. Specifically, it tests
|
||||
# that new-style custom r-tree queries (geometry callbacks) work.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !rtree { finish_test ; return }
|
||||
ifcapable rtree_int_only { finish_test; return }
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the example 2d "circle" geometry callback.
|
||||
#
|
||||
register_circle_geom db
|
||||
|
||||
do_execsql_test rtreeE-1.1 {
|
||||
PRAGMA page_size=512;
|
||||
CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1);
|
||||
|
||||
/* A tight pattern of small boxes near 0,0 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT x+5*y, x, x+2, y, y+2 FROM x, y;
|
||||
|
||||
/* A looser pattern of small boxes near 100, 0 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT 100+x+5*y, x*3+100, x*3+102, y*3, y*3+2 FROM x, y;
|
||||
|
||||
/* A looser pattern of larger boxes near 0, 200 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT 200+x+5*y, x*7, x*7+15, y*7+200, y*7+215 FROM x, y;
|
||||
} {}
|
||||
|
||||
# Queries against each of the three clusters */
|
||||
do_execsql_test rtreeE-1.1 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 0.0, 50.0, 3) ORDER BY id;
|
||||
} {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24}
|
||||
do_execsql_test rtreeE-1.2 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(100.0, 0.0, 50.0, 3) ORDER BY id;
|
||||
} {100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124}
|
||||
do_execsql_test rtreeE-1.3 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 200.0, 50.0, 3) ORDER BY id;
|
||||
} {200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224}
|
||||
|
||||
# The Qcircle geometry function gives a lower score to larger leaf-nodes.
|
||||
# This causes the 200s to sort before the 100s and the 0s to sort before
|
||||
# last.
|
||||
#
|
||||
do_execsql_test rtreeE-1.4 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,3) AND id%100==0
|
||||
} {200 100 0}
|
||||
|
||||
# Exclude odd rowids on a depth-first search
|
||||
do_execsql_test rtreeE-1.5 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,4) ORDER BY +id
|
||||
} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224}
|
||||
|
||||
# Exclude odd rowids on a breadth-first search.
|
||||
do_execsql_test rtreeE-1.6 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,5) ORDER BY +id
|
||||
} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224}
|
||||
|
||||
# Construct a large 2-D RTree with thousands of random entries.
|
||||
#
|
||||
do_test rtreeE-2.1 {
|
||||
db eval {
|
||||
CREATE TABLE t2(id,x0,x1,y0,y1);
|
||||
CREATE VIRTUAL TABLE rt2 USING rtree(id,x0,x1,y0,y1);
|
||||
BEGIN;
|
||||
}
|
||||
expr srand(0)
|
||||
for {set i 1} {$i<=10000} {incr i} {
|
||||
set dx [expr {int(rand()*40)+1}]
|
||||
set dy [expr {int(rand()*40)+1}]
|
||||
set x0 [expr {int(rand()*(10000 - $dx))}]
|
||||
set x1 [expr {$x0+$dx}]
|
||||
set y0 [expr {int(rand()*(10000 - $dy))}]
|
||||
set y1 [expr {$y0+$dy}]
|
||||
set id [expr {$i+10000}]
|
||||
db eval {INSERT INTO t2 VALUES($id,$x0,$x1,$y0,$y1)}
|
||||
}
|
||||
db eval {
|
||||
INSERT INTO rt2 SELECT * FROM t2;
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
|
||||
for {set i 1} {$i<=200} {incr i} {
|
||||
set dx [expr {int(rand()*100)}]
|
||||
set dy [expr {int(rand()*100)}]
|
||||
set x0 [expr {int(rand()*(10000 - $dx))}]
|
||||
set x1 [expr {$x0+$dx}]
|
||||
set y0 [expr {int(rand()*(10000 - $dy))}]
|
||||
set y1 [expr {$y0+$dy}]
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=$x0 AND x0<=$x1 AND y1>=$y0 AND y0<=$y1 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.2.$i {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ORDER BY id
|
||||
} $ans
|
||||
}
|
||||
|
||||
# Run query that have very deep priority queues
|
||||
#
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=5000 AND y1>=0 AND y0<=5000 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.3 {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,5000,0,5000) ORDER BY id
|
||||
} $ans
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=10000 AND y1>=0 AND y0<=10000 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.4 {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,10000,0,10000) ORDER BY id
|
||||
} $ans
|
||||
|
||||
finish_test
|
||||
@@ -21,6 +21,16 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
|
||||
typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
|
||||
|
||||
/* The double-precision datatype used by RTree depends on the
|
||||
** SQLITE_RTREE_INT_ONLY compile-time option.
|
||||
*/
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
typedef sqlite3_int64 sqlite3_rtree_dbl;
|
||||
#else
|
||||
typedef double sqlite3_rtree_dbl;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Register a geometry callback named zGeom that can be used as part of an
|
||||
@@ -31,11 +41,7 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
|
||||
int sqlite3_rtree_geometry_callback(
|
||||
sqlite3 *db,
|
||||
const char *zGeom,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
|
||||
#else
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
|
||||
#endif
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
|
||||
void *pContext
|
||||
);
|
||||
|
||||
@@ -47,11 +53,60 @@ int sqlite3_rtree_geometry_callback(
|
||||
struct sqlite3_rtree_geometry {
|
||||
void *pContext; /* Copy of pContext passed to s_r_g_c() */
|
||||
int nParam; /* Size of array aParam[] */
|
||||
double *aParam; /* Parameters passed to SQL geom function */
|
||||
sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */
|
||||
void *pUser; /* Callback implementation user data */
|
||||
void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */
|
||||
};
|
||||
|
||||
/*
|
||||
** Register a 2nd-generation geometry callback named zScore that can be
|
||||
** used as part of an R-Tree geometry query as follows:
|
||||
**
|
||||
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
|
||||
*/
|
||||
int sqlite3_rtree_query_callback(
|
||||
sqlite3 *db,
|
||||
const char *zQueryFunc,
|
||||
int (*xQueryFunc)(sqlite3_rtree_query_info*),
|
||||
void *pContext,
|
||||
void (*xDestructor)(void*)
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
** A pointer to a structure of the following type is passed as the
|
||||
** argument to scored geometry callback registered using
|
||||
** sqlite3_rtree_query_callback().
|
||||
**
|
||||
** Note that the first 5 fields of this structure are identical to
|
||||
** sqlite3_rtree_geometry. This structure is a subclass of
|
||||
** sqlite3_rtree_geometry.
|
||||
*/
|
||||
struct sqlite3_rtree_query_info {
|
||||
void *pContext; /* pContext from when function registered */
|
||||
int nParam; /* Number of function parameters */
|
||||
sqlite3_rtree_dbl *aParam; /* value of function parameters */
|
||||
void *pUser; /* callback can use this, if desired */
|
||||
void (*xDelUser)(void*); /* function to free pUser */
|
||||
sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */
|
||||
unsigned int *anQueue; /* Number of pending entries in the queue */
|
||||
int nCoord; /* Number of coordinates */
|
||||
int iLevel; /* Level of current node or entry */
|
||||
int mxLevel; /* The largest iLevel value in the tree */
|
||||
sqlite3_int64 iRowid; /* Rowid for current entry */
|
||||
sqlite3_rtree_dbl rParentScore; /* Score of parent node */
|
||||
int eParentWithin; /* Visibility of parent node */
|
||||
int eWithin; /* OUT: Visiblity */
|
||||
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin.
|
||||
*/
|
||||
#define NOT_WITHIN 0 /* Object completely outside of query region */
|
||||
#define PARTLY_WITHIN 1 /* Object partially overlaps query region */
|
||||
#define FULLY_WITHIN 2 /* Object fully contained within query region */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
|
||||
@@ -121,8 +121,10 @@ SRC = \
|
||||
$(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 \
|
||||
$(TOP)/src/os_win.h \
|
||||
$(TOP)/src/pager.c \
|
||||
$(TOP)/src/pager.h \
|
||||
$(TOP)/src/parse.y \
|
||||
@@ -208,6 +210,7 @@ SRC += \
|
||||
$(TOP)/ext/icu/sqliteicu.h \
|
||||
$(TOP)/ext/icu/icu.c
|
||||
SRC += \
|
||||
$(TOP)/ext/rtree/sqlite3rtree.h \
|
||||
$(TOP)/ext/rtree/rtree.h \
|
||||
$(TOP)/ext/rtree/rtree.c
|
||||
|
||||
@@ -339,6 +342,8 @@ HDR = \
|
||||
opcodes.h \
|
||||
$(TOP)/src/os.h \
|
||||
$(TOP)/src/os_common.h \
|
||||
$(TOP)/src/os_setup.h \
|
||||
$(TOP)/src/os_win.h \
|
||||
$(TOP)/src/pager.h \
|
||||
$(TOP)/src/pcache.h \
|
||||
parse.h \
|
||||
@@ -476,7 +481,7 @@ parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk
|
||||
mv parse.h parse.h.temp
|
||||
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
|
||||
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
|
||||
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
|
||||
|
||||
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
C Merge\schanges\sto\sthe\squery\splanner\sthat\sstrive\sto\sensure\sthat\sany\sindex\s\nusage\sthat\sis\sa\sproper\ssubset\sof\ssome\sother\sindex\susage\salways\shas\sa\sslightly\nhigher\scost.
|
||||
D 2014-04-04T18:20:35.620
|
||||
C Add\sextra\schecking\sof\sthe\sdatabase\sextended\serror\scode.
|
||||
D 2014-05-30T16:54:09.869
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.in dd2b1aba364ff9b05de41086f74407f285c57670
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc fdacba6fb574868c71fde6db6b77789a383a4c19
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F Makefile.msc 52911c6bfeaf9b40f47ef4615ab66d98ab0f2b3d
|
||||
F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0
|
||||
F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
|
||||
F VERSION 9f823c026c6a32fc5f84d212a8aae0a221dba45c
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -78,11 +78,11 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 41b1920b9a8657963f09cb93b208c2671c5568db
|
||||
F ext/fts3/fts3.c 20bc65862cfcea0a39bb64a819f8fe92a8e144c1
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h bdeb9015405e8facffb8fc7e09174521a2a780f4
|
||||
F ext/fts3/fts3Int.h 16cddf2d7b0e5f3681615ae1d8ca0e45fca44918
|
||||
F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
|
||||
F ext/fts3/fts3_expr.c 5165c365cb5a035f5be8bb296f7aa3211d43e4ac
|
||||
F ext/fts3/fts3_expr.c 351395fad6fcb16ecfc61db0861008a70101330c
|
||||
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
|
||||
@@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9
|
||||
F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d
|
||||
F ext/fts3/fts3_write.c 74c00329006c3ed6325ba4e5ab7c9b5fc99c8934
|
||||
F ext/fts3/fts3_write.c 5ee9d894da74a5d15a3c317414fb8c84f1694fa4
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
|
||||
@@ -120,30 +120,31 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 2d9f95da404d850474e628c720c5ce15d29b47de
|
||||
F ext/rtree/rtree.c 6f70db93e0e42c369325c5cddcf2024c5a87ca43
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290
|
||||
F ext/rtree/rtree1.test e2da4aaa426918d27122d1a1066c6ecf8409a514
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
|
||||
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
|
||||
F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e
|
||||
F ext/rtree/rtree6.test fe0bd377a21c68ce2826129d14354c884cb1f354
|
||||
F ext/rtree/rtree6.test 756585abc51727fec97c77852476445c10c0ee95
|
||||
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
|
||||
F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
|
||||
F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34
|
||||
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
|
||||
F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2
|
||||
F ext/rtree/rtreeC.test 16d7aa86ecb6a876d2a38cf590a1471a41b3a46d
|
||||
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e
|
||||
F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06
|
||||
F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca
|
||||
F ext/rtree/rtreeE.test 388c1c8602c3ce55c15f03b509e9cf545fb7c41f
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765
|
||||
F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt f439556c5ce01ced70987e5ee86549a45165d9ff
|
||||
F main.mk 3ae543fa446525c1dec55f58de67f41b78651812
|
||||
F main.mk cfa185eed4e0f7e9d28a2e3167cecaa9d6cb39f3
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@@ -157,36 +158,36 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 5d99edbac5bc416032772b723ee30182ee6e5de0
|
||||
F src/analyze.c 663e0b291d27eb03c9fd6b421e2d61ba348a2389
|
||||
F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1
|
||||
F src/analyze.c e8c8a9d20beb2ad156321330e8f4fea002d8deee
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c a59a199f21338ae1847d69f5db87c3e8ef1b1578
|
||||
F src/btree.h 232836cb51753f2e96aa8ce0f052c6df850f76ba
|
||||
F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4
|
||||
F src/build.c 0d50ef95aad63f4c4fc47f3fa2670d4557c45db0
|
||||
F src/btree.c 70c60a3807b2072982f184d9614e020d2953f89c
|
||||
F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a
|
||||
F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
|
||||
F src/build.c 927e39b6aaf872c7b28f154f6acfeb9a05a72442
|
||||
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c cdd57149543bb28304d8f717c243f2a86b1fc280
|
||||
F src/expr.c da2b3cb41081af6b56e95e7c9e95949564ce2e21
|
||||
F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf
|
||||
F src/expr.c 4f9e497c66e2f25a4d139357a778c84d5713207c
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
|
||||
F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
|
||||
F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
|
||||
F src/fkey.c a549cff9fe8b736cdae21650ea0af6de29b77619
|
||||
F src/func.c 2e16316ec3a6365a0dc3e553c586f91b20f7f6c8
|
||||
F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4
|
||||
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c d8bb30535c8c0785876025a4a07f9074640a15d1
|
||||
F src/insert.c a038daeadfb818aaadafa854f40f5623b6929d84
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
|
||||
F src/main.c 691b25754bef596108fe60ff1bcbe8445369c9db
|
||||
F src/main.c 40d0837e5d0597eadc47c3acc2fc95bdbd9250b8
|
||||
F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
|
||||
@@ -198,37 +199,39 @@ F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
|
||||
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
|
||||
F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553
|
||||
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc
|
||||
F src/mutex_w32.c 6108c88e1cb38d8fbb3534b170793815cbedbf97
|
||||
F src/mutex_w32.c 9bcab6e699fdb20eae784237c36b299830fb3316
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c ae4b5240af4619d711301d7992396e182585269f
|
||||
F src/os_win.c e71678ac927d0a0fb11d993db20a9748eabf808e
|
||||
F src/pager.c ab62a24218d87dda1be641f6c5ad291bff78fd94
|
||||
F src/os_win.c 8dbf6c11780fe2eb96c1f289e664d0c7b2911d37
|
||||
F src/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25
|
||||
F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||
F src/pragma.c 10f169b9650f0930a7a6df67e1387a4c2c449f38
|
||||
F src/pragma.c 810ef31ccfaa233201dcf100637a9777cc24e897
|
||||
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
|
||||
F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 269c3e31a450fce642a10569221a49180348c88e
|
||||
F src/shell.c 5260f2ada8dd06e9f5ae0a448c8c01e7a75dd881
|
||||
F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80
|
||||
F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
|
||||
F src/select.c 7df17ec5506c2427576d412bee0e6ea740e12563
|
||||
F src/shell.c bfac06fb15f3cd0d447e2e72ab3a283fac301813
|
||||
F src/sqlite.h.in a98eb3e8c86c934ea6f5bcfc6b69653dde2f4ed4
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h cc9582a91b2910404ccda7b7e198815ea0f75948
|
||||
F src/sqliteInt.h fccdc735c27b3dc12322fec7cdad8bc76be8d00b
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd
|
||||
F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test1.c 4edf8810c86d77ae7ac6d56d563965a9beeea2ce
|
||||
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
F src/test5.c 5a34feec76d9b3a86aab30fd4f6cc9c48cbab4c1
|
||||
@@ -239,8 +242,8 @@ F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
|
||||
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
|
||||
F src/test_config.c 0336e0bdbe541b4af89d7e3dd0656e8e6b51e585
|
||||
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
|
||||
F src/test_config.c dabaa32868974e1ae39770cc17d7e066a9c38e6d
|
||||
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
|
||||
@@ -256,11 +259,11 @@ F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8
|
||||
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1
|
||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||
F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25
|
||||
F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
|
||||
F src/test_osinst.c 3d0340bc31a9f3d8a3547e0272373e80f78dde25
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
F src/test_quota.c 30c64f0ef84734f2231a686df41ed882b0c59bc0
|
||||
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
|
||||
F src/test_rtree.c f3d1d12538dccb75fd916e3fa58f250edbdd3b47
|
||||
F src/test_quota.c 65f6348fec0f2b3020c907247fb47556b214abb9
|
||||
F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d
|
||||
F src/test_rtree.c fdd8d29ca5165c7857987a2ba263fac5c69e231f
|
||||
F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6
|
||||
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
|
||||
@@ -269,49 +272,49 @@ F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
|
||||
F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
|
||||
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
|
||||
F src/test_vfs.c f84075a388527892ff184988f43b69ce69b8083c
|
||||
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
|
||||
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
|
||||
F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115
|
||||
F src/update.c 01564b3c430f6c7b0a35afaf7aba7987206fa3a5
|
||||
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
|
||||
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
|
||||
F src/util.c 049fe1d3c0e2209c1bee107aec2fcff6285f909f
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c e811a0081149fb90db367026d154cd7efb3c7098
|
||||
F src/vdbe.c 9bfe6becfc094382ae213656fbe511055ad83a54
|
||||
F src/vdbe.h 394464909ed682334aa3d5831aae0c2fe2abef94
|
||||
F src/vdbeInt.h e6d83e5bfd62fc6685ba1ed6153f7099f82de9f7
|
||||
F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
|
||||
F src/vdbeaux.c 1153175fb57a8454e1c8cf79b59b7bf92b26779d
|
||||
F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
|
||||
F src/vdbeaux.c e493f38758c4b8f4ca2007cf6a700bd405d192f3
|
||||
F src/vdbeblob.c 9205ce9d3b064d9600f8418a897fc88b5687d9ac
|
||||
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
|
||||
F src/vdbesort.c 4abb7c0f8f19b7d7d82f4558d5da1a30fdf9ea38
|
||||
F src/vdbesort.c 44441d73b08b3a638dcdb725afffb87c6574ad27
|
||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c 70eb10da08cebbd6a576ced18edb7c8f79d41597
|
||||
F src/whereInt.h 2564055b440e44ebec8b47f237bbccae6719b7af
|
||||
F src/where.c b3be5eb4193b6327c4a02fe91411df503fe770e8
|
||||
F src/whereInt.h 6804c2e5010378568c2bb1350477537755296a46
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
||||
F test/alter.test e88dfa77e020c2b48e52a8020c70171ab828e079
|
||||
F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2
|
||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
|
||||
F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
|
||||
F test/analyze3.test 412f690dfe95b337475e3e78a84a85d25f6f125d
|
||||
F test/analyze3.test bf41f0f680dd1e0d44eed5e769531e93a5320275
|
||||
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
|
||||
F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
|
||||
F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c
|
||||
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
|
||||
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
|
||||
F test/analyze9.test e072a5172d55afcba98d6ca6a219ce8878c2f5c9
|
||||
F test/analyze9.test 623e02a99a78fa12fe5def2fd559032d5d887e0f
|
||||
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
|
||||
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
@@ -329,11 +332,11 @@ F test/auth.test 5bdf154eb28c0e4bbc0473f335858c0d96171768
|
||||
F test/auth2.test c3b415b76c033bedb81292118fb7c01f5f10cbcd
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7
|
||||
F test/autoindex1.test d4dfe14001dfcb74cfbd7107f45a79fc1ab6183e
|
||||
F test/autoindex1.test 762ff3f8e25d852aae55c6462ca166a80c0cde61
|
||||
F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
F test/backcompat.test 5f8ad58b3eaebc78cd2c66c65476a42e6f32b2ad
|
||||
F test/backcompat.test 19a1f337c68419b020a7481dd272a472c4ad8ef4
|
||||
F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62
|
||||
F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf
|
||||
F test/backup4.test 2a2e4a64388090b152de753fd9e123f28f6a3bd4
|
||||
@@ -406,6 +409,7 @@ F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
|
||||
F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb
|
||||
F test/corruptI.test b3e4203d420490fc3d3062711597bc1dea06a789
|
||||
F test/cost.test 04842adec34311d70c3f3c5fd698b22be54138fd
|
||||
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
|
||||
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
|
||||
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
@@ -433,12 +437,12 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
||||
F test/e_createtable.test ed82efcedc4b3656b27a5fcd12335cdb7e20eeee
|
||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
|
||||
F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
|
||||
F test/e_expr.test 5c71d183fbf519a4769fd2e2124afdc70b5b1f42
|
||||
F test/e_fkey.test 630597377549af579d34faaf64c6959a5a68ef76
|
||||
F test/e_fkey.test a1783fe1f759e1990e6a11adfcf0702dac4d0707
|
||||
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
|
||||
F test/e_insert.test 1e44f84d2abe44d66e4fbf198be4b20e3cc724a0
|
||||
F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589
|
||||
@@ -452,7 +456,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
|
||||
F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40
|
||||
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
|
||||
F test/eqp.test 57c6c604c2807fb5531731c5323133453c24afac
|
||||
F test/eqp.test 85873fa5816c48915c82c4e74cb5c35a5b48160f
|
||||
F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75
|
||||
@@ -535,15 +539,16 @@ F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de
|
||||
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
|
||||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test 597b0b76e41f0d672e2731c4d7b631d628efd13f
|
||||
F test/fts3d.test 95c17d1b67b33a5eac0bf5a0d11116a0c0ac7a3a
|
||||
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
|
||||
F test/fts3defer2.test a3b6cbeabaf28c9398652a4d101ea224d9358479
|
||||
F test/fts3defer2.test e880e3b65bdf999f4746cdaefa65f14a98b9b724
|
||||
F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd
|
||||
F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
|
||||
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
||||
F test/fts3expr.test 06f1a96facc8f3e4b1ad5cc001dc5c8e83e68b9f
|
||||
F test/fts3expr.test 3401d47b229c4504424caf362cc4ff704cad4162
|
||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3expr3.test 9e91b8edbcb197bf2e92161aa7696446d96dce5f
|
||||
F test/fts3expr4.test 0713d94ab951ed88a8c3629a4889a48c55c4067c
|
||||
F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660
|
||||
F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887
|
||||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
@@ -565,22 +570,24 @@ F test/fts4aa.test 0c3152322c7f0b548cc942ad763eaba0da87ccca
|
||||
F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8
|
||||
F test/fts4content.test 2e7252557d6d24afa101d9ba1de710d6140e6d06
|
||||
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
|
||||
F test/fts4growth.test df10fde9f47cf5c71861e63fd8efcd573c4f7e53
|
||||
F test/fts4growth2.test 2f063be1902a73cd087355837c52fed42ac11a5d
|
||||
F test/fts4incr.test 361960ed3550e781f3f313e17e2182ef9cefc0e9
|
||||
F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7
|
||||
F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
|
||||
F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
|
||||
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
|
||||
F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b
|
||||
F test/fts4noti.test 9695c7c6c32480ea9fc20a2b38ed1de0640bcaec
|
||||
F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test a21814945d32137412b553d98ad2107f9b2173a9
|
||||
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a
|
||||
F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
|
||||
F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4
|
||||
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
|
||||
F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
|
||||
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
|
||||
F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
|
||||
F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
@@ -610,12 +617,12 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 55a90cff99834305e8141df7afaef39674b57062
|
||||
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
|
||||
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
|
||||
F test/index6.test 936979c3a1e87b81feaed2d00505665bf142d764
|
||||
F test/index6.test fb370966ac3cd0989053dd5385757b5c3e24ab6a
|
||||
F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf
|
||||
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test acf909b067b838eb55338d619e800e148c17f1f5
|
||||
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
|
||||
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
|
||||
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
|
||||
F test/insert4.test 4791662c50518bdd37d394cae9a7a8014e845bb3
|
||||
@@ -693,7 +700,7 @@ F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
|
||||
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
|
||||
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
|
||||
F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef
|
||||
F test/misc1.test 441a0fafc7087f841db09fbfca54e7aea9f5a84c
|
||||
F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417
|
||||
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
|
||||
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
|
||||
F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
|
||||
@@ -711,6 +718,7 @@ F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
|
||||
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a
|
||||
F test/nolock.test 0540dd96f39b8876e3ffdd8814fad0ea425efeee
|
||||
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test ce23eb522c9e1fff6443f96376fe67872202061c
|
||||
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
|
||||
@@ -722,8 +730,9 @@ F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6
|
||||
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
||||
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
||||
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
|
||||
F test/orderby5.test 2490183fef54417209d1df253633a605d46bd350
|
||||
F test/orderby5.test 8f08a54836d21fb7c70245360751aedd1c2286fb
|
||||
F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859
|
||||
F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
|
||||
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
|
||||
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
|
||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||
@@ -737,7 +746,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
|
||||
F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04
|
||||
F test/permutations.test d8946218493c77806ec1029df473d8ed4ad9aef6
|
||||
F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0
|
||||
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
@@ -752,7 +761,7 @@ F test/quota2.test 7dc12e08b11cbc4c16c9ba2aa2e040ea8d8ab4b8
|
||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
|
||||
F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d
|
||||
F test/rdonly.test dd30a4858d8e0fbad2304c2bd74a33d4df36412a
|
||||
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
|
||||
@@ -786,7 +795,7 @@ F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2
|
||||
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test 77adaffe9704cb80e301ebaeff4b107b58d435c5
|
||||
F test/selectA.test 64b88a80271c1710966e50e633380696b60a12a4
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
|
||||
F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394
|
||||
@@ -808,12 +817,13 @@ F test/shell1.test f2a1d471e5cd2b42f7a65b166dc1ace2b8d11583
|
||||
F test/shell2.test c57da3a381c099b02c813ba156298d5c2f5c93a3
|
||||
F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
|
||||
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
|
||||
F test/shell5.test bb755ea9144b8078a752fc56223582627070b5f1
|
||||
F test/shell5.test fa5583230c0aea5c9ff33f0ac1e26b1e3f03d153
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test bed8cbe9d554c8c27afb6c88500f704c86a9196f
|
||||
F test/skipscan2.test 5a4db0799c338ddbacb154aaa5589c0254b36a8d
|
||||
F test/skipscan1.test 28c7faa41a0d7265040ecb0a0abd90c0904270b2
|
||||
F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
|
||||
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
|
||||
@@ -825,7 +835,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 90446861e566a9965a8d005381a3c964ff333646
|
||||
F test/speedtest1.c d29c8048beb7ea9254191f3fde9414709166a920
|
||||
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
|
||||
@@ -896,6 +906,7 @@ F test/tkt-a8a0d2996a.test eb597379dbcefa24765763d7f682c00cb5924fa9
|
||||
F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550
|
||||
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
|
||||
F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
|
||||
F test/tkt-b75a9ca6b0.test 97cc2d5eeaf82799eb42138c0a1ff64370238ce4
|
||||
F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898
|
||||
F test/tkt-bdc6bbbb38.test fc38bb09bdd440e3513a1f5f98fc60a075182d7d
|
||||
F test/tkt-c48d99d690.test ba61977d62ab612fc515b3c488a6fbd6464a2447
|
||||
@@ -904,6 +915,7 @@ F test/tkt-d11f09d36e.test d999b548fef885d1d1afa49a0e8544ecf436869d
|
||||
F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09
|
||||
F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30
|
||||
F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00
|
||||
F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9
|
||||
F test/tkt-f777251dc7a.test af6531446c64bfd268416f07b4df7be7f9c749d2
|
||||
F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7
|
||||
F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead
|
||||
@@ -996,7 +1008,7 @@ F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/tpch01.test 8f4ac52f62f3e9f6bce0889105aecdf0275e331b
|
||||
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
|
||||
F test/trace2.test e7a988fdd982cdec62f1f1f34b0360e6476d01a0
|
||||
F test/trace2.test 93b47ca6996c66b47f57224cfb146f34e07df382
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
|
||||
F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732
|
||||
@@ -1021,7 +1033,7 @@ F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
|
||||
F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
|
||||
F test/unordered.test ef85ac8f2f3c93ed2b9e811b684de73175fc464c
|
||||
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
|
||||
F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb
|
||||
F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
@@ -1051,7 +1063,7 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772
|
||||
F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc
|
||||
F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af
|
||||
F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada
|
||||
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b
|
||||
@@ -1078,7 +1090,7 @@ F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test 28b64e93428961b07b0d486778d63fd672948f6b
|
||||
F test/where2.test 455a2eb2666e66c1e84e2cb5815173a85e6237db
|
||||
F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e
|
||||
F test/where3.test 1ad55ba900bd7747f98b6082e65bd3e442c5004e
|
||||
F test/where4.test d8420ceeb8323a41ceff1f1841fc528e824e1ecf
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
@@ -1089,15 +1101,16 @@ F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
|
||||
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62
|
||||
F test/whereD.test fd9120e262f9da3c45940f52aefeef4d15b904e5
|
||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/whereG.test 2533b72ed4a31fd1687230a499b557b911525344
|
||||
F test/whereG.test 0ac23e5e8311b69d87245f4a85112de321031658
|
||||
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32lock.test 71642fa56e9b06e5cfffe6bad67cb8c1eb2c555a
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/with1.test 268081a6b14817a262ced4d0ee34d4d2a1dd2068
|
||||
F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775
|
||||
@@ -1110,7 +1123,7 @@ F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107
|
||||
F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac
|
||||
F tool/build-all-msvc.bat e0917e787df675b020d250d60a00de8abaa4e30a x
|
||||
F tool/build-all-msvc.bat a0534c971b86fe95f1983f445db5b896d3394818 x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
|
||||
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||
@@ -1122,17 +1135,17 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/lemon.c 07aba6270d5a5016ba8107b09e431eea4ecdc123
|
||||
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/logest.c 388c318c7ac8b52b7c08ca1e2de0f4ca9a8f7e81
|
||||
F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
|
||||
F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383
|
||||
F tool/mkkeywordhash.c c9e05e4a7bcab8fab9f583d5b321fb72f565ad97
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 78a77b2c554d534c6f2dc903130186ed15715460
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
|
||||
F tool/mksqlite3c.tcl ed5b4e9ca8bf209ff401059a16362f37710fd8b8
|
||||
F tool/mksqlite3c-noext.tcl 1712d3d71256ca1f297046619c89e77a4d7c8f6d
|
||||
F tool/mksqlite3c.tcl ba274df71f5e6534b0a913c7c48eabfcbd0934b6
|
||||
F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
|
||||
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
|
||||
F tool/mkvsix.tcl 6477fb9dab838b7eea1eed50658ff1cda04850b5
|
||||
F tool/mksqlite3internalh.tcl b6514145a7d5321b47e64e19b8116cc44f973eb1
|
||||
F tool/mkvsix.tcl 52a4c613707ac34ae9c226e5ccc69cb948556105
|
||||
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
|
||||
F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
@@ -1158,10 +1171,9 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
|
||||
F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P e54330b43127e46fc6494748cbb353a6fc91cfd7 7473c4dfc10a47594affa6f4e071a08dc8838c0c
|
||||
R dcb8d4aedf5f44fc76078dc97c08f05d
|
||||
T +closed 7473c4dfc10a47594affa6f4e071a08dc8838c0c
|
||||
U drh
|
||||
Z b9b64aa08b9101816e80a031012d4116
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P ed5a9eb4f30a395bc641e79254217c7d7cf0aa5d
|
||||
R 35776e018c929a9d3407d29571ba8a8f
|
||||
U mistachkin
|
||||
Z b80ed398d4e8aaa5357d010e1790f177
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
683dd379a293b2f330e1e4cd746f190527fe48ee
|
||||
f2906c44519d76db5bc36013369ae498b80655a8
|
||||
@@ -116,6 +116,7 @@ static void renameParentFunc(
|
||||
int token; /* Type of token */
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
if( zInput==0 || zOld==0 ) return;
|
||||
for(z=zInput; *z; z=z+n){
|
||||
n = sqlite3GetToken(z, &token);
|
||||
if( token==TK_REFERENCES ){
|
||||
|
||||
+19
-8
@@ -1002,7 +1002,7 @@ static void analyzeOneTable(
|
||||
if( aGotoChng==0 ) continue;
|
||||
|
||||
/* Populate the register containing the index name. */
|
||||
if( pIdx->autoIndex==2 && !HasRowid(pTab) ){
|
||||
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
||||
zIdxName = pTab->zName;
|
||||
}else{
|
||||
zIdxName = pIdx->zName;
|
||||
@@ -1371,6 +1371,7 @@ static void decodeIntArray(
|
||||
char *zIntArray, /* String containing int array to decode */
|
||||
int nOut, /* Number of slots in aOut[] */
|
||||
tRowcnt *aOut, /* Store integers here */
|
||||
LogEst *aLog, /* Or, if aOut==0, here */
|
||||
Index *pIndex /* Handle extra flags for this index, if not NULL */
|
||||
){
|
||||
char *z = zIntArray;
|
||||
@@ -1389,7 +1390,17 @@ static void decodeIntArray(
|
||||
v = v*10 + c - '0';
|
||||
z++;
|
||||
}
|
||||
aOut[i] = v;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( aOut ){
|
||||
aOut[i] = v;
|
||||
}else
|
||||
#else
|
||||
assert( aOut==0 );
|
||||
UNUSED_PARAMETER(aOut);
|
||||
#endif
|
||||
{
|
||||
aLog[i] = sqlite3LogEst(v);
|
||||
}
|
||||
if( *z==' ' ) z++;
|
||||
}
|
||||
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
@@ -1445,12 +1456,12 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
z = argv[2];
|
||||
|
||||
if( pIndex ){
|
||||
decodeIntArray((char*)z, pIndex->nKeyCol+1, pIndex->aiRowEst, pIndex);
|
||||
if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0];
|
||||
decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
|
||||
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
|
||||
}else{
|
||||
Index fakeIdx;
|
||||
fakeIdx.szIdxRow = pTable->szTabRow;
|
||||
decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx);
|
||||
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
|
||||
pTable->szTabRow = fakeIdx.szIdxRow;
|
||||
}
|
||||
|
||||
@@ -1642,9 +1653,9 @@ static int loadStatTbl(
|
||||
pPrevIdx = pIdx;
|
||||
}
|
||||
pSample = &pIdx->aSample[pIdx->nSample];
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,1), nCol, pSample->anEq, 0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,2), nCol, pSample->anLt, 0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,3), nCol, pSample->anDLt,0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0);
|
||||
|
||||
/* Take a copy of the sample. Add two 0x00 bytes the end of the buffer.
|
||||
** This is in case the sample record is corrupted. In that case, the
|
||||
|
||||
+109
-96
@@ -446,16 +446,11 @@ static int cursorHoldsMutex(BtCursor *p){
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/*
|
||||
** Invalidate the overflow page-list cache for cursor pCur, if any.
|
||||
** Invalidate the overflow cache of the cursor passed as the first argument.
|
||||
** on the shared btree structure pBt.
|
||||
*/
|
||||
static void invalidateOverflowCache(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
sqlite3_free(pCur->aOverflow);
|
||||
pCur->aOverflow = 0;
|
||||
}
|
||||
#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl)
|
||||
|
||||
/*
|
||||
** Invalidate the overflow page-list cache for all cursors opened
|
||||
@@ -469,6 +464,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/*
|
||||
** This function is called before modifying the contents of a table
|
||||
** to invalidate any incrblob cursors that are open on the
|
||||
@@ -491,16 +487,14 @@ static void invalidateIncrblobCursors(
|
||||
BtShared *pBt = pBtree->pBt;
|
||||
assert( sqlite3BtreeHoldsMutex(pBtree) );
|
||||
for(p=pBt->pCursor; p; p=p->pNext){
|
||||
if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){
|
||||
if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
|
||||
p->eState = CURSOR_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub functions when INCRBLOB is omitted */
|
||||
#define invalidateOverflowCache(x)
|
||||
#define invalidateAllOverflowCache(x)
|
||||
/* Stub function when INCRBLOB is omitted */
|
||||
#define invalidateIncrblobCursors(x,y,z)
|
||||
#endif /* SQLITE_OMIT_INCRBLOB */
|
||||
|
||||
@@ -2563,7 +2557,8 @@ static int countValidCursors(BtShared *pBt, int wrOnly){
|
||||
BtCursor *pCur;
|
||||
int r = 0;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++;
|
||||
if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
|
||||
&& pCur->eState!=CURSOR_FAULT ) r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -3638,7 +3633,8 @@ static int btreeCursor(
|
||||
pCur->pKeyInfo = pKeyInfo;
|
||||
pCur->pBtree = p;
|
||||
pCur->pBt = pBt;
|
||||
pCur->wrFlag = (u8)wrFlag;
|
||||
assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
|
||||
pCur->curFlags = wrFlag;
|
||||
pCur->pNext = pBt->pCursor;
|
||||
if( pCur->pNext ){
|
||||
pCur->pNext->pPrev = pCur;
|
||||
@@ -3708,7 +3704,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
releasePage(pCur->apPage[i]);
|
||||
}
|
||||
unlockBtreeIfUnused(pBt);
|
||||
invalidateOverflowCache(pCur);
|
||||
sqlite3DbFree(pBtree->db, pCur->aOverflow);
|
||||
/* sqlite3_free(pCur); */
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
@@ -3747,7 +3743,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
if( pCur->info.nSize==0 ){
|
||||
int iPage = pCur->iPage;
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
|
||||
pCur->validNKey = 1;
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
}else{
|
||||
assertCellInfo(pCur);
|
||||
}
|
||||
@@ -3757,8 +3753,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
#define getCellInfo(pCur) \
|
||||
if( pCur->info.nSize==0 ){ \
|
||||
int iPage = pCur->iPage; \
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
|
||||
pCur->validNKey = 1; \
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
|
||||
pCur->curFlags |= BTCF_ValidNKey; \
|
||||
}else{ \
|
||||
assertCellInfo(pCur); \
|
||||
}
|
||||
@@ -3929,10 +3925,12 @@ static int copyPayload(
|
||||
|
||||
/*
|
||||
** This function is used to read or overwrite payload information
|
||||
** for the entry that the pCur cursor is pointing to. If the eOp
|
||||
** parameter is 0, this is a read operation (data copied into
|
||||
** buffer pBuf). If it is non-zero, a write (data copied from
|
||||
** buffer pBuf).
|
||||
** for the entry that the pCur cursor is pointing to. The eOp
|
||||
** argument is interpreted as follows:
|
||||
**
|
||||
** 0: The operation is a read. Populate the overflow cache.
|
||||
** 1: The operation is a write. Populate the overflow cache.
|
||||
** 2: The operation is a read. Do not populate the overflow cache.
|
||||
**
|
||||
** A total of "amt" bytes are read or written beginning at "offset".
|
||||
** Data is read to or from the buffer pBuf.
|
||||
@@ -3940,11 +3938,11 @@ static int copyPayload(
|
||||
** The content being read or written might appear on the main page
|
||||
** or be scattered out on multiple overflow pages.
|
||||
**
|
||||
** If the BtCursor.isIncrblobHandle flag is set, and the current
|
||||
** cursor entry uses one or more overflow pages, this function
|
||||
** allocates space for and lazily popluates the overflow page-list
|
||||
** cache array (BtCursor.aOverflow). Subsequent calls use this
|
||||
** cache to make seeking to the supplied offset more efficient.
|
||||
** If the current cursor entry uses one or more overflow pages and the
|
||||
** eOp argument is not 2, this function may allocate space for and lazily
|
||||
** popluates the overflow page-list cache array (BtCursor.aOverflow).
|
||||
** Subsequent calls use this cache to make seeking to the supplied offset
|
||||
** more efficient.
|
||||
**
|
||||
** Once an overflow page-list cache has been allocated, it may be
|
||||
** invalidated if some other cursor writes to the same table, or if
|
||||
@@ -3968,15 +3966,22 @@ static int accessPayload(
|
||||
int iIdx = 0;
|
||||
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
|
||||
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
int bEnd; /* True if reading to end of data */
|
||||
#endif
|
||||
|
||||
assert( pPage );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
|
||||
|
||||
getCellInfo(pCur);
|
||||
aPayload = pCur->info.pCell + pCur->info.nHeader;
|
||||
nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
bEnd = (offset+amt==nKey+pCur->info.nData);
|
||||
#endif
|
||||
|
||||
if( NEVER(offset+amt > nKey+pCur->info.nData)
|
||||
|| &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
|
||||
@@ -3991,7 +3996,7 @@ static int accessPayload(
|
||||
if( a+offset>pCur->info.nLocal ){
|
||||
a = pCur->info.nLocal - offset;
|
||||
}
|
||||
rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
|
||||
rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
|
||||
offset = 0;
|
||||
pBuf += a;
|
||||
amt -= a;
|
||||
@@ -4005,21 +4010,30 @@ static int accessPayload(
|
||||
|
||||
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[]
|
||||
** has not been allocated, allocate it now. The array is sized at
|
||||
** one entry for each overflow page in the overflow chain. The
|
||||
** page number of the first overflow page is stored in aOverflow[0],
|
||||
** etc. A value of 0 in the aOverflow[] array means "not yet known"
|
||||
** (the cache is lazily populated).
|
||||
/* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
|
||||
** Except, do not allocate aOverflow[] for eOp==2.
|
||||
**
|
||||
** The aOverflow[] array is sized at one entry for each overflow page
|
||||
** in the overflow chain. The page number of the first overflow page is
|
||||
** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
|
||||
** means "not yet known" (the cache is lazily populated).
|
||||
*/
|
||||
if( pCur->isIncrblobHandle && !pCur->aOverflow ){
|
||||
if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
|
||||
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
|
||||
pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl);
|
||||
/* nOvfl is always positive. If it were zero, fetchPayload would have
|
||||
** been used instead of this routine. */
|
||||
if( ALWAYS(nOvfl) && !pCur->aOverflow ){
|
||||
rc = SQLITE_NOMEM;
|
||||
if( nOvfl>pCur->nOvflAlloc ){
|
||||
Pgno *aNew = (Pgno*)sqlite3DbRealloc(
|
||||
pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
|
||||
);
|
||||
if( aNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pCur->nOvflAlloc = nOvfl*2;
|
||||
pCur->aOverflow = aNew;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
|
||||
pCur->curFlags |= BTCF_ValidOvfl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4027,22 +4041,19 @@ static int accessPayload(
|
||||
** entry for the first required overflow page is valid, skip
|
||||
** directly to it.
|
||||
*/
|
||||
if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
|
||||
if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){
|
||||
iIdx = (offset/ovflSize);
|
||||
nextPage = pCur->aOverflow[iIdx];
|
||||
offset = (offset%ovflSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/* If required, populate the overflow page-list cache. */
|
||||
if( pCur->aOverflow ){
|
||||
if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
|
||||
assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
|
||||
pCur->aOverflow[iIdx] = nextPage;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( offset>=ovflSize ){
|
||||
/* The only reason to read this page is to obtain the page
|
||||
@@ -4050,13 +4061,17 @@ static int accessPayload(
|
||||
** data is not required. So first try to lookup the overflow
|
||||
** page-list cache, if any, then fall back to the getOverflowPage()
|
||||
** function.
|
||||
**
|
||||
** Note that the aOverflow[] array must be allocated because eOp!=2
|
||||
** here. If eOp==2, then offset==0 and this branch is never taken.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
|
||||
assert( eOp!=2 );
|
||||
assert( pCur->curFlags & BTCF_ValidOvfl );
|
||||
if( pCur->aOverflow[iIdx+1] ){
|
||||
nextPage = pCur->aOverflow[iIdx+1];
|
||||
} else
|
||||
#endif
|
||||
}else{
|
||||
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
|
||||
}
|
||||
offset -= ovflSize;
|
||||
}else{
|
||||
/* Need to read this page properly. It contains some of the
|
||||
@@ -4078,13 +4093,15 @@ static int accessPayload(
|
||||
** 3) the database is file-backed, and
|
||||
** 4) there is no open write-transaction, and
|
||||
** 5) the database is not a WAL database,
|
||||
** 6) all data from the page is being read.
|
||||
**
|
||||
** then data can be read directly from the database file into the
|
||||
** output buffer, bypassing the page-cache altogether. This speeds
|
||||
** up loading large records that span many overflow pages.
|
||||
*/
|
||||
if( eOp==0 /* (1) */
|
||||
if( (eOp&0x01)==0 /* (1) */
|
||||
&& offset==0 /* (2) */
|
||||
&& (bEnd || a==ovflSize) /* (6) */
|
||||
&& pBt->inTransaction==TRANS_READ /* (4) */
|
||||
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
|
||||
&& pBt->pPage1->aData[19]==0x01 /* (5) */
|
||||
@@ -4101,12 +4118,12 @@ static int accessPayload(
|
||||
{
|
||||
DbPage *pDbPage;
|
||||
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
|
||||
(eOp==0 ? PAGER_GET_READONLY : 0)
|
||||
((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
aPayload = sqlite3PagerGetData(pDbPage);
|
||||
nextPage = get4byte(aPayload);
|
||||
rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
|
||||
rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
|
||||
sqlite3PagerUnref(pDbPage);
|
||||
offset = 0;
|
||||
}
|
||||
@@ -4201,12 +4218,6 @@ static const void *fetchPayload(
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->info.nSize>0 );
|
||||
#if 0
|
||||
if( pCur->info.nSize==0 ){
|
||||
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
|
||||
&pCur->info);
|
||||
}
|
||||
#endif
|
||||
*pAmt = pCur->info.nLocal;
|
||||
return (void*)(pCur->info.pCell + pCur->info.nHeader);
|
||||
}
|
||||
@@ -4257,14 +4268,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = getAndInitPage(pBt, newPgno, &pNewPage,
|
||||
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
|
||||
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
|
||||
if( rc ) return rc;
|
||||
pCur->apPage[i+1] = pNewPage;
|
||||
pCur->aiIdx[i+1] = 0;
|
||||
pCur->iPage++;
|
||||
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
@@ -4322,7 +4333,7 @@ static void moveToParent(BtCursor *pCur){
|
||||
releasePage(pCur->apPage[pCur->iPage]);
|
||||
pCur->iPage--;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4369,7 +4380,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
|
||||
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
|
||||
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
return rc;
|
||||
@@ -4396,8 +4407,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
|
||||
pCur->aiIdx[0] = 0;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->atLast = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
|
||||
if( pRoot->nCell>0 ){
|
||||
pCur->eState = CURSOR_VALID;
|
||||
@@ -4460,7 +4470,7 @@ static int moveToRightmost(BtCursor *pCur){
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~BTCF_ValidNKey;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -4499,7 +4509,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
|
||||
/* If the cursor already points to the last entry, this is a no-op. */
|
||||
if( CURSOR_VALID==pCur->eState && pCur->atLast ){
|
||||
if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* This block serves to assert() that the cursor really does point
|
||||
** to the last entry in the b-tree. */
|
||||
@@ -4522,7 +4532,12 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
*pRes = 0;
|
||||
rc = moveToRightmost(pCur);
|
||||
pCur->atLast = rc==SQLITE_OK ?1:0;
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->curFlags |= BTCF_AtLast;
|
||||
}else{
|
||||
pCur->curFlags &= ~BTCF_AtLast;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -4573,14 +4588,14 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
|
||||
/* If the cursor is already positioned at the point we are trying
|
||||
** to move to, then just return without doing any work */
|
||||
if( pCur->eState==CURSOR_VALID && pCur->validNKey
|
||||
if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
|
||||
&& pCur->apPage[0]->intKey
|
||||
){
|
||||
if( pCur->info.nKey==intKey ){
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pCur->atLast && pCur->info.nKey<intKey ){
|
||||
if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
|
||||
*pRes = -1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -4647,7 +4662,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( lwr>upr ){ c = +1; break; }
|
||||
}else{
|
||||
assert( nCellKey==intKey );
|
||||
pCur->validNKey = 1;
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
pCur->info.nKey = nCellKey;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( !pPage->leaf ){
|
||||
@@ -4704,7 +4719,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
|
||||
if( rc ){
|
||||
sqlite3_free(pCellKey);
|
||||
goto moveto_finish;
|
||||
@@ -4751,7 +4766,7 @@ moveto_next_layer:
|
||||
}
|
||||
moveto_finish:
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4796,6 +4811,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
invalidateOverflowCache(pCur);
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pRes = 0;
|
||||
@@ -4829,7 +4845,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
testcase( idx>pPage->nCell );
|
||||
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
if( idx>=pPage->nCell ){
|
||||
if( !pPage->leaf ){
|
||||
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
|
||||
@@ -4890,7 +4906,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
pCur->atLast = 0;
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
|
||||
rc = btreeRestoreCursorPosition(pCur);
|
||||
@@ -4935,7 +4951,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
moveToParent(pCur);
|
||||
}
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
@@ -6960,7 +6976,7 @@ int sqlite3BtreeInsert(
|
||||
}
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE
|
||||
assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
|
||||
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
|
||||
@@ -6993,7 +7009,7 @@ int sqlite3BtreeInsert(
|
||||
/* If the cursor is currently on the last row and we are appending a
|
||||
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
|
||||
** call */
|
||||
if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){
|
||||
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
|
||||
loc = -1;
|
||||
}
|
||||
}
|
||||
@@ -7046,7 +7062,7 @@ int sqlite3BtreeInsert(
|
||||
|
||||
/* If no error has occurred and pPage has an overflow cell, call balance()
|
||||
** to redistribute the cells within the tree. Since balance() may move
|
||||
** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey
|
||||
** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
|
||||
** variables.
|
||||
**
|
||||
** Previous versions of SQLite called moveToRoot() to move the cursor
|
||||
@@ -7066,7 +7082,7 @@ int sqlite3BtreeInsert(
|
||||
*/
|
||||
pCur->info.nSize = 0;
|
||||
if( rc==SQLITE_OK && pPage->nOverflow ){
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey);
|
||||
rc = balance(pCur);
|
||||
|
||||
/* Must make sure nOverflow is reset to zero even if the balance()
|
||||
@@ -7098,7 +7114,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
||||
assert( pCur->wrFlag );
|
||||
assert( pCur->curFlags & BTCF_WriteFlag );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
|
||||
|
||||
@@ -8411,7 +8427,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
|
||||
int rc;
|
||||
assert( cursorHoldsMutex(pCsr) );
|
||||
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
|
||||
assert( pCsr->isIncrblobHandle );
|
||||
assert( pCsr->curFlags & BTCF_Incrblob );
|
||||
|
||||
rc = restoreCursorPosition(pCsr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -8440,7 +8456,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
|
||||
** (d) there are no conflicting read-locks, and
|
||||
** (e) the cursor points at a valid row of an intKey table.
|
||||
*/
|
||||
if( !pCsr->wrFlag ){
|
||||
if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
|
||||
@@ -8453,20 +8469,10 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
|
||||
}
|
||||
|
||||
/*
|
||||
** Set a flag on this cursor to cache the locations of pages from the
|
||||
** overflow list for the current row. This is used by cursors opened
|
||||
** for incremental blob IO only.
|
||||
**
|
||||
** This function sets a flag only. The actual page location cache
|
||||
** (stored in BtCursor.aOverflow[]) is allocated and used by function
|
||||
** accessPayload() (the worker function for sqlite3BtreeData() and
|
||||
** sqlite3BtreePutData()).
|
||||
** Mark this cursor as an incremental blob cursor.
|
||||
*/
|
||||
void sqlite3BtreeCacheOverflow(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
invalidateOverflowCache(pCur);
|
||||
pCur->isIncrblobHandle = 1;
|
||||
void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
|
||||
pCur->curFlags |= BTCF_Incrblob;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -8514,3 +8520,10 @@ void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
|
||||
assert( mask==BTREE_BULKLOAD || mask==0 );
|
||||
pCsr->hints = mask;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the given Btree is read-only.
|
||||
*/
|
||||
int sqlite3BtreeIsReadonly(Btree *p){
|
||||
return (p->pBt->btsFlags & BTS_READ_ONLY)!=0;
|
||||
}
|
||||
|
||||
+2
-1
@@ -190,10 +190,11 @@ char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
|
||||
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
void sqlite3BtreeCacheOverflow(BtCursor *);
|
||||
void sqlite3BtreeIncrblobCursor(BtCursor *);
|
||||
void sqlite3BtreeClearCursor(BtCursor *);
|
||||
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
|
||||
void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
|
||||
int sqlite3BtreeIsReadonly(Btree *pBt);
|
||||
|
||||
#ifndef NDEBUG
|
||||
int sqlite3BtreeCursorIsValid(BtCursor*);
|
||||
|
||||
+14
-11
@@ -496,27 +496,30 @@ struct BtCursor {
|
||||
BtShared *pBt; /* The BtShared this cursor points to */
|
||||
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
|
||||
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
Pgno *aOverflow; /* Cache of overflow page locations */
|
||||
#endif
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
CellInfo info; /* A parse of the cell we are pointing at */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
void *pKey; /* Saved key that was cursor's last known position */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
void *pKey; /* Saved key that was cursor last known position */
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
int nOvflAlloc; /* Allocated size of aOverflow[] array */
|
||||
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
|
||||
u8 wrFlag; /* True if writable */
|
||||
u8 atLast; /* Cursor pointing to the last entry */
|
||||
u8 validNKey; /* True if info.nKey is valid */
|
||||
u8 curFlags; /* zero or more BTCF_* flags defined below */
|
||||
u8 eState; /* One of the CURSOR_XXX constants (see below) */
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
|
||||
#endif
|
||||
u8 hints; /* As configured by CursorSetHints() */
|
||||
i16 iPage; /* Index of current page in apPage */
|
||||
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
|
||||
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
};
|
||||
|
||||
/*
|
||||
** Legal values for BtCursor.curFlags
|
||||
*/
|
||||
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
|
||||
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
|
||||
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
|
||||
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
|
||||
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
|
||||
|
||||
/*
|
||||
** Potential values for BtCursor.eState.
|
||||
**
|
||||
|
||||
+41
-30
@@ -757,7 +757,7 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){
|
||||
*/
|
||||
Index *sqlite3PrimaryKeyIndex(Table *pTab){
|
||||
Index *p;
|
||||
for(p=pTab->pIndex; p && p->autoIndex!=2; p=p->pNext){}
|
||||
for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){}
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -905,7 +905,7 @@ void sqlite3StartTable(
|
||||
pTable->iPKey = -1;
|
||||
pTable->pSchema = db->aDb[iDb].pSchema;
|
||||
pTable->nRef = 1;
|
||||
pTable->nRowEst = 1048576;
|
||||
pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
assert( pParse->pNewTable==0 );
|
||||
pParse->pNewTable = pTable;
|
||||
|
||||
@@ -1286,7 +1286,7 @@ void sqlite3AddPrimaryKey(
|
||||
p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
|
||||
0, sortOrder, 0);
|
||||
if( p ){
|
||||
p->autoIndex = 2;
|
||||
p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
|
||||
if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK);
|
||||
}
|
||||
pList = 0;
|
||||
@@ -1306,7 +1306,10 @@ void sqlite3AddCheckConstraint(
|
||||
){
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
Table *pTab = pParse->pNewTable;
|
||||
if( pTab && !IN_DECLARE_VTAB ){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( pTab && !IN_DECLARE_VTAB
|
||||
&& !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt)
|
||||
){
|
||||
pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
|
||||
if( pParse->constraintName.n ){
|
||||
sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
|
||||
@@ -1658,7 +1661,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
assert( pParse->pNewTable==pTab );
|
||||
pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
|
||||
if( pPk==0 ) return;
|
||||
pPk->autoIndex = 2;
|
||||
pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
|
||||
pTab->iPKey = -1;
|
||||
}else{
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
@@ -1681,7 +1684,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
*/
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int n;
|
||||
if( pIdx->autoIndex==2 ) continue;
|
||||
if( IsPrimaryKeyIndex(pIdx) ) continue;
|
||||
for(i=n=0; i<nPk; i++){
|
||||
if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++;
|
||||
}
|
||||
@@ -2680,7 +2683,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
|
||||
sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
|
||||
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
||||
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
|
||||
@@ -2730,15 +2733,15 @@ Index *sqlite3AllocateIndexObject(
|
||||
|
||||
nByte = ROUND8(sizeof(Index)) + /* Index structure */
|
||||
ROUND8(sizeof(char*)*nCol) + /* Index.azColl */
|
||||
ROUND8(sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */
|
||||
ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */
|
||||
sizeof(i16)*nCol + /* Index.aiColumn */
|
||||
sizeof(u8)*nCol); /* Index.aSortOrder */
|
||||
p = sqlite3DbMallocZero(db, nByte + nExtra);
|
||||
if( p ){
|
||||
char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
|
||||
p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
|
||||
p->aiRowEst = (tRowcnt*)pExtra; pExtra += sizeof(tRowcnt)*(nCol+1);
|
||||
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
|
||||
p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
|
||||
p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
|
||||
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
|
||||
p->aSortOrder = (u8*)pExtra;
|
||||
p->nColumn = nCol;
|
||||
p->nKeyCol = nCol - 1;
|
||||
@@ -2761,7 +2764,7 @@ Index *sqlite3AllocateIndexObject(
|
||||
**
|
||||
** If the index is created successfully, return a pointer to the new Index
|
||||
** structure. This is used by sqlite3AddPrimaryKey() to mark the index
|
||||
** as the tables primary key (Index.autoIndex==2).
|
||||
** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY)
|
||||
*/
|
||||
Index *sqlite3CreateIndex(
|
||||
Parse *pParse, /* All information about this parse */
|
||||
@@ -2968,7 +2971,7 @@ Index *sqlite3CreateIndex(
|
||||
if( db->mallocFailed ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
|
||||
pIndex->zName = zExtra;
|
||||
zExtra += nName + 1;
|
||||
@@ -2976,7 +2979,7 @@ Index *sqlite3CreateIndex(
|
||||
pIndex->pTable = pTab;
|
||||
pIndex->onError = (u8)onError;
|
||||
pIndex->uniqNotNull = onError!=OE_None;
|
||||
pIndex->autoIndex = (u8)(pName==0);
|
||||
pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE;
|
||||
pIndex->pSchema = db->aDb[iDb].pSchema;
|
||||
pIndex->nKeyCol = pList->nExpr;
|
||||
if( pPIWhere ){
|
||||
@@ -3088,7 +3091,7 @@ Index *sqlite3CreateIndex(
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int k;
|
||||
assert( pIdx->onError!=OE_None );
|
||||
assert( pIdx->autoIndex );
|
||||
assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF );
|
||||
assert( pIndex->onError!=OE_None );
|
||||
|
||||
if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue;
|
||||
@@ -3249,7 +3252,7 @@ exit_create_index:
|
||||
** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the
|
||||
** number of rows in the table that match any particular value of the
|
||||
** first column of the index. aiRowEst[2] is an estimate of the number
|
||||
** of rows that match any particular combiniation of the first 2 columns
|
||||
** of rows that match any particular combination of the first 2 columns
|
||||
** of the index. And so forth. It must always be the case that
|
||||
*
|
||||
** aiRowEst[N]<=aiRowEst[N-1]
|
||||
@@ -3260,20 +3263,27 @@ exit_create_index:
|
||||
** are based on typical values found in actual indices.
|
||||
*/
|
||||
void sqlite3DefaultRowEst(Index *pIdx){
|
||||
tRowcnt *a = pIdx->aiRowEst;
|
||||
/* 10, 9, 8, 7, 6 */
|
||||
LogEst aVal[] = { 33, 32, 30, 28, 26 };
|
||||
LogEst *a = pIdx->aiRowLogEst;
|
||||
int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
|
||||
int i;
|
||||
tRowcnt n;
|
||||
assert( a!=0 );
|
||||
a[0] = pIdx->pTable->nRowEst;
|
||||
if( a[0]<10 ) a[0] = 10;
|
||||
n = 10;
|
||||
for(i=1; i<=pIdx->nKeyCol; i++){
|
||||
a[i] = n;
|
||||
if( n>5 ) n--;
|
||||
}
|
||||
if( pIdx->onError!=OE_None ){
|
||||
a[pIdx->nKeyCol] = 1;
|
||||
|
||||
/* Set the first entry (number of rows in the index) to the estimated
|
||||
** number of rows in the table. Or 10, if the estimated number of rows
|
||||
** in the table is less than that. */
|
||||
a[0] = pIdx->pTable->nRowLogEst;
|
||||
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
||||
|
||||
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
|
||||
** 6 and each subsequent value (if any) is 5. */
|
||||
memcpy(&a[1], aVal, nCopy*sizeof(LogEst));
|
||||
for(i=nCopy+1; i<=pIdx->nKeyCol; i++){
|
||||
a[i] = 23; assert( 23==sqlite3LogEst(5) );
|
||||
}
|
||||
|
||||
assert( 0==sqlite3LogEst(1) );
|
||||
if( pIdx->onError!=OE_None ) a[pIdx->nKeyCol] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3304,7 +3314,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
||||
pParse->checkSchema = 1;
|
||||
goto exit_drop_index;
|
||||
}
|
||||
if( pIndex->autoIndex ){
|
||||
if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
|
||||
sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
|
||||
"or PRIMARY KEY constraint cannot be dropped", 0);
|
||||
goto exit_drop_index;
|
||||
@@ -3963,7 +3973,8 @@ void sqlite3UniqueConstraint(
|
||||
}
|
||||
zErr = sqlite3StrAccumFinish(&errMsg);
|
||||
sqlite3HaltConstraint(pParse,
|
||||
(pIdx->autoIndex==2)?SQLITE_CONSTRAINT_PRIMARYKEY:SQLITE_CONSTRAINT_UNIQUE,
|
||||
IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY
|
||||
: SQLITE_CONSTRAINT_UNIQUE,
|
||||
onError, zErr, P4_DYNAMIC, P5_ConstraintUnique);
|
||||
}
|
||||
|
||||
|
||||
+16
-2
@@ -739,7 +739,7 @@ void sqlite3GenerateRowIndexDelete(
|
||||
&iPartIdxLabel, pPrior, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
||||
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
||||
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
||||
pPrior = pIdx;
|
||||
}
|
||||
}
|
||||
@@ -758,10 +758,11 @@ void sqlite3GenerateRowIndexDelete(
|
||||
**
|
||||
** If *piPartIdxLabel is not NULL, fill it in with a label and jump
|
||||
** to that label if pIdx is a partial index that should be skipped.
|
||||
** The label should be resolved using sqlite3ResolvePartIdxLabel().
|
||||
** A partial index should be skipped if its WHERE clause evaluates
|
||||
** to false or null. If pIdx is not a partial index, *piPartIdxLabel
|
||||
** will be set to zero which is an empty label that is ignored by
|
||||
** sqlite3VdbeResolveLabel().
|
||||
** sqlite3ResolvePartIdxLabel().
|
||||
**
|
||||
** The pPrior and regPrior parameters are used to implement a cache to
|
||||
** avoid unnecessary register loads. If pPrior is not NULL, then it is
|
||||
@@ -794,6 +795,7 @@ int sqlite3GenerateIndexKey(
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
|
||||
pParse->iPartIdxTab = iDataCur;
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
||||
SQLITE_JUMPIFNULL);
|
||||
}else{
|
||||
@@ -821,3 +823,15 @@ int sqlite3GenerateIndexKey(
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
||||
return regBase;
|
||||
}
|
||||
|
||||
/*
|
||||
** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label
|
||||
** because it was a partial index, then this routine should be called to
|
||||
** resolve that label.
|
||||
*/
|
||||
void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
|
||||
if( iLabel ){
|
||||
sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}
|
||||
}
|
||||
|
||||
+15
-16
@@ -1883,7 +1883,7 @@ int sqlite3CodeSubselect(
|
||||
if( testAddr>=0 ){
|
||||
sqlite3VdbeJumpHere(v, testAddr);
|
||||
}
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
|
||||
return rReg;
|
||||
}
|
||||
@@ -2018,7 +2018,7 @@ static void sqlite3ExprCodeIN(
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
VdbeComment((v, "end IN expr"));
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
@@ -2201,15 +2201,14 @@ void sqlite3ExprCachePush(Parse *pParse){
|
||||
|
||||
/*
|
||||
** Remove from the column cache any entries that were added since the
|
||||
** the previous N Push operations. In other words, restore the cache
|
||||
** to the state it was in N Pushes ago.
|
||||
** the previous sqlite3ExprCachePush operation. In other words, restore
|
||||
** the cache to the state it was in prior the most recent Push.
|
||||
*/
|
||||
void sqlite3ExprCachePop(Parse *pParse, int N){
|
||||
void sqlite3ExprCachePop(Parse *pParse){
|
||||
int i;
|
||||
struct yColCache *p;
|
||||
assert( N>0 );
|
||||
assert( pParse->iCacheLevel>=N );
|
||||
pParse->iCacheLevel -= N;
|
||||
assert( pParse->iCacheLevel>=1 );
|
||||
pParse->iCacheLevel--;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
|
||||
printf("POP to %d\n", pParse->iCacheLevel);
|
||||
@@ -2687,7 +2686,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3ExprCacheRemove(pParse, target, 1);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, endCoalesce);
|
||||
break;
|
||||
@@ -2741,7 +2740,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1,
|
||||
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
|
||||
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
|
||||
sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */
|
||||
}else{
|
||||
r1 = 0;
|
||||
}
|
||||
@@ -2961,13 +2960,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
|
||||
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
sqlite3VdbeResolveLabel(v, nextCase);
|
||||
}
|
||||
if( (nExpr&1)!=0 ){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||
}
|
||||
@@ -3546,7 +3545,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
sqlite3VdbeResolveLabel(v, d2);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
break;
|
||||
}
|
||||
case TK_OR: {
|
||||
@@ -3554,7 +3553,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
break;
|
||||
}
|
||||
case TK_NOT: {
|
||||
@@ -3700,7 +3699,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
break;
|
||||
}
|
||||
case TK_OR: {
|
||||
@@ -3710,7 +3709,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
sqlite3VdbeResolveLabel(v, d2);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
break;
|
||||
}
|
||||
case TK_NOT: {
|
||||
|
||||
+2
-2
@@ -233,8 +233,8 @@ int sqlite3FkLocateIndex(
|
||||
if( zKey==0 ){
|
||||
/* If zKey is NULL, then this foreign key is implicitly mapped to
|
||||
** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be
|
||||
** identified by the test (Index.autoIndex==2). */
|
||||
if( pIdx->autoIndex==2 ){
|
||||
** identified by the test. */
|
||||
if( IsPrimaryKeyIndex(pIdx) ){
|
||||
if( aiCol ){
|
||||
int i;
|
||||
for(i=0; i<nCol; i++) aiCol[i] = pFKey->aCol[i].iFrom;
|
||||
|
||||
+1
-1
@@ -1541,7 +1541,7 @@ static void groupConcatStep(
|
||||
}
|
||||
zVal = (char*)sqlite3_value_text(argv[0]);
|
||||
nVal = sqlite3_value_bytes(argv[0]);
|
||||
if( nVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal);
|
||||
if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal);
|
||||
}
|
||||
}
|
||||
static void groupConcatFinalize(sqlite3_context *context){
|
||||
|
||||
+10
-3
@@ -173,15 +173,22 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* isMutexInit */
|
||||
0, /* isMallocInit */
|
||||
0, /* isPCacheInit */
|
||||
0, /* pInitMutex */
|
||||
0, /* nRefInitMutex */
|
||||
0, /* pInitMutex */
|
||||
0, /* xLog */
|
||||
0, /* pLogArg */
|
||||
0, /* bLocaltimeFault */
|
||||
#ifdef SQLITE_ENABLE_SQLLOG
|
||||
0, /* xSqllog */
|
||||
0 /* pSqllogArg */
|
||||
0, /* pSqllogArg */
|
||||
#endif
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
0, /* xVdbeBranch */
|
||||
0, /* pVbeBranchArg */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
0, /* xTestCallback */
|
||||
#endif
|
||||
0 /* bLocaltimeFault */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+16
-6
@@ -614,6 +614,7 @@ void sqlite3Insert(
|
||||
if( j>=pTab->nCol ){
|
||||
if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){
|
||||
ipkColumn = i;
|
||||
bIdListInOrder = 0;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "table %S has no column named %s",
|
||||
pTabList, 0, pColumn->a[i].zName);
|
||||
@@ -1462,7 +1463,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
** KEY values of this row before the update. */
|
||||
int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
|
||||
int op = OP_Ne;
|
||||
int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
|
||||
int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR);
|
||||
|
||||
for(i=0; i<pPk->nKeyCol; i++){
|
||||
char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
|
||||
@@ -1563,7 +1564,7 @@ void sqlite3CompleteInsertion(
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
|
||||
pik_flags = 0;
|
||||
if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
|
||||
if( pIdx->autoIndex==2 && !HasRowid(pTab) ){
|
||||
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
||||
assert( pParse->nested==0 );
|
||||
pik_flags |= OPFLAG_NCHANGE;
|
||||
}
|
||||
@@ -1649,7 +1650,7 @@ int sqlite3OpenTableAndIndices(
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
int iIdxCur = iBase++;
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
if( pIdx->autoIndex==2 && !HasRowid(pTab) && piDataCur ){
|
||||
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){
|
||||
*piDataCur = iIdxCur;
|
||||
}
|
||||
if( aToOpen==0 || aToOpen[i+1] ){
|
||||
@@ -1865,15 +1866,24 @@ static int xferOptimization(
|
||||
return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
|
||||
}
|
||||
for(i=0; i<pDest->nCol; i++){
|
||||
if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){
|
||||
Column *pDestCol = &pDest->aCol[i];
|
||||
Column *pSrcCol = &pSrc->aCol[i];
|
||||
if( pDestCol->affinity!=pSrcCol->affinity ){
|
||||
return 0; /* Affinity must be the same on all columns */
|
||||
}
|
||||
if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){
|
||||
if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){
|
||||
return 0; /* Collating sequence must be the same on all columns */
|
||||
}
|
||||
if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){
|
||||
if( pDestCol->notNull && !pSrcCol->notNull ){
|
||||
return 0; /* tab2 must be NOT NULL if tab1 is */
|
||||
}
|
||||
/* Default values for second and subsequent columns need to match. */
|
||||
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){
|
||||
if( pDestIdx->onError!=OE_None ){
|
||||
|
||||
+39
-1
@@ -3114,6 +3114,28 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_test_control(FAULT_INSTALL, xCallback)
|
||||
**
|
||||
** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called,
|
||||
** if xCallback is not NULL.
|
||||
**
|
||||
** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0)
|
||||
** is called immediately after installing the new callback and the return
|
||||
** value from sqlite3FaultSim(0) becomes the return from
|
||||
** sqlite3_test_control().
|
||||
*/
|
||||
case SQLITE_TESTCTRL_FAULT_INSTALL: {
|
||||
/* MSVC is picky about pulling func ptrs from va lists.
|
||||
** http://support.microsoft.com/kb/47961
|
||||
** sqlite3Config.xTestCallback = va_arg(ap, int(*)(int));
|
||||
*/
|
||||
typedef int(*TESTCALLBACKFUNC_t)(int);
|
||||
sqlite3Config.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t);
|
||||
rc = sqlite3FaultSim(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd)
|
||||
**
|
||||
@@ -3205,6 +3227,22 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER);
|
||||
**
|
||||
** The integer returned reveals the byte-order of the computer on which
|
||||
** SQLite is running:
|
||||
**
|
||||
** 1 big-endian, determined at run-time
|
||||
** 10 little-endian, determined at run-time
|
||||
** 432101 big-endian, determined at compile-time
|
||||
** 123410 little-endian, determined at compile-time
|
||||
*/
|
||||
case SQLITE_TESTCTRL_BYTEORDER: {
|
||||
rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
|
||||
**
|
||||
** Set the nReserve size to N for the main database on the database
|
||||
@@ -3407,5 +3445,5 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
|
||||
*/
|
||||
int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
|
||||
Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
|
||||
return pBt ? sqlite3PagerIsreadonly(sqlite3BtreePager(pBt)) : -1;
|
||||
return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#if SQLITE_OS_WIN
|
||||
/*
|
||||
** Include the header file for the Windows VFS.
|
||||
*/
|
||||
#include "os_win.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The code in this file is only used if we are compiling multithreaded
|
||||
** on a win32 system.
|
||||
|
||||
@@ -21,83 +21,10 @@
|
||||
#define _SQLITE_OS_H_
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows, or some other
|
||||
** operating system. After the following block of preprocess macros,
|
||||
** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, and SQLITE_OS_OTHER
|
||||
** will defined to either 1 or 0. One of the four will be 1. The other
|
||||
** three will be 0.
|
||||
** Attempt to automatically detect the operating system and setup the
|
||||
** necessary pre-processor macros for it.
|
||||
*/
|
||||
#if defined(SQLITE_OS_OTHER)
|
||||
# if SQLITE_OS_OTHER==1
|
||||
# undef SQLITE_OS_UNIX
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# undef SQLITE_OS_WIN
|
||||
# define SQLITE_OS_WIN 0
|
||||
# else
|
||||
# undef SQLITE_OS_OTHER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
|
||||
# define SQLITE_OS_OTHER 0
|
||||
# ifndef SQLITE_OS_WIN
|
||||
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define SQLITE_OS_WIN 1
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# else
|
||||
# define SQLITE_OS_WIN 0
|
||||
# define SQLITE_OS_UNIX 1
|
||||
# endif
|
||||
# else
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# endif
|
||||
#else
|
||||
# ifndef SQLITE_OS_WIN
|
||||
# define SQLITE_OS_WIN 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if SQLITE_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with Windows NT.
|
||||
**
|
||||
** We ought to be able to determine if we are compiling for win98 or winNT
|
||||
** using the _WIN32_WINNT macro as follows:
|
||||
**
|
||||
** #if defined(_WIN32_WINNT)
|
||||
** # define SQLITE_OS_WINNT 1
|
||||
** #else
|
||||
** # define SQLITE_OS_WINNT 0
|
||||
** #endif
|
||||
**
|
||||
** However, vs2005 does not set _WIN32_WINNT by default, as it ought to,
|
||||
** so the above test does not work. We'll just assume that everything is
|
||||
** winNT unless the programmer explicitly says otherwise by setting
|
||||
** SQLITE_OS_WINNT to 0.
|
||||
*/
|
||||
#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT)
|
||||
# define SQLITE_OS_WINNT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with WindowsCE - which has a much
|
||||
** reduced API.
|
||||
*/
|
||||
#if defined(_WIN32_WCE)
|
||||
# define SQLITE_OS_WINCE 1
|
||||
#else
|
||||
# define SQLITE_OS_WINCE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with WinRT, which provides only a subset of
|
||||
** the full Win32 API.
|
||||
*/
|
||||
#if !defined(SQLITE_OS_WINRT)
|
||||
# define SQLITE_OS_WINRT 0
|
||||
#endif
|
||||
#include "os_setup.h"
|
||||
|
||||
/* If the SET_FULLSYNC macro is not defined above, then make it
|
||||
** a no-op
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
** 2013 November 25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains pre-processor directives related to operating system
|
||||
** detection and/or setup.
|
||||
*/
|
||||
#ifndef _OS_SETUP_H_
|
||||
#define _OS_SETUP_H_
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows, or some other operating
|
||||
** system.
|
||||
**
|
||||
** After the following block of preprocess macros, all of SQLITE_OS_UNIX,
|
||||
** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of
|
||||
** the three will be 1. The other two will be 0.
|
||||
*/
|
||||
#if defined(SQLITE_OS_OTHER)
|
||||
# if SQLITE_OS_OTHER==1
|
||||
# undef SQLITE_OS_UNIX
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# undef SQLITE_OS_WIN
|
||||
# define SQLITE_OS_WIN 0
|
||||
# else
|
||||
# undef SQLITE_OS_OTHER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
|
||||
# define SQLITE_OS_OTHER 0
|
||||
# ifndef SQLITE_OS_WIN
|
||||
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
|
||||
defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define SQLITE_OS_WIN 1
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# else
|
||||
# define SQLITE_OS_WIN 0
|
||||
# define SQLITE_OS_UNIX 1
|
||||
# endif
|
||||
# else
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# endif
|
||||
#else
|
||||
# ifndef SQLITE_OS_WIN
|
||||
# define SQLITE_OS_WIN 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _OS_SETUP_H_ */
|
||||
+70
-20
@@ -15,16 +15,16 @@
|
||||
#include "sqliteInt.h"
|
||||
#if SQLITE_OS_WIN /* This file is used for Windows only */
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <sys/cygwin.h>
|
||||
# include <errno.h> /* amalgamator: keep */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Include code that is common to all os_*.c files
|
||||
*/
|
||||
#include "os_common.h"
|
||||
|
||||
/*
|
||||
** Include the header file for the Windows VFS.
|
||||
*/
|
||||
#include "os_win.h"
|
||||
|
||||
/*
|
||||
** Compiling and using WAL mode requires several APIs that are only
|
||||
** available in Windows platforms based on the NT kernel.
|
||||
@@ -1836,6 +1836,32 @@ static int winLogErrorAtLine(
|
||||
static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY;
|
||||
static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
|
||||
|
||||
/*
|
||||
** The "winIoerrCanRetry1" macro is used to determine if a particular I/O
|
||||
** error code obtained via GetLastError() is eligible to be retried. It
|
||||
** must accept the error code DWORD as its only argument and should return
|
||||
** non-zero if the error code is transient in nature and the operation
|
||||
** responsible for generating the original error might succeed upon being
|
||||
** retried. The argument to this macro should be a variable.
|
||||
**
|
||||
** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it
|
||||
** is defined, it will be consulted only when the macro "winIoerrCanRetry1"
|
||||
** returns zero. The "winIoerrCanRetry2" macro is completely optional and
|
||||
** may be used to include additional error codes in the set that should
|
||||
** result in the failing I/O operation being retried by the caller. If
|
||||
** defined, the "winIoerrCanRetry2" macro must exhibit external semantics
|
||||
** identical to those of the "winIoerrCanRetry1" macro.
|
||||
*/
|
||||
#if !defined(winIoerrCanRetry1)
|
||||
#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \
|
||||
((a)==ERROR_SHARING_VIOLATION) || \
|
||||
((a)==ERROR_LOCK_VIOLATION) || \
|
||||
((a)==ERROR_DEV_NOT_EXIST) || \
|
||||
((a)==ERROR_NETNAME_DELETED) || \
|
||||
((a)==ERROR_SEM_TIMEOUT) || \
|
||||
((a)==ERROR_NETWORK_UNREACHABLE))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If a ReadFile() or WriteFile() error occurs, invoke this routine
|
||||
** to see if it should be retried. Return TRUE to retry. Return FALSE
|
||||
@@ -1849,13 +1875,18 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if( e==ERROR_ACCESS_DENIED ||
|
||||
e==ERROR_LOCK_VIOLATION ||
|
||||
e==ERROR_SHARING_VIOLATION ){
|
||||
if( winIoerrCanRetry1(e) ){
|
||||
sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
|
||||
++*pnRetry;
|
||||
return 1;
|
||||
}
|
||||
#if defined(winIoerrCanRetry2)
|
||||
else if( winIoerrCanRetry2(e) ){
|
||||
sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
|
||||
++*pnRetry;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
if( pError ){
|
||||
*pError = e;
|
||||
}
|
||||
@@ -2794,7 +2825,7 @@ static int winGetReadLock(winFile *pFile){
|
||||
pFile->lastErrno = osGetLastError();
|
||||
/* No need to log a failure to lock */
|
||||
}
|
||||
OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
|
||||
OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res));
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2818,7 +2849,7 @@ static int winUnlockReadLock(winFile *pFile){
|
||||
winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
|
||||
"winUnlockReadLock", pFile->zPath);
|
||||
}
|
||||
OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
|
||||
OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res));
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2893,8 +2924,16 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
** If you are using this code as a model for alternative VFSes, do not
|
||||
** copy this retry logic. It is a hack intended for Windows only.
|
||||
*/
|
||||
OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n",
|
||||
pFile->h, cnt, sqlite3ErrName(res)));
|
||||
lastErrno = osGetLastError();
|
||||
OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
|
||||
pFile->h, cnt, res));
|
||||
if( lastErrno==ERROR_INVALID_HANDLE ){
|
||||
pFile->lastErrno = lastErrno;
|
||||
rc = SQLITE_IOERR_LOCK;
|
||||
OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n",
|
||||
pFile->h, cnt, sqlite3ErrName(rc)));
|
||||
return rc;
|
||||
}
|
||||
if( cnt ) sqlite3_win32_sleep(1);
|
||||
}
|
||||
gotPendingLock = res;
|
||||
@@ -2979,7 +3018,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
** non-zero, otherwise zero.
|
||||
*/
|
||||
static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
|
||||
int rc;
|
||||
int res;
|
||||
winFile *pFile = (winFile*)id;
|
||||
|
||||
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
|
||||
@@ -2987,17 +3026,17 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
|
||||
|
||||
assert( id!=0 );
|
||||
if( pFile->locktype>=RESERVED_LOCK ){
|
||||
rc = 1;
|
||||
OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc));
|
||||
res = 1;
|
||||
OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
|
||||
}else{
|
||||
rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
|
||||
if( rc ){
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
|
||||
if( res ){
|
||||
winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
|
||||
}
|
||||
rc = !rc;
|
||||
OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc));
|
||||
res = !res;
|
||||
OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res));
|
||||
}
|
||||
*pResOut = rc;
|
||||
*pResOut = res;
|
||||
OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
|
||||
pFile->h, pResOut, *pResOut));
|
||||
return SQLITE_OK;
|
||||
@@ -3138,6 +3177,17 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#ifdef SQLITE_TEST
|
||||
case SQLITE_FCNTL_WIN32_SET_HANDLE: {
|
||||
LPHANDLE phFile = (LPHANDLE)pArg;
|
||||
HANDLE hOldFile = pFile->h;
|
||||
pFile->h = *phFile;
|
||||
*phFile = hOldFile;
|
||||
OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n",
|
||||
hOldFile, pFile->h));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
case SQLITE_FCNTL_TEMPFILENAME: {
|
||||
char *zTFile = 0;
|
||||
int rc = winGetTempname(pFile->pVfs, &zTFile);
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
** 2013 November 25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains code that is specific to Windows.
|
||||
*/
|
||||
#ifndef _OS_WIN_H_
|
||||
#define _OS_WIN_H_
|
||||
|
||||
/*
|
||||
** Include the primary Windows SDK header file.
|
||||
*/
|
||||
#include "windows.h"
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <sys/cygwin.h>
|
||||
# include <errno.h> /* amalgamator: dontcache */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with Windows NT.
|
||||
**
|
||||
** We ought to be able to determine if we are compiling for Windows 9x or
|
||||
** Windows NT using the _WIN32_WINNT macro as follows:
|
||||
**
|
||||
** #if defined(_WIN32_WINNT)
|
||||
** # define SQLITE_OS_WINNT 1
|
||||
** #else
|
||||
** # define SQLITE_OS_WINNT 0
|
||||
** #endif
|
||||
**
|
||||
** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as
|
||||
** it ought to, so the above test does not work. We'll just assume that
|
||||
** everything is Windows NT unless the programmer explicitly says otherwise
|
||||
** by setting SQLITE_OS_WINNT to 0.
|
||||
*/
|
||||
#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT)
|
||||
# define SQLITE_OS_WINNT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with Windows CE - which has a much reduced
|
||||
** API.
|
||||
*/
|
||||
#if defined(_WIN32_WCE)
|
||||
# define SQLITE_OS_WINCE 1
|
||||
#else
|
||||
# define SQLITE_OS_WINCE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with WinRT, which provides only a subset of
|
||||
** the full Win32 API.
|
||||
*/
|
||||
#if !defined(SQLITE_OS_WINRT)
|
||||
# define SQLITE_OS_WINRT 0
|
||||
#endif
|
||||
|
||||
#endif /* _OS_WIN_H_ */
|
||||
+39
-29
@@ -626,7 +626,8 @@ struct Pager {
|
||||
u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
|
||||
u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
|
||||
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
|
||||
u8 tempFile; /* zFilename is a temporary file */
|
||||
u8 tempFile; /* zFilename is a temporary or immutable file */
|
||||
u8 noLock; /* Do not lock (except in WAL mode) */
|
||||
u8 readOnly; /* True for a read-only database */
|
||||
u8 memDb; /* True to inhibit all file I/O */
|
||||
|
||||
@@ -1091,7 +1092,7 @@ static int pagerUnlockDb(Pager *pPager, int eLock){
|
||||
assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 );
|
||||
if( isOpen(pPager->fd) ){
|
||||
assert( pPager->eLock>=eLock );
|
||||
rc = sqlite3OsUnlock(pPager->fd, eLock);
|
||||
rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock);
|
||||
if( pPager->eLock!=UNKNOWN_LOCK ){
|
||||
pPager->eLock = (u8)eLock;
|
||||
}
|
||||
@@ -1115,7 +1116,7 @@ static int pagerLockDb(Pager *pPager, int eLock){
|
||||
|
||||
assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK );
|
||||
if( pPager->eLock<eLock || pPager->eLock==UNKNOWN_LOCK ){
|
||||
rc = sqlite3OsLock(pPager->fd, eLock);
|
||||
rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock);
|
||||
if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){
|
||||
pPager->eLock = (u8)eLock;
|
||||
IOTRACE(("LOCK %p %d\n", pPager, eLock))
|
||||
@@ -4674,30 +4675,38 @@ int sqlite3PagerOpen(
|
||||
** + The value returned by sqlite3OsSectorSize()
|
||||
** + The largest page size that can be written atomically.
|
||||
*/
|
||||
if( rc==SQLITE_OK && !readOnly ){
|
||||
setSectorSize(pPager);
|
||||
assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE);
|
||||
if( szPageDflt<pPager->sectorSize ){
|
||||
if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){
|
||||
szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE;
|
||||
}else{
|
||||
szPageDflt = (u32)pPager->sectorSize;
|
||||
}
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
{
|
||||
int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
|
||||
int ii;
|
||||
assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
|
||||
assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
|
||||
assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536);
|
||||
for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){
|
||||
if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){
|
||||
szPageDflt = ii;
|
||||
if( rc==SQLITE_OK ){
|
||||
int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
|
||||
if( !readOnly ){
|
||||
setSectorSize(pPager);
|
||||
assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE);
|
||||
if( szPageDflt<pPager->sectorSize ){
|
||||
if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){
|
||||
szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE;
|
||||
}else{
|
||||
szPageDflt = (u32)pPager->sectorSize;
|
||||
}
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
{
|
||||
int ii;
|
||||
assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
|
||||
assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
|
||||
assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536);
|
||||
for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){
|
||||
if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){
|
||||
szPageDflt = ii;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0);
|
||||
if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0
|
||||
|| sqlite3_uri_boolean(zFilename, "immutable", 0) ){
|
||||
vfsFlags |= SQLITE_OPEN_READONLY;
|
||||
goto act_like_temp_file;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* If a temporary file is requested, it is not opened immediately.
|
||||
@@ -4707,10 +4716,14 @@ int sqlite3PagerOpen(
|
||||
** This branch is also run for an in-memory database. An in-memory
|
||||
** database is the same as a temp-file that is never written out to
|
||||
** disk and uses an in-memory rollback journal.
|
||||
**
|
||||
** This branch also runs for files marked as immutable.
|
||||
*/
|
||||
act_like_temp_file:
|
||||
tempFile = 1;
|
||||
pPager->eState = PAGER_READER;
|
||||
pPager->eLock = EXCLUSIVE_LOCK;
|
||||
pPager->eState = PAGER_READER; /* Pretend we already have a lock */
|
||||
pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE locking mode */
|
||||
pPager->noLock = 1; /* Do no locking */
|
||||
readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
|
||||
}
|
||||
|
||||
@@ -4751,9 +4764,6 @@ int sqlite3PagerOpen(
|
||||
/* pPager->nPage = 0; */
|
||||
pPager->mxPgno = SQLITE_MAX_PAGE_COUNT;
|
||||
/* pPager->state = PAGER_UNLOCK; */
|
||||
#if 0
|
||||
assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) );
|
||||
#endif
|
||||
/* pPager->errMask = 0; */
|
||||
pPager->tempFile = (u8)tempFile;
|
||||
assert( tempFile==PAGER_LOCKINGMODE_NORMAL
|
||||
|
||||
+5
-3
@@ -1488,13 +1488,15 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pTab->szTabRow), 3);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, (int)pTab->nRowEst, 4);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pTab->nRowLogEst), 4);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pIdx->szIdxRow), 3);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, (int)pIdx->aiRowEst[0], 4);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]), 4);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
||||
}
|
||||
}
|
||||
@@ -1928,7 +1930,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
sqlite3VdbeJumpHere(v, jmp4);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeResolveLabel(v, jmp3);
|
||||
sqlite3ResolvePartIdxLabel(pParse, jmp3);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
|
||||
+3
-3
@@ -112,8 +112,8 @@ struct RowSet {
|
||||
struct RowSetEntry *pFresh; /* Source of new entry objects */
|
||||
struct RowSetEntry *pForest; /* List of binary trees of entries */
|
||||
u16 nFresh; /* Number of objects on pFresh */
|
||||
u8 rsFlags; /* Various flags */
|
||||
u8 iBatch; /* Current insert batch */
|
||||
u16 rsFlags; /* Various flags */
|
||||
int iBatch; /* Current insert batch */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -447,7 +447,7 @@ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
|
||||
** on pRowSet->pEntry, then sort those entires into the forest at
|
||||
** pRowSet->pForest so that they can be tested.
|
||||
*/
|
||||
int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){
|
||||
int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
|
||||
struct RowSetEntry *p, *pTree;
|
||||
|
||||
/* This routine is never called after sqlite3RowSetNext() */
|
||||
|
||||
+44
-28
@@ -466,15 +466,17 @@ static void pushOntoSorter(
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int nExpr = pSort->pOrderBy->nExpr;
|
||||
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
|
||||
int regRecord = sqlite3GetTempReg(pParse);
|
||||
int regRecord = ++pParse->nMem;
|
||||
int regBase = pParse->nMem+1;
|
||||
int nOBSat = pSort->nOBSat;
|
||||
int op;
|
||||
|
||||
pParse->nMem += nExpr+2; /* nExpr+2 registers allocated at regBase */
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
|
||||
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat, regRecord);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat,regRecord);
|
||||
if( nOBSat>0 ){
|
||||
int regPrevKey; /* The first nOBSat columns of the previous row */
|
||||
int addrFirst; /* Address of the OP_IfNot opcode */
|
||||
@@ -511,10 +513,6 @@ static void pushOntoSorter(
|
||||
op = OP_IdxInsert;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
|
||||
if( nOBSat==0 ){
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
|
||||
}
|
||||
if( pSelect->iLimit ){
|
||||
int addr1, addr2;
|
||||
int iLimit;
|
||||
@@ -1690,7 +1688,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
||||
assert( db->lookaside.bEnabled==0 );
|
||||
pTab->nRef = 1;
|
||||
pTab->zName = 0;
|
||||
pTab->nRowEst = 1048576;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
||||
selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
||||
pTab->iPKey = -1;
|
||||
@@ -3829,7 +3827,7 @@ static int withExpand(
|
||||
pTab->nRef = 1;
|
||||
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
|
||||
pTab->iPKey = -1;
|
||||
pTab->nRowEst = 1048576;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
pTab->tabFlags |= TF_Ephemeral;
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
|
||||
if( db->mallocFailed ) return SQLITE_NOMEM;
|
||||
@@ -4005,7 +4003,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
||||
selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
|
||||
pTab->iPKey = -1;
|
||||
pTab->nRowEst = 1048576;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
pTab->tabFlags |= TF_Ephemeral;
|
||||
#endif
|
||||
}else{
|
||||
@@ -4500,10 +4498,11 @@ static void explainSimpleCount(
|
||||
Index *pIdx /* Index used to optimize scan, or NULL */
|
||||
){
|
||||
if( pParse->explain==2 ){
|
||||
int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx)));
|
||||
char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s",
|
||||
pTab->zName,
|
||||
pIdx ? " USING COVERING INDEX " : "",
|
||||
pIdx ? pIdx->zName : ""
|
||||
pTab->zName,
|
||||
bCover ? " USING COVERING INDEX " : "",
|
||||
bCover ? pIdx->zName : ""
|
||||
);
|
||||
sqlite3VdbeAddOp4(
|
||||
pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC
|
||||
@@ -4655,7 +4654,7 @@ int sqlite3Select(
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
|
||||
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
||||
pItem->viaCoroutine = 1;
|
||||
pItem->regResult = dest.iSdst;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
||||
@@ -4686,7 +4685,7 @@ int sqlite3Select(
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
|
||||
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
@@ -4719,18 +4718,6 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then disable the ORDER BY clause since the GROUP BY
|
||||
** will cause elements to come out in the correct order. This is
|
||||
** an optimization - the correct answer should result regardless.
|
||||
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
|
||||
** to disable this optimization for testing purposes.
|
||||
*/
|
||||
if( sqlite3ExprListCompare(p->pGroupBy, sSort.pOrderBy, -1)==0
|
||||
&& OptimizationEnabled(db, SQLITE_GroupByOrder) ){
|
||||
sSort.pOrderBy = 0;
|
||||
}
|
||||
|
||||
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
||||
** if the select-list is the same as the ORDER BY list, then this query
|
||||
** can be rewritten as a GROUP BY. In other words, this:
|
||||
@@ -4859,6 +4846,7 @@ int sqlite3Select(
|
||||
int addrEnd; /* End of processing for this SELECT */
|
||||
int sortPTab = 0; /* Pseudotable used to decode sorting results */
|
||||
int sortOut = 0; /* Output register from the sorter */
|
||||
int orderByGrp = 0; /* True if the GROUP BY and ORDER BY are the same */
|
||||
|
||||
/* Remove any and all aliases between the result set and the
|
||||
** GROUP BY clause.
|
||||
@@ -4878,6 +4866,18 @@ int sqlite3Select(
|
||||
p->nSelectRow = 1;
|
||||
}
|
||||
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then it may be possible to disable the ORDER BY clause
|
||||
** on the grounds that the GROUP BY will cause elements to come out
|
||||
** in the correct order. It also may not - the GROUP BY may use a
|
||||
** database index that causes rows to be grouped together as required
|
||||
** but not actually sorted. Either way, record the fact that the
|
||||
** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
|
||||
** variable. */
|
||||
if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
|
||||
orderByGrp = 1;
|
||||
}
|
||||
|
||||
/* Create a label to jump to when we want to abort the query */
|
||||
addrEnd = sqlite3VdbeMakeLabel(v);
|
||||
@@ -4958,7 +4958,8 @@ int sqlite3Select(
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
|
||||
WHERE_GROUPBY, 0);
|
||||
WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0
|
||||
);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
|
||||
/* The optimizer is able to deliver rows in group by order so
|
||||
@@ -5023,6 +5024,21 @@ int sqlite3Select(
|
||||
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
|
||||
sAggInfo.useSortingIdx = 1;
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
|
||||
}
|
||||
|
||||
/* If the index or temporary table used by the GROUP BY sort
|
||||
** will naturally deliver rows in the order required by the ORDER BY
|
||||
** clause, cancel the ephemeral table open coded earlier.
|
||||
**
|
||||
** This is an optimization - the correct answer should result regardless.
|
||||
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to
|
||||
** disable this optimization for testing purposes. */
|
||||
if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder)
|
||||
&& (groupBySort || sqlite3WhereIsSorted(pWInfo))
|
||||
){
|
||||
sSort.pOrderBy = 0;
|
||||
sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
|
||||
}
|
||||
|
||||
/* Evaluate the current GROUP BY terms and store in b0, b1, b2...
|
||||
|
||||
+7
-3
@@ -697,7 +697,8 @@ static void output_csv(struct callback_data *p, const char *z, int bSep){
|
||||
*/
|
||||
static void interrupt_handler(int NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
seenInterrupt = 1;
|
||||
seenInterrupt++;
|
||||
if( seenInterrupt>2 ) exit(1);
|
||||
if( db ) sqlite3_interrupt(db);
|
||||
}
|
||||
#endif
|
||||
@@ -2430,6 +2431,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}
|
||||
nByte = strlen30(zSql);
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
csv_append_char(&sCsv, 0); /* To ensure sCsv.z is allocated */
|
||||
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
|
||||
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
|
||||
char cSep = '(';
|
||||
@@ -3027,6 +3029,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
|
||||
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
|
||||
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
|
||||
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
|
||||
};
|
||||
int testctrl = -1;
|
||||
int rc = 0;
|
||||
@@ -3067,9 +3070,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
break;
|
||||
|
||||
/* sqlite3_test_control(int) */
|
||||
case SQLITE_TESTCTRL_PRNG_SAVE:
|
||||
case SQLITE_TESTCTRL_PRNG_RESTORE:
|
||||
case SQLITE_TESTCTRL_PRNG_SAVE:
|
||||
case SQLITE_TESTCTRL_PRNG_RESTORE:
|
||||
case SQLITE_TESTCTRL_PRNG_RESET:
|
||||
case SQLITE_TESTCTRL_BYTEORDER:
|
||||
if( nArg==2 ){
|
||||
rc = sqlite3_test_control(testctrl);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
|
||||
|
||||
+41
-4
@@ -555,7 +555,10 @@ int sqlite3_exec(
|
||||
** file that were written at the application level might have changed
|
||||
** and that adjacent bytes, even bytes within the same sector are
|
||||
** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
|
||||
** flag indicate that a file cannot be deleted when open.
|
||||
** flag indicate that a file cannot be deleted when open. The
|
||||
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
|
||||
** read-only media and cannot be changed even by processes with
|
||||
** elevated privileges.
|
||||
*/
|
||||
#define SQLITE_IOCAP_ATOMIC 0x00000001
|
||||
#define SQLITE_IOCAP_ATOMIC512 0x00000002
|
||||
@@ -570,6 +573,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
|
||||
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
|
||||
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
|
||||
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
|
||||
|
||||
/*
|
||||
** CAPI3REF: File Locking Levels
|
||||
@@ -938,6 +942,12 @@ struct sqlite3_io_methods {
|
||||
** on whether or not the file has been renamed, moved, or deleted since it
|
||||
** was first opened.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_WIN32_SET_HANDLE]]
|
||||
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
|
||||
** opcode causes the xFileControl method to swap the file handle with the one
|
||||
** pointed to by the pArg argument. This capability is used during testing
|
||||
** and only needs to be supported when SQLITE_TEST is defined.
|
||||
**
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
@@ -961,6 +971,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_HAS_MOVED 20
|
||||
#define SQLITE_FCNTL_SYNC 21
|
||||
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
|
||||
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
|
||||
|
||||
/*
|
||||
** CAPI3REF: Mutex Handle
|
||||
@@ -2774,6 +2785,30 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
|
||||
** a URI filename, its value overrides any behavior requested by setting
|
||||
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
|
||||
**
|
||||
** <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or
|
||||
** "1") or "false" (or "off" or "no" or "0") to indicate that the
|
||||
** [powersafe overwrite] property does or does not apply to the
|
||||
** storage media on which the database file resides. ^The psow query
|
||||
** parameter only works for the built-in unix and Windows VFSes.
|
||||
**
|
||||
** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
|
||||
** which if set disables file locking in rollback journal modes. This
|
||||
** is useful for accessing a database on a filesystem that does not
|
||||
** support locking. Caution: Database corruption might result if two
|
||||
** or more processes write to the same database and any one of those
|
||||
** processes uses nolock=1.
|
||||
**
|
||||
** <li> <b>immutable</b>: ^The immutable parameter is a boolean query
|
||||
** parameter that indicates that the database file is stored on
|
||||
** read-only media. ^When immutable is set, SQLite assumes that the
|
||||
** database file cannot be changed, even by a process with higher
|
||||
** privilege, and so the database is opened read-only and all locking
|
||||
** and change detection is disabled. Caution: Setting the immutable
|
||||
** property on a database file that does in fact change can result
|
||||
** in incorrect query results and/or [SQLITE_CORRUPT] errors.
|
||||
** See also: [SQLITE_IOCAP_IMMUTABLE].
|
||||
**
|
||||
** </ul>
|
||||
**
|
||||
** ^Specifying an unknown parameter in the query component of a URI is not an
|
||||
@@ -2803,8 +2838,9 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** Open file "data.db" in the current directory for read-only access.
|
||||
** Regardless of whether or not shared-cache mode is enabled by
|
||||
** default, use a private cache.
|
||||
** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td>
|
||||
** Open file "/home/fred/data.db". Use the special VFS "unix-nolock".
|
||||
** <tr><td> file:/home/fred/data.db?vfs=unix-dotfile <td>
|
||||
** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile"
|
||||
** that uses dot-files in place of posix advisory locking.
|
||||
** <tr><td> file:data.db?mode=readonly <td>
|
||||
** An error. "readonly" is not a valid option for the "mode" parameter.
|
||||
** </table>
|
||||
@@ -6118,7 +6154,8 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
|
||||
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
|
||||
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
|
||||
#define SQLITE_TESTCTRL_LAST 21
|
||||
#define SQLITE_TESTCTRL_BYTEORDER 22
|
||||
#define SQLITE_TESTCTRL_LAST 22
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
|
||||
+53
-14
@@ -525,10 +525,10 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
|
||||
** gives a possible range of values of approximately 1.0e986 to 1e-986.
|
||||
** But the allowed values are "grainy". Not every value is representable.
|
||||
** For example, quantities 16 and 17 are both represented by a LogEst
|
||||
** of 40. However, since LogEst quantatites are suppose to be estimates,
|
||||
** of 40. However, since LogEst quantaties are suppose to be estimates,
|
||||
** not exact values, this imprecision is not a problem.
|
||||
**
|
||||
** "LogEst" is short for "Logarithimic Estimate".
|
||||
** "LogEst" is short for "Logarithmic Estimate".
|
||||
**
|
||||
** Examples:
|
||||
** 1 -> 0 20 -> 43 10000 -> 132
|
||||
@@ -546,22 +546,39 @@ typedef INT16_TYPE LogEst;
|
||||
|
||||
/*
|
||||
** Macros to determine whether the machine is big or little endian,
|
||||
** evaluated at runtime.
|
||||
** and whether or not that determination is run-time or compile-time.
|
||||
**
|
||||
** For best performance, an attempt is made to guess at the byte-order
|
||||
** using C-preprocessor macros. If that is unsuccessful, or if
|
||||
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
|
||||
** at run-time.
|
||||
*/
|
||||
#ifdef SQLITE_AMALGAMATION
|
||||
const int sqlite3one = 1;
|
||||
#else
|
||||
extern const int sqlite3one;
|
||||
#endif
|
||||
#if defined(i386) || defined(__i386__) || defined(_M_IX86)\
|
||||
|| defined(__x86_64) || defined(__x86_64__)
|
||||
#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
|
||||
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
|
||||
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
|
||||
defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER)
|
||||
# define SQLITE_BYTEORDER 1234
|
||||
# define SQLITE_BIGENDIAN 0
|
||||
# define SQLITE_LITTLEENDIAN 1
|
||||
# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
|
||||
#else
|
||||
#endif
|
||||
#if (defined(sparc) || defined(__ppc__)) \
|
||||
&& !defined(SQLITE_RUNTIME_BYTEORDER)
|
||||
# define SQLITE_BYTEORDER 4321
|
||||
# define SQLITE_BIGENDIAN 1
|
||||
# define SQLITE_LITTLEENDIAN 0
|
||||
# define SQLITE_UTF16NATIVE SQLITE_UTF16BE
|
||||
#endif
|
||||
#if !defined(SQLITE_BYTEORDER)
|
||||
# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
|
||||
# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
|
||||
# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
|
||||
# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
|
||||
# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1454,7 +1471,7 @@ struct Table {
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
ExprList *pCheck; /* All CHECK constraints */
|
||||
#endif
|
||||
tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
|
||||
LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
|
||||
int tnum; /* Root BTree node for this table (see note above) */
|
||||
i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
|
||||
i16 nCol; /* Number of columns in this table */
|
||||
@@ -1663,7 +1680,7 @@ struct UnpackedRecord {
|
||||
struct Index {
|
||||
char *zName; /* Name of this index */
|
||||
i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */
|
||||
tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
|
||||
LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */
|
||||
Table *pTable; /* The SQL table being indexed */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
Index *pNext; /* The next index associated with the same table */
|
||||
@@ -1677,7 +1694,7 @@ struct Index {
|
||||
u16 nKeyCol; /* Number of columns forming the key */
|
||||
u16 nColumn; /* Number of columns stored in the index */
|
||||
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
||||
unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
|
||||
unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
|
||||
unsigned bUnordered:1; /* Use this index for == or IN queries only */
|
||||
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
|
||||
unsigned isResized:1; /* True if resizeIndexObject() has been called */
|
||||
@@ -1690,6 +1707,16 @@ struct Index {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for Index.idxType
|
||||
*/
|
||||
#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */
|
||||
#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */
|
||||
#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */
|
||||
|
||||
/* Return true if index X is a PRIMARY KEY index */
|
||||
#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY)
|
||||
|
||||
/*
|
||||
** Each sample stored in the sqlite_stat3 table is represented in memory
|
||||
** using a structure of this type. See documentation at the top of the
|
||||
@@ -2108,6 +2135,7 @@ struct SrcList {
|
||||
#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */
|
||||
#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */
|
||||
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
|
||||
#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */
|
||||
|
||||
/* Allowed return values from sqlite3WhereIsDistinct()
|
||||
*/
|
||||
@@ -2691,11 +2719,10 @@ struct Sqlite3Config {
|
||||
int isMutexInit; /* True after mutexes are initialized */
|
||||
int isMallocInit; /* True after malloc is initialized */
|
||||
int isPCacheInit; /* True after malloc is initialized */
|
||||
sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */
|
||||
int nRefInitMutex; /* Number of users of pInitMutex */
|
||||
sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */
|
||||
void (*xLog)(void*,int,const char*); /* Function for logging */
|
||||
void *pLogArg; /* First argument to xLog() */
|
||||
int bLocaltimeFault; /* True to fail localtime() calls */
|
||||
#ifdef SQLITE_ENABLE_SQLLOG
|
||||
void(*xSqllog)(void*,sqlite3*,const char*, int);
|
||||
void *pSqllogArg;
|
||||
@@ -2707,6 +2734,10 @@ struct Sqlite3Config {
|
||||
void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */
|
||||
void *pVdbeBranchArg; /* 1st argument */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
|
||||
#endif
|
||||
int bLocaltimeFault; /* True to fail localtime() calls */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3008,6 +3039,12 @@ int sqlite3ParseUri(const char*,const char*,unsigned int*,
|
||||
Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
|
||||
int sqlite3CodeOnce(Parse *);
|
||||
|
||||
#ifdef SQLITE_OMIT_BUILTIN_TEST
|
||||
# define sqlite3FaultSim(X) SQLITE_OK
|
||||
#else
|
||||
int sqlite3FaultSim(int);
|
||||
#endif
|
||||
|
||||
Bitvec *sqlite3BitvecCreate(u32);
|
||||
int sqlite3BitvecTest(Bitvec*, u32);
|
||||
int sqlite3BitvecSet(Bitvec*, u32);
|
||||
@@ -3019,7 +3056,7 @@ int sqlite3BitvecBuiltinTest(int,int*);
|
||||
RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
|
||||
void sqlite3RowSetClear(RowSet*);
|
||||
void sqlite3RowSetInsert(RowSet*, i64);
|
||||
int sqlite3RowSetTest(RowSet*, u8 iBatch, i64);
|
||||
int sqlite3RowSetTest(RowSet*, int iBatch, i64);
|
||||
int sqlite3RowSetNext(RowSet*, i64*);
|
||||
|
||||
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
|
||||
@@ -3075,6 +3112,7 @@ void sqlite3WhereEnd(WhereInfo*);
|
||||
u64 sqlite3WhereOutputRowCount(WhereInfo*);
|
||||
int sqlite3WhereIsDistinct(WhereInfo*);
|
||||
int sqlite3WhereIsOrdered(WhereInfo*);
|
||||
int sqlite3WhereIsSorted(WhereInfo*);
|
||||
int sqlite3WhereContinueLabel(WhereInfo*);
|
||||
int sqlite3WhereBreakLabel(WhereInfo*);
|
||||
int sqlite3WhereOkOnePass(WhereInfo*, int*);
|
||||
@@ -3083,7 +3121,7 @@ void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
|
||||
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
||||
void sqlite3ExprCacheStore(Parse*, int, int, int);
|
||||
void sqlite3ExprCachePush(Parse*);
|
||||
void sqlite3ExprCachePop(Parse*, int);
|
||||
void sqlite3ExprCachePop(Parse*);
|
||||
void sqlite3ExprCacheRemove(Parse*, int, int);
|
||||
void sqlite3ExprCacheClear(Parse*);
|
||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||
@@ -3135,6 +3173,7 @@ int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
|
||||
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
|
||||
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
|
||||
void sqlite3ResolvePartIdxLabel(Parse*,int);
|
||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
|
||||
u8,u8,int,int*);
|
||||
void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
|
||||
|
||||
+54
@@ -14,6 +14,10 @@
|
||||
** testing of the SQLite library.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#if SQLITE_OS_WIN
|
||||
# include "os_win.h"
|
||||
#endif
|
||||
|
||||
#include "vdbeInt.h"
|
||||
#include "tcl.h"
|
||||
#include <stdlib.h>
|
||||
@@ -113,6 +117,16 @@ int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#if SQLITE_OS_WIN
|
||||
/*
|
||||
** Decode a Win32 HANDLE object.
|
||||
*/
|
||||
int getWin32Handle(Tcl_Interp *interp, const char *zA, LPHANDLE phFile){
|
||||
*phFile = (HANDLE)sqlite3TestTextToPtr(zA);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern const char *sqlite3ErrName(int);
|
||||
#define t1ErrorName sqlite3ErrName
|
||||
|
||||
@@ -5206,6 +5220,7 @@ static int file_control_lockproxy_test(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#if SQLITE_OS_WIN
|
||||
/*
|
||||
** tclcmd: file_control_win32_av_retry DB NRETRY DELAY
|
||||
**
|
||||
@@ -5239,6 +5254,42 @@ static int file_control_win32_av_retry(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_win32_set_handle DB HANDLE
|
||||
**
|
||||
** This TCL command runs the sqlite3_file_control interface with
|
||||
** the SQLITE_FCNTL_WIN32_SET_HANDLE opcode.
|
||||
*/
|
||||
static int file_control_win32_set_handle(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
HANDLE hFile = NULL;
|
||||
char z[100];
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " DB HANDLE", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getWin32Handle(interp, Tcl_GetString(objv[2]), &hFile) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_SET_HANDLE,
|
||||
(void*)&hFile);
|
||||
sqlite3_snprintf(sizeof(z), z, "%d %p", rc, (void*)hFile);
|
||||
Tcl_AppendResult(interp, z, (char*)0);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_persist_wal DB PERSIST-FLAG
|
||||
**
|
||||
@@ -6468,7 +6519,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
|
||||
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
|
||||
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
|
||||
#if SQLITE_OS_WIN
|
||||
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
|
||||
{ "file_control_win32_set_handle", file_control_win32_set_handle, 0 },
|
||||
#endif
|
||||
{ "file_control_persist_wal", file_control_persist_wal, 0 },
|
||||
{ "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
|
||||
{ "file_control_vfsname", file_control_vfsname, 0 },
|
||||
|
||||
+86
-2
@@ -568,7 +568,90 @@ static int testPendingByte(
|
||||
rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3FaultSim() callback:
|
||||
*/
|
||||
static Tcl_Interp *faultSimInterp = 0;
|
||||
static int faultSimScriptSize = 0;
|
||||
static char *faultSimScript;
|
||||
static int faultSimCallback(int x){
|
||||
char zInt[30];
|
||||
int i;
|
||||
int isNeg;
|
||||
int rc;
|
||||
if( x==0 ){
|
||||
memcpy(faultSimScript+faultSimScriptSize, "0", 2);
|
||||
}else{
|
||||
/* Convert x to text without using any sqlite3 routines */
|
||||
if( x<0 ){
|
||||
isNeg = 1;
|
||||
x = -x;
|
||||
}else{
|
||||
isNeg = 0;
|
||||
}
|
||||
zInt[sizeof(zInt)-1] = 0;
|
||||
for(i=sizeof(zInt)-2; i>0 && x>0; i--, x /= 10){
|
||||
zInt[i] = (x%10) + '0';
|
||||
}
|
||||
if( isNeg ) zInt[i--] = '-';
|
||||
memcpy(faultSimScript+faultSimScriptSize, zInt+i+1, sizeof(zInt)-i);
|
||||
}
|
||||
rc = Tcl_Eval(faultSimInterp, faultSimScript);
|
||||
if( rc ){
|
||||
fprintf(stderr, "fault simulator script failed: [%s]", faultSimScript);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
rc = atoi(Tcl_GetStringResult(faultSimInterp));
|
||||
}
|
||||
Tcl_ResetResult(faultSimInterp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_test_control_fault_install SCRIPT
|
||||
**
|
||||
** Arrange to invoke SCRIPT with the integer argument to sqlite3FaultSim()
|
||||
** appended, whenever sqlite3FaultSim() is called. Or, if SCRIPT is the
|
||||
** empty string, cancel the sqlite3FaultSim() callback.
|
||||
*/
|
||||
static int faultInstallCmd(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
const char *zScript;
|
||||
int nScript;
|
||||
int rc;
|
||||
if( argc!=1 && argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" SCRIPT\"", (void*)0);
|
||||
}
|
||||
zScript = argc==2 ? argv[1] : "";
|
||||
nScript = (int)strlen(zScript);
|
||||
if( faultSimScript ){
|
||||
free(faultSimScript);
|
||||
faultSimScript = 0;
|
||||
}
|
||||
if( nScript==0 ){
|
||||
rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, 0);
|
||||
}else{
|
||||
faultSimScript = malloc( nScript+100 );
|
||||
if( faultSimScript==0 ){
|
||||
Tcl_AppendResult(interp, "out of memory", (void*)0);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
memcpy(faultSimScript, zScript, nScript);
|
||||
faultSimScript[nScript] = ' ';
|
||||
faultSimScriptSize = nScript+1;
|
||||
faultSimInterp = interp;
|
||||
rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, faultSimCallback);
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3BitvecBuiltinTest SIZE PROGRAM
|
||||
@@ -638,7 +721,8 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
|
||||
{ "fake_big_file", (Tcl_CmdProc*)fake_big_file },
|
||||
#endif
|
||||
{ "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest },
|
||||
{ "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte },
|
||||
{ "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte },
|
||||
{ "sqlite3_test_control_fault_install", (Tcl_CmdProc*)faultInstallCmd },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ void sqlite3BtreeCursorList(Btree *p){
|
||||
BtShared *pBt = p->pBt;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
MemPage *pPage = pCur->apPage[pCur->iPage];
|
||||
char *zMode = pCur->wrFlag ? "rw" : "ro";
|
||||
char *zMode = (pCur->curFlags & BTCF_WriteFlag) ? "rw" : "ro";
|
||||
sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
|
||||
pCur, pCur->pgnoRoot, zMode,
|
||||
pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage],
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#include "sqliteLimit.h"
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#if SQLITE_OS_WIN
|
||||
# include "os_win.h"
|
||||
#endif
|
||||
|
||||
#include "tcl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
+6
-1
@@ -70,6 +70,12 @@
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
#include "os_setup.h"
|
||||
#if SQLITE_OS_WIN
|
||||
# include "os_win.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -221,7 +227,6 @@ static sqlite3_uint64 vfslog_time(){
|
||||
return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
|
||||
}
|
||||
#elif SQLITE_OS_WIN
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
static sqlite3_uint64 vfslog_time(){
|
||||
FILETIME ft;
|
||||
|
||||
+2
-38
@@ -44,49 +44,13 @@
|
||||
#define sqlite3_mutex_notheld(X) ((void)(X),1)
|
||||
#endif /* SQLITE_THREADSAFE==0 */
|
||||
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows, or some other
|
||||
** operating system. After the following block of preprocess macros,
|
||||
** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, and SQLITE_OS_OTHER
|
||||
** will defined to either 1 or 0. One of the four will be 1. The other
|
||||
** three will be 0.
|
||||
*/
|
||||
#if defined(SQLITE_OS_OTHER)
|
||||
# if SQLITE_OS_OTHER==1
|
||||
# undef SQLITE_OS_UNIX
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# undef SQLITE_OS_WIN
|
||||
# define SQLITE_OS_WIN 0
|
||||
# else
|
||||
# undef SQLITE_OS_OTHER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
|
||||
# define SQLITE_OS_OTHER 0
|
||||
# ifndef SQLITE_OS_WIN
|
||||
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) \
|
||||
|| defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define SQLITE_OS_WIN 1
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# else
|
||||
# define SQLITE_OS_WIN 0
|
||||
# define SQLITE_OS_UNIX 1
|
||||
# endif
|
||||
# else
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# endif
|
||||
#else
|
||||
# ifndef SQLITE_OS_WIN
|
||||
# define SQLITE_OS_WIN 0
|
||||
# endif
|
||||
#endif
|
||||
#include "os_setup.h"
|
||||
|
||||
#if SQLITE_OS_UNIX
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if SQLITE_OS_WIN
|
||||
# include <windows.h>
|
||||
# include "os_win.h"
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -31,12 +31,6 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if SQLITE_OS_UNIX
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if SQLITE_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Make this callable from C++ */
|
||||
#ifdef __cplusplus
|
||||
|
||||
+183
-17
@@ -35,6 +35,8 @@ struct Circle {
|
||||
double centerx;
|
||||
double centery;
|
||||
double radius;
|
||||
double mxArea;
|
||||
int eScoreType;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -50,11 +52,7 @@ static void circle_del(void *p){
|
||||
static int circle_geom(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_int64 *aCoord,
|
||||
#else
|
||||
double *aCoord,
|
||||
#endif
|
||||
sqlite3_rtree_dbl *aCoord,
|
||||
int *pRes
|
||||
){
|
||||
int i; /* Iterator variable */
|
||||
@@ -62,7 +60,12 @@ static int circle_geom(
|
||||
double xmin, xmax; /* X dimensions of box being tested */
|
||||
double ymin, ymax; /* X dimensions of box being tested */
|
||||
|
||||
if( p->pUser==0 ){
|
||||
xmin = aCoord[0];
|
||||
xmax = aCoord[1];
|
||||
ymin = aCoord[2];
|
||||
ymax = aCoord[3];
|
||||
pCircle = (Circle *)p->pUser;
|
||||
if( pCircle==0 ){
|
||||
/* If pUser is still 0, then the parameter values have not been tested
|
||||
** for correctness or stored into a Circle structure yet. Do this now. */
|
||||
|
||||
@@ -108,14 +111,9 @@ static int circle_geom(
|
||||
pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
|
||||
pCircle->aBox[1].ymin = pCircle->centery;
|
||||
pCircle->aBox[1].ymax = pCircle->centery;
|
||||
pCircle->mxArea = (xmax - xmin)*(ymax - ymin) + 1.0;
|
||||
}
|
||||
|
||||
pCircle = (Circle *)p->pUser;
|
||||
xmin = aCoord[0];
|
||||
xmax = aCoord[1];
|
||||
ymin = aCoord[2];
|
||||
ymax = aCoord[3];
|
||||
|
||||
/* Check if any of the 4 corners of the bounding-box being tested lie
|
||||
** inside the circular region. If they do, then the bounding-box does
|
||||
** intersect the region of interest. Set the output variable to true and
|
||||
@@ -154,6 +152,170 @@ static int circle_geom(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of "circle" r-tree geometry callback using the
|
||||
** 2nd-generation interface that allows scoring.
|
||||
*/
|
||||
static int circle_query_func(sqlite3_rtree_query_info *p){
|
||||
int i; /* Iterator variable */
|
||||
Circle *pCircle; /* Structure defining circular region */
|
||||
double xmin, xmax; /* X dimensions of box being tested */
|
||||
double ymin, ymax; /* X dimensions of box being tested */
|
||||
int nWithin = 0; /* Number of corners inside the circle */
|
||||
|
||||
xmin = p->aCoord[0];
|
||||
xmax = p->aCoord[1];
|
||||
ymin = p->aCoord[2];
|
||||
ymax = p->aCoord[3];
|
||||
pCircle = (Circle *)p->pUser;
|
||||
if( pCircle==0 ){
|
||||
/* If pUser is still 0, then the parameter values have not been tested
|
||||
** for correctness or stored into a Circle structure yet. Do this now. */
|
||||
|
||||
/* This geometry callback is for use with a 2-dimensional r-tree table.
|
||||
** Return an error if the table does not have exactly 2 dimensions. */
|
||||
if( p->nCoord!=4 ) return SQLITE_ERROR;
|
||||
|
||||
/* Test that the correct number of parameters (4) have been supplied,
|
||||
** and that the parameters are in range (that the radius of the circle
|
||||
** radius is greater than zero). */
|
||||
if( p->nParam!=4 || p->aParam[2]<0.0 ) return SQLITE_ERROR;
|
||||
|
||||
/* Allocate a structure to cache parameter data in. Return SQLITE_NOMEM
|
||||
** if the allocation fails. */
|
||||
pCircle = (Circle *)(p->pUser = sqlite3_malloc(sizeof(Circle)));
|
||||
if( !pCircle ) return SQLITE_NOMEM;
|
||||
p->xDelUser = circle_del;
|
||||
|
||||
/* Record the center and radius of the circular region. One way that
|
||||
** tested bounding boxes that intersect the circular region are detected
|
||||
** is by testing if each corner of the bounding box lies within radius
|
||||
** units of the center of the circle. */
|
||||
pCircle->centerx = p->aParam[0];
|
||||
pCircle->centery = p->aParam[1];
|
||||
pCircle->radius = p->aParam[2];
|
||||
pCircle->eScoreType = (int)p->aParam[3];
|
||||
|
||||
/* Define two bounding box regions. The first, aBox[0], extends to
|
||||
** infinity in the X dimension. It covers the same range of the Y dimension
|
||||
** as the circular region. The second, aBox[1], extends to infinity in
|
||||
** the Y dimension and is constrained to the range of the circle in the
|
||||
** X dimension.
|
||||
**
|
||||
** Then imagine each box is split in half along its short axis by a line
|
||||
** that intersects the center of the circular region. A bounding box
|
||||
** being tested can be said to intersect the circular region if it contains
|
||||
** points from each half of either of the two infinite bounding boxes.
|
||||
*/
|
||||
pCircle->aBox[0].xmin = pCircle->centerx;
|
||||
pCircle->aBox[0].xmax = pCircle->centerx;
|
||||
pCircle->aBox[0].ymin = pCircle->centery + pCircle->radius;
|
||||
pCircle->aBox[0].ymax = pCircle->centery - pCircle->radius;
|
||||
pCircle->aBox[1].xmin = pCircle->centerx + pCircle->radius;
|
||||
pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
|
||||
pCircle->aBox[1].ymin = pCircle->centery;
|
||||
pCircle->aBox[1].ymax = pCircle->centery;
|
||||
pCircle->mxArea = 200.0*200.0;
|
||||
}
|
||||
|
||||
/* Check if any of the 4 corners of the bounding-box being tested lie
|
||||
** inside the circular region. If they do, then the bounding-box does
|
||||
** intersect the region of interest. Set the output variable to true and
|
||||
** return SQLITE_OK in this case. */
|
||||
for(i=0; i<4; i++){
|
||||
double x = (i&0x01) ? xmax : xmin;
|
||||
double y = (i&0x02) ? ymax : ymin;
|
||||
double d2;
|
||||
|
||||
d2 = (x-pCircle->centerx)*(x-pCircle->centerx);
|
||||
d2 += (y-pCircle->centery)*(y-pCircle->centery);
|
||||
if( d2<(pCircle->radius*pCircle->radius) ) nWithin++;
|
||||
}
|
||||
|
||||
/* Check if the bounding box covers any other part of the circular region.
|
||||
** See comments above for a description of how this test works. If it does
|
||||
** cover part of the circular region, set the output variable to true
|
||||
** and return SQLITE_OK. */
|
||||
if( nWithin==0 ){
|
||||
for(i=0; i<2; i++){
|
||||
if( xmin<=pCircle->aBox[i].xmin
|
||||
&& xmax>=pCircle->aBox[i].xmax
|
||||
&& ymin<=pCircle->aBox[i].ymin
|
||||
&& ymax>=pCircle->aBox[i].ymax
|
||||
){
|
||||
nWithin = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pCircle->eScoreType==1 ){
|
||||
/* Depth first search */
|
||||
p->rScore = p->iLevel;
|
||||
}else if( pCircle->eScoreType==2 ){
|
||||
/* Breadth first search */
|
||||
p->rScore = 100 - p->iLevel;
|
||||
}else if( pCircle->eScoreType==3 ){
|
||||
/* Depth-first search, except sort the leaf nodes by area with
|
||||
** the largest area first */
|
||||
if( p->iLevel==1 ){
|
||||
p->rScore = 1.0 - (xmax-xmin)*(ymax-ymin)/pCircle->mxArea;
|
||||
if( p->rScore<0.01 ) p->rScore = 0.01;
|
||||
}else{
|
||||
p->rScore = 0.0;
|
||||
}
|
||||
}else if( pCircle->eScoreType==4 ){
|
||||
/* Depth-first search, except exclude odd rowids */
|
||||
p->rScore = p->iLevel;
|
||||
if( p->iRowid&1 ) nWithin = 0;
|
||||
}else{
|
||||
/* Breadth-first search, except exclude odd rowids */
|
||||
p->rScore = 100 - p->iLevel;
|
||||
if( p->iRowid&1 ) nWithin = 0;
|
||||
}
|
||||
if( nWithin==0 ){
|
||||
p->eWithin = NOT_WITHIN;
|
||||
}else if( nWithin>=4 ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else{
|
||||
p->eWithin = PARTLY_WITHIN;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
/*
|
||||
** Implementation of "breadthfirstsearch" r-tree geometry callback using the
|
||||
** 2nd-generation interface that allows scoring.
|
||||
**
|
||||
** ... WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ...
|
||||
**
|
||||
** It returns all entries whose bounding boxes overlap with $x0,$x1,$y0,$y1.
|
||||
*/
|
||||
static int bfs_query_func(sqlite3_rtree_query_info *p){
|
||||
double x0,x1,y0,y1; /* Dimensions of box being tested */
|
||||
double bx0,bx1,by0,by1; /* Boundary of the query function */
|
||||
|
||||
if( p->nParam!=4 ) return SQLITE_ERROR;
|
||||
x0 = p->aCoord[0];
|
||||
x1 = p->aCoord[1];
|
||||
y0 = p->aCoord[2];
|
||||
y1 = p->aCoord[3];
|
||||
bx0 = p->aParam[0];
|
||||
bx1 = p->aParam[1];
|
||||
by0 = p->aParam[2];
|
||||
by1 = p->aParam[3];
|
||||
p->rScore = 100 - p->iLevel;
|
||||
if( p->eParentWithin==FULLY_WITHIN ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else if( x0>=bx0 && x1<=bx1 && y0>=by0 && y1<=by1 ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else if( x1>=bx0 && x0<=bx1 && y1>=by0 && y0<=by1 ){
|
||||
p->eWithin = PARTLY_WITHIN;
|
||||
}else{
|
||||
p->eWithin = NOT_WITHIN;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* END of implementation of "circle" geometry callback.
|
||||
**************************************************************************
|
||||
*************************************************************************/
|
||||
@@ -194,11 +356,7 @@ static int gHere = 42;
|
||||
static int cube_geom(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_int64 *aCoord,
|
||||
#else
|
||||
double *aCoord,
|
||||
#endif
|
||||
sqlite3_rtree_dbl *aCoord,
|
||||
int *piRes
|
||||
){
|
||||
Cube *pCube = (Cube *)p->pUser;
|
||||
@@ -293,6 +451,14 @@ static int register_circle_geom(
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_rtree_geometry_callback(db, "circle", circle_geom, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_rtree_query_callback(db, "Qcircle",
|
||||
circle_query_func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_rtree_query_callback(db, "breadthfirstsearch",
|
||||
bfs_query_func, 0, 0);
|
||||
}
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
|
||||
+53
-20
@@ -127,8 +127,10 @@ struct Testvfs {
|
||||
#define TESTVFS_FULLPATHNAME_MASK 0x00008000
|
||||
#define TESTVFS_READ_MASK 0x00010000
|
||||
#define TESTVFS_UNLOCK_MASK 0x00020000
|
||||
#define TESTVFS_LOCK_MASK 0x00040000
|
||||
#define TESTVFS_CKLOCK_MASK 0x00080000
|
||||
|
||||
#define TESTVFS_ALL_MASK 0x0003FFFF
|
||||
#define TESTVFS_ALL_MASK 0x000FFFFF
|
||||
|
||||
|
||||
#define TESTVFS_MAX_PAGES 1024
|
||||
@@ -466,8 +468,15 @@ static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
** Lock an tvfs-file.
|
||||
*/
|
||||
static int tvfsLock(sqlite3_file *pFile, int eLock){
|
||||
TestvfsFd *p = tvfsGetFd(pFile);
|
||||
return sqlite3OsLock(p->pReal, eLock);
|
||||
TestvfsFd *pFd = tvfsGetFd(pFile);
|
||||
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||
if( p->pScript && p->mask&TESTVFS_LOCK_MASK ){
|
||||
char zLock[30];
|
||||
sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock);
|
||||
tvfsExecTcl(p, "xLock", Tcl_NewStringObj(pFd->zFilename, -1),
|
||||
Tcl_NewStringObj(zLock, -1), 0, 0);
|
||||
}
|
||||
return sqlite3OsLock(pFd->pReal, eLock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -476,6 +485,12 @@ static int tvfsLock(sqlite3_file *pFile, int eLock){
|
||||
static int tvfsUnlock(sqlite3_file *pFile, int eLock){
|
||||
TestvfsFd *pFd = tvfsGetFd(pFile);
|
||||
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||
if( p->pScript && p->mask&TESTVFS_UNLOCK_MASK ){
|
||||
char zLock[30];
|
||||
sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock);
|
||||
tvfsExecTcl(p, "xUnlock", Tcl_NewStringObj(pFd->zFilename, -1),
|
||||
Tcl_NewStringObj(zLock, -1), 0, 0);
|
||||
}
|
||||
if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){
|
||||
return SQLITE_IOERR_UNLOCK;
|
||||
}
|
||||
@@ -486,8 +501,13 @@ static int tvfsUnlock(sqlite3_file *pFile, int eLock){
|
||||
** Check if another file-handle holds a RESERVED lock on an tvfs-file.
|
||||
*/
|
||||
static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
TestvfsFd *p = tvfsGetFd(pFile);
|
||||
return sqlite3OsCheckReservedLock(p->pReal, pResOut);
|
||||
TestvfsFd *pFd = tvfsGetFd(pFile);
|
||||
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||
if( p->pScript && p->mask&TESTVFS_CKLOCK_MASK ){
|
||||
tvfsExecTcl(p, "xCheckReservedLock", Tcl_NewStringObj(pFd->zFilename, -1),
|
||||
0, 0, 0);
|
||||
}
|
||||
return sqlite3OsCheckReservedLock(pFd->pReal, pResOut);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1111,26 +1131,32 @@ static int testvfs_obj_cmd(
|
||||
break;
|
||||
}
|
||||
|
||||
/* TESTVFS filter METHOD-LIST
|
||||
**
|
||||
** Activate special processing for those methods contained in the list
|
||||
*/
|
||||
case CMD_FILTER: {
|
||||
static struct VfsMethod {
|
||||
char *zName;
|
||||
int mask;
|
||||
} vfsmethod [] = {
|
||||
{ "xShmOpen", TESTVFS_SHMOPEN_MASK },
|
||||
{ "xShmLock", TESTVFS_SHMLOCK_MASK },
|
||||
{ "xShmBarrier", TESTVFS_SHMBARRIER_MASK },
|
||||
{ "xShmUnmap", TESTVFS_SHMCLOSE_MASK },
|
||||
{ "xShmMap", TESTVFS_SHMMAP_MASK },
|
||||
{ "xSync", TESTVFS_SYNC_MASK },
|
||||
{ "xDelete", TESTVFS_DELETE_MASK },
|
||||
{ "xWrite", TESTVFS_WRITE_MASK },
|
||||
{ "xRead", TESTVFS_READ_MASK },
|
||||
{ "xTruncate", TESTVFS_TRUNCATE_MASK },
|
||||
{ "xOpen", TESTVFS_OPEN_MASK },
|
||||
{ "xClose", TESTVFS_CLOSE_MASK },
|
||||
{ "xAccess", TESTVFS_ACCESS_MASK },
|
||||
{ "xFullPathname", TESTVFS_FULLPATHNAME_MASK },
|
||||
{ "xUnlock", TESTVFS_UNLOCK_MASK },
|
||||
{ "xShmOpen", TESTVFS_SHMOPEN_MASK },
|
||||
{ "xShmLock", TESTVFS_SHMLOCK_MASK },
|
||||
{ "xShmBarrier", TESTVFS_SHMBARRIER_MASK },
|
||||
{ "xShmUnmap", TESTVFS_SHMCLOSE_MASK },
|
||||
{ "xShmMap", TESTVFS_SHMMAP_MASK },
|
||||
{ "xSync", TESTVFS_SYNC_MASK },
|
||||
{ "xDelete", TESTVFS_DELETE_MASK },
|
||||
{ "xWrite", TESTVFS_WRITE_MASK },
|
||||
{ "xRead", TESTVFS_READ_MASK },
|
||||
{ "xTruncate", TESTVFS_TRUNCATE_MASK },
|
||||
{ "xOpen", TESTVFS_OPEN_MASK },
|
||||
{ "xClose", TESTVFS_CLOSE_MASK },
|
||||
{ "xAccess", TESTVFS_ACCESS_MASK },
|
||||
{ "xFullPathname", TESTVFS_FULLPATHNAME_MASK },
|
||||
{ "xUnlock", TESTVFS_UNLOCK_MASK },
|
||||
{ "xLock", TESTVFS_LOCK_MASK },
|
||||
{ "xCheckReservedLock", TESTVFS_CKLOCK_MASK },
|
||||
};
|
||||
Tcl_Obj **apElem = 0;
|
||||
int nElem = 0;
|
||||
@@ -1162,6 +1188,12 @@ static int testvfs_obj_cmd(
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** TESTVFS script ?SCRIPT?
|
||||
**
|
||||
** Query or set the script to be run when filtered VFS events
|
||||
** occur.
|
||||
*/
|
||||
case CMD_SCRIPT: {
|
||||
if( objc==3 ){
|
||||
int nByte;
|
||||
@@ -1248,6 +1280,7 @@ static int testvfs_obj_cmd(
|
||||
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND },
|
||||
{ "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN },
|
||||
{ "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
|
||||
{ "immutable", SQLITE_IOCAP_IMMUTABLE },
|
||||
{ 0, 0 }
|
||||
};
|
||||
Tcl_Obj *pRet;
|
||||
|
||||
+1
-1
@@ -678,7 +678,7 @@ static int vfstraceAccess(
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
|
||||
vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
|
||||
pInfo->zVfsName, zPath, flags);
|
||||
rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
|
||||
vfstrace_print_errcode(pInfo, " -> %s", rc);
|
||||
|
||||
+1
-1
@@ -187,7 +187,7 @@ void sqlite3Update(
|
||||
iIdxCur = iDataCur+1;
|
||||
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
|
||||
if( pIdx->autoIndex==2 && pPk!=0 ){
|
||||
if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){
|
||||
iDataCur = pParse->nTab;
|
||||
pTabList->a[0].iCursor = iDataCur;
|
||||
}
|
||||
|
||||
+20
-2
@@ -31,6 +31,24 @@ void sqlite3Coverage(int x){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Give a callback to the test harness that can be used to simulate faults
|
||||
** in places where it is difficult or expensive to do so purely by means
|
||||
** of inputs.
|
||||
**
|
||||
** The intent of the integer argument is to let the fault simulator know
|
||||
** which of multiple sqlite3FaultSim() calls has been hit.
|
||||
**
|
||||
** Return whatever integer value the test callback returns, or return
|
||||
** SQLITE_OK if no test callback is installed.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
int sqlite3FaultSim(int iTest){
|
||||
int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback;
|
||||
return xCallback ? xCallback(iTest) : SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** Return true if the floating point value is Not a Number (NaN).
|
||||
@@ -1246,8 +1264,8 @@ LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert an integer into a LogEst. In other words, compute a
|
||||
** good approximatation for 10*log2(x).
|
||||
** Convert an integer into a LogEst. In other words, compute an
|
||||
** approximation for 10*log2(x).
|
||||
*/
|
||||
LogEst sqlite3LogEst(u64 x){
|
||||
static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
|
||||
|
||||
+9
-10
@@ -3464,7 +3464,7 @@ case OP_Close: {
|
||||
** is greater than or equal to the key value. If there are no records
|
||||
** greater than or equal to the key and P2 is not zero, then jump to P2.
|
||||
**
|
||||
** See also: Found, NotFound, Distinct, SeekLt, SeekGt, SeekLe
|
||||
** See also: Found, NotFound, SeekLt, SeekGt, SeekLe
|
||||
*/
|
||||
/* Opcode: SeekGt P1 P2 P3 P4 *
|
||||
** Synopsis: key=r[P3@P4]
|
||||
@@ -3478,7 +3478,7 @@ case OP_Close: {
|
||||
** is greater than the key value. If there are no records greater than
|
||||
** the key and P2 is not zero, then jump to P2.
|
||||
**
|
||||
** See also: Found, NotFound, Distinct, SeekLt, SeekGe, SeekLe
|
||||
** See also: Found, NotFound, SeekLt, SeekGe, SeekLe
|
||||
*/
|
||||
/* Opcode: SeekLt P1 P2 P3 P4 *
|
||||
** Synopsis: key=r[P3@P4]
|
||||
@@ -3492,7 +3492,7 @@ case OP_Close: {
|
||||
** is less than the key value. If there are no records less than
|
||||
** the key and P2 is not zero, then jump to P2.
|
||||
**
|
||||
** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLe
|
||||
** See also: Found, NotFound, SeekGt, SeekGe, SeekLe
|
||||
*/
|
||||
/* Opcode: SeekLe P1 P2 P3 P4 *
|
||||
** Synopsis: key=r[P3@P4]
|
||||
@@ -3506,7 +3506,7 @@ case OP_Close: {
|
||||
** is less than or equal to the key value. If there are no records
|
||||
** less than or equal to the key and P2 is not zero, then jump to P2.
|
||||
**
|
||||
** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLt
|
||||
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
|
||||
*/
|
||||
case OP_SeekLT: /* jump, in3 */
|
||||
case OP_SeekLE: /* jump, in3 */
|
||||
@@ -4232,6 +4232,7 @@ case OP_SorterData: {
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( isSorter(pC) );
|
||||
rc = sqlite3VdbeSorterRowkey(pC, pOut);
|
||||
assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5227,9 +5228,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
||||
assert( pOp->p4type==P4_INT32 );
|
||||
assert( iSet==-1 || iSet>=0 );
|
||||
if( iSet ){
|
||||
exists = sqlite3RowSetTest(pIn1->u.pRowSet,
|
||||
(u8)(iSet>=0 ? iSet & 0xf : 0xff),
|
||||
pIn3->u.i);
|
||||
exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
|
||||
VdbeBranchTaken(exists!=0,2);
|
||||
if( exists ){
|
||||
pc = pOp->p2 - 1;
|
||||
@@ -6282,7 +6281,7 @@ case OP_Init: { /* jump */
|
||||
if( zTrace ){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( MASKBIT(i) & p->btreeMask)==0 ) continue;
|
||||
if( (MASKBIT(i) & p->btreeMask)==0 ) continue;
|
||||
sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
|
||||
}
|
||||
}
|
||||
@@ -6325,8 +6324,8 @@ default: { /* This is really OP_Noop and OP_Explain */
|
||||
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
u64 elapsed = sqlite3Hwtime() - start;
|
||||
pOp->cycles += elapsed;
|
||||
u64 endTime = sqlite3Hwtime();
|
||||
if( endTime>start ) pOp->cycles += endTime - start;
|
||||
pOp->cnt++;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -276,7 +276,7 @@ void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
||||
int j = -1-x;
|
||||
assert( v->magic==VDBE_MAGIC_INIT );
|
||||
assert( j<p->nLabel );
|
||||
if( j>=0 && p->aLabel ){
|
||||
if( ALWAYS(j>=0) && p->aLabel ){
|
||||
p->aLabel[j] = v->nOp;
|
||||
}
|
||||
p->iFixedOp = v->nOp - 1;
|
||||
|
||||
+1
-3
@@ -77,9 +77,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
||||
p->iOffset = pC->aType[p->iCol + pC->nField];
|
||||
p->nByte = sqlite3VdbeSerialTypeLen(type);
|
||||
p->pCsr = pC->pCursor;
|
||||
sqlite3BtreeEnterCursor(p->pCsr);
|
||||
sqlite3BtreeCacheOverflow(p->pCsr);
|
||||
sqlite3BtreeLeaveCursor(p->pCsr);
|
||||
sqlite3BtreeIncrblobCursor(p->pCsr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +350,6 @@ static int vdbeSorterIterInit(
|
||||
rc = sqlite3OsRead(
|
||||
pSorter->pTemp1, &pIter->aBuffer[iBuf], nRead, iStart
|
||||
);
|
||||
assert( rc!=SQLITE_IOERR_SHORT_READ );
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
+438
-200
File diff suppressed because it is too large
Load Diff
@@ -398,6 +398,7 @@ struct WhereInfo {
|
||||
LogEst nRowOut; /* Estimated number of output rows */
|
||||
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
|
||||
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
|
||||
u8 sorted; /* True if really sorted (not just grouped) */
|
||||
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
|
||||
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
||||
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
|
||||
@@ -457,3 +458,4 @@ struct WhereInfo {
|
||||
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
|
||||
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
|
||||
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
|
||||
#define WHERE_LIKELIHOOD 0x00020000 /* A likelihood() is affecting nOut */
|
||||
|
||||
@@ -875,4 +875,42 @@ do_execsql_test alter-16.2 {
|
||||
SELECT * FROM t16a_rn ORDER BY a;
|
||||
} {abc 1.25 99 xyzzy cba 5.5 98 fizzle}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Verify that NULL values into the internal-use-only sqlite_rename_*()
|
||||
# functions do not cause problems.
|
||||
#
|
||||
do_execsql_test alter-17.1 {
|
||||
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)','abc');
|
||||
} {{CREATE TABLE "abc"(a,b,c)}}
|
||||
do_execsql_test alter-17.2 {
|
||||
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)',NULL);
|
||||
} {{CREATE TABLE "(NULL)"(a,b,c)}}
|
||||
do_execsql_test alter-17.3 {
|
||||
SELECT sqlite_rename_table(NULL,'abc');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.4 {
|
||||
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN','abc');
|
||||
} {{CREATE TRIGGER r1 ON "abc" WHEN}}
|
||||
do_execsql_test alter-17.5 {
|
||||
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN',NULL);
|
||||
} {{CREATE TRIGGER r1 ON "(NULL)" WHEN}}
|
||||
do_execsql_test alter-17.6 {
|
||||
SELECT sqlite_rename_trigger(NULL,'abc');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.7 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
'xyzzy','lmnop');
|
||||
} {{CREATE TABLE t1(a REFERENCES "lmnop")}}
|
||||
do_execsql_test alter-17.8 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
'xyzzy',NULL);
|
||||
} {{CREATE TABLE t1(a REFERENCES "(NULL)")}}
|
||||
do_execsql_test alter-17.9 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
NULL, 'lmnop');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.10 {
|
||||
SELECT sqlite_rename_parent(NULL,'abc','xyz');
|
||||
} {{}}
|
||||
|
||||
finish_test
|
||||
|
||||
+30
-12
@@ -103,12 +103,21 @@ do_test analyze3-1.1.1 {
|
||||
}
|
||||
} {1}
|
||||
|
||||
do_execsql_test analyze3-1.1.x {
|
||||
SELECT count(*) FROM t1 WHERE x>200 AND x<300;
|
||||
SELECT count(*) FROM t1 WHERE x>0 AND x<1100;
|
||||
} {99 1000}
|
||||
|
||||
# The first of the following two SELECT statements visits 99 rows. So
|
||||
# it is better to use the index. But the second visits every row in
|
||||
# the table (1000 in total) so it is better to do a full-table scan.
|
||||
#
|
||||
do_eqp_test analyze3-1.1.2 {
|
||||
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
|
||||
do_eqp_test analyze3-1.1.3 {
|
||||
SELECT sum(y) FROM t1 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
|
||||
} {0 0 0 {SCAN TABLE t1}}
|
||||
|
||||
do_test analyze3-1.1.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 }
|
||||
@@ -125,17 +134,17 @@ do_test analyze3-1.1.6 {
|
||||
} {199 0 14850}
|
||||
do_test analyze3-1.1.7 {
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
do_test analyze3-1.1.8 {
|
||||
set l [string range "0" 0 end]
|
||||
set u [string range "1100" 0 end]
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
do_test analyze3-1.1.9 {
|
||||
set l [expr int(0)]
|
||||
set u [expr int(1100)]
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
|
||||
|
||||
# The following tests are similar to the block above. The difference is
|
||||
@@ -152,12 +161,17 @@ do_test analyze3-1.2.1 {
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
do_execsql_test analyze3-2.1.x {
|
||||
SELECT count(*) FROM t2 WHERE x>1 AND x<2;
|
||||
SELECT count(*) FROM t2 WHERE x>0 AND x<99;
|
||||
} {200 990}
|
||||
do_eqp_test analyze3-1.2.2 {
|
||||
SELECT sum(y) FROM t2 WHERE x>1 AND x<2
|
||||
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}}
|
||||
do_eqp_test analyze3-1.2.3 {
|
||||
SELECT sum(y) FROM t2 WHERE x>0 AND x<99
|
||||
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}}
|
||||
} {0 0 0 {SCAN TABLE t2}}
|
||||
|
||||
do_test analyze3-1.2.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 }
|
||||
} {161 0 4760}
|
||||
@@ -173,17 +187,17 @@ do_test analyze3-1.2.6 {
|
||||
} {161 0 integer integer 4760}
|
||||
do_test analyze3-1.2.7 {
|
||||
sf_execsql { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 }
|
||||
} {1981 0 490555}
|
||||
} {999 999 490555}
|
||||
do_test analyze3-1.2.8 {
|
||||
set l [string range "0" 0 end]
|
||||
set u [string range "99" 0 end]
|
||||
sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u}
|
||||
} {1981 0 text text 490555}
|
||||
} {999 999 text text 490555}
|
||||
do_test analyze3-1.2.9 {
|
||||
set l [expr int(0)]
|
||||
set u [expr int(99)]
|
||||
sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u}
|
||||
} {1981 0 integer integer 490555}
|
||||
} {999 999 integer integer 490555}
|
||||
|
||||
# Same tests a third time. This time, column x has INTEGER affinity and
|
||||
# is not the leftmost column of the table. This triggered a bug causing
|
||||
@@ -199,12 +213,16 @@ do_test analyze3-1.3.1 {
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
do_execsql_test analyze3-1.3.x {
|
||||
SELECT count(*) FROM t3 WHERE x>200 AND x<300;
|
||||
SELECT count(*) FROM t3 WHERE x>0 AND x<1100
|
||||
} {99 1000}
|
||||
do_eqp_test analyze3-1.3.2 {
|
||||
SELECT sum(y) FROM t3 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}}
|
||||
do_eqp_test analyze3-1.3.3 {
|
||||
SELECT sum(y) FROM t3 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}}
|
||||
} {0 0 0 {SCAN TABLE t3}}
|
||||
|
||||
do_test analyze3-1.3.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 }
|
||||
@@ -221,17 +239,17 @@ do_test analyze3-1.3.6 {
|
||||
} {199 0 14850}
|
||||
do_test analyze3-1.3.7 {
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
do_test analyze3-1.3.8 {
|
||||
set l [string range "0" 0 end]
|
||||
set u [string range "1100" 0 end]
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
do_test analyze3-1.3.9 {
|
||||
set l [expr int(0)]
|
||||
set u [expr int(1100)]
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that the values of bound SQL variables may be used for the LIKE
|
||||
|
||||
+5
-5
@@ -566,7 +566,7 @@ foreach {tn schema} {
|
||||
drop_all_tables
|
||||
do_test 13.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE TABLE t1(a, b, c, d);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b, c);
|
||||
}
|
||||
@@ -577,16 +577,16 @@ do_test 13.1 {
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_eqp_test 13.2.1 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<20
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<12
|
||||
} {/SEARCH TABLE t1 USING INDEX i1/}
|
||||
do_eqp_test 13.2.2 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<20
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<12
|
||||
} {/SEARCH TABLE t1 USING INDEX i1/}
|
||||
do_eqp_test 13.3.1 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<20
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<12
|
||||
} {/SEARCH TABLE t1 USING INDEX i2/}
|
||||
do_eqp_test 13.3.2 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<20
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<12
|
||||
} {/SEARCH TABLE t1 USING INDEX i2/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -97,6 +97,8 @@ do_test autoindex1-210 {
|
||||
PRAGMA automatic_index=ON;
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t1';
|
||||
-- Table t2 actually contains 8 rows.
|
||||
UPDATE sqlite_stat1 SET stat='16' WHERE tbl='t2';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
|
||||
}
|
||||
|
||||
@@ -58,12 +58,24 @@ proc do_backcompat_test {rv bin1 bin2 script} {
|
||||
code1 { sqlite3 db test.db }
|
||||
code2 { sqlite3 db test.db }
|
||||
|
||||
foreach c {code1 code2} {
|
||||
$c {
|
||||
set v [split [db version] .]
|
||||
if {[llength $v]==3} {lappend v 0}
|
||||
set ::sqlite_libversion [format \
|
||||
"%d%.2d%.2d%2d" [lindex $v 0] [lindex $v 1] [lindex $v 2] [lindex $v 3]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
uplevel $script
|
||||
|
||||
catch { code1 { db close } }
|
||||
catch { code2 { db close } }
|
||||
catch { close $::bc_chan2 }
|
||||
catch { close $::bc_chan1 }
|
||||
|
||||
|
||||
}
|
||||
|
||||
array set ::incompatible [list]
|
||||
@@ -381,6 +393,48 @@ ifcapable fts3 {
|
||||
} {
|
||||
do_test backcompat-3.7 [list sql1 $q] [sql2 $q]
|
||||
}
|
||||
|
||||
# Now test that an incremental merge can be started by one version
|
||||
# and finished by another. And that the integrity-check still
|
||||
# passes.
|
||||
do_test backcompat-3.8 {
|
||||
sql1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t1(docid, words);
|
||||
CREATE VIRTUAL TABLE t2 USING fts3(words);
|
||||
}
|
||||
code1 [list source $testdir/genesis.tcl]
|
||||
code1 { fts_kjv_genesis }
|
||||
sql1 {
|
||||
INSERT INTO t2 SELECT words FROM t1;
|
||||
INSERT INTO t2 SELECT words FROM t1;
|
||||
INSERT INTO t2 SELECT words FROM t1;
|
||||
INSERT INTO t2 SELECT words FROM t1;
|
||||
INSERT INTO t2 SELECT words FROM t1;
|
||||
INSERT INTO t2 SELECT words FROM t1;
|
||||
SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level;
|
||||
}
|
||||
} {0 {0 1 2 3 4 5}}
|
||||
|
||||
if {[code1 { set ::sqlite_libversion }] >=3071200
|
||||
&& [code2 { set ::sqlite_libversion }] >=3071200
|
||||
} {
|
||||
do_test backcompat-3.9 {
|
||||
sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); }
|
||||
sql2 { INSERT INTO t2(t2) VALUES('merge=100,4'); }
|
||||
sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); }
|
||||
sql2 { INSERT INTO t2(t2) VALUES('merge=2500,4'); }
|
||||
sql2 {
|
||||
SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level;
|
||||
}
|
||||
} {0 {0 1} 1 0}
|
||||
|
||||
do_test backcompat-3.10 {
|
||||
sql1 { INSERT INTO t2(t2) VALUES('integrity-check') }
|
||||
sql2 { INSERT INTO t2(t2) VALUES('integrity-check') }
|
||||
} {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
# 2014-04-26
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix cost
|
||||
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t3(id INTEGER PRIMARY KEY, b NOT NULL);
|
||||
CREATE TABLE t4(c, d, e);
|
||||
CREATE UNIQUE INDEX i3 ON t3(b);
|
||||
CREATE UNIQUE INDEX i4 ON t4(c, d);
|
||||
}
|
||||
do_eqp_test 1.2 {
|
||||
SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t3 USING COVERING INDEX i3}
|
||||
0 1 1 {SEARCH TABLE t4 USING INDEX i4 (c=?)}
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
}
|
||||
|
||||
# It is better to use an index for ORDER BY than sort externally, even
|
||||
# if the index is a non-covering index.
|
||||
do_eqp_test 2.2 {
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 USING INDEX i1}
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
|
||||
CREATE INDEX t5b ON t5(b);
|
||||
CREATE INDEX t5c ON t5(c);
|
||||
CREATE INDEX t5d ON t5(d);
|
||||
CREATE INDEX t5e ON t5(e);
|
||||
CREATE INDEX t5f ON t5(f);
|
||||
CREATE INDEX t5g ON t5(g);
|
||||
}
|
||||
|
||||
do_eqp_test 3.2 {
|
||||
SELECT a FROM t5
|
||||
WHERE b IS NULL OR c IS NULL OR d IS NULL
|
||||
ORDER BY a;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t5 USING INDEX t5b (b=?)}
|
||||
0 0 0 {SEARCH TABLE t5 USING INDEX t5c (c=?)}
|
||||
0 0 0 {SEARCH TABLE t5 USING INDEX t5d (d=?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# If there is no likelihood() or stat3 data, SQLite assumes that a closed
|
||||
# range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint)
|
||||
# visits 1/64 of the rows in a table.
|
||||
#
|
||||
# Note: 1/63 =~ 0.016
|
||||
# Note: 1/65 =~ 0.015
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b);
|
||||
}
|
||||
do_eqp_test 4.2 {
|
||||
SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
|
||||
}
|
||||
do_eqp_test 4.3 {
|
||||
SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
CREATE TABLE t2(x, y);
|
||||
CREATE INDEX t2i1 ON t2(x);
|
||||
}
|
||||
|
||||
do_eqp_test 5.2 {
|
||||
SELECT * FROM t2 ORDER BY x, y;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
}
|
||||
|
||||
do_eqp_test 5.3 {
|
||||
SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
# where7.test, where8.test:
|
||||
#
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX t3i1 ON t3(b);
|
||||
CREATE INDEX t3i2 ON t3(c);
|
||||
}
|
||||
|
||||
do_eqp_test 6.2 {
|
||||
SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)}
|
||||
0 0 0 {SEARCH TABLE t3 USING INDEX t3i2 (c=?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
CREATE INDEX t1c ON t1(c);
|
||||
CREATE INDEX t1d ON t1(d);
|
||||
CREATE INDEX t1e ON t1(e);
|
||||
CREATE INDEX t1f ON t1(f);
|
||||
CREATE INDEX t1g ON t1(g);
|
||||
}
|
||||
|
||||
do_eqp_test 7.2 {
|
||||
SELECT a FROM t1
|
||||
WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL)
|
||||
ORDER BY a
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
do_eqp_test 7.3 {
|
||||
SELECT rowid FROM t1
|
||||
WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL)
|
||||
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
|
||||
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
do_eqp_test 7.4 {
|
||||
SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE composer(
|
||||
cid INTEGER PRIMARY KEY,
|
||||
cname TEXT
|
||||
);
|
||||
CREATE TABLE album(
|
||||
aid INTEGER PRIMARY KEY,
|
||||
aname TEXT
|
||||
);
|
||||
CREATE TABLE track(
|
||||
tid INTEGER PRIMARY KEY,
|
||||
cid INTEGER REFERENCES composer,
|
||||
aid INTEGER REFERENCES album,
|
||||
title TEXT
|
||||
);
|
||||
CREATE INDEX track_i1 ON track(cid);
|
||||
CREATE INDEX track_i2 ON track(aid);
|
||||
}
|
||||
|
||||
do_eqp_test 8.2 {
|
||||
SELECT DISTINCT aname
|
||||
FROM album, composer, track
|
||||
WHERE cname LIKE '%bach%'
|
||||
AND unlikely(composer.cid=track.cid)
|
||||
AND unlikely(album.aid=track.aid);
|
||||
} {
|
||||
0 0 2 {SCAN TABLE track}
|
||||
0 1 0 {SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
0 2 1 {SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 9.1 {
|
||||
CREATE TABLE t1(
|
||||
a,b,c,d,e, f,g,h,i,j,
|
||||
k,l,m,n,o, p,q,r,s,t
|
||||
);
|
||||
CREATE INDEX i1 ON t1(k,l,m,n,o,p,q,r,s,t);
|
||||
}
|
||||
do_test 9.2 {
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
execsql { INSERT INTO t1 DEFAULT VALUES }
|
||||
}
|
||||
execsql {
|
||||
ANALYZE;
|
||||
CREATE INDEX i2 ON t1(a,b,c,d,e,f,g,h,i,j);
|
||||
}
|
||||
} {}
|
||||
|
||||
set L [list a=? b=? c=? d=? e=? f=? g=? h=? i=? j=?]
|
||||
foreach {tn nTerm nRow} {
|
||||
1 1 10
|
||||
2 2 9
|
||||
3 3 8
|
||||
4 4 7
|
||||
5 5 6
|
||||
6 6 5
|
||||
7 7 5
|
||||
8 8 5
|
||||
9 9 5
|
||||
10 10 5
|
||||
} {
|
||||
set w [join [lrange $L 0 [expr $nTerm-1]] " AND "]
|
||||
set p1 [expr ($nRow-1) / 100.0]
|
||||
set p2 [expr ($nRow+1) / 100.0]
|
||||
|
||||
set sql1 "SELECT * FROM t1 WHERE likelihood(k=?, $p1) AND $w"
|
||||
set sql2 "SELECT * FROM t1 WHERE likelihood(k=?, $p2) AND $w"
|
||||
|
||||
do_eqp_test 9.3.$tn.1 $sql1 {/INDEX i1/}
|
||||
do_eqp_test 9.3.$tn.2 $sql2 {/INDEX i2/}
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -884,9 +884,10 @@ do_execsql_test e_createtable-3.3.1 {
|
||||
);
|
||||
} {}
|
||||
|
||||
# EVIDENCE-OF: R-10288-43169 For the purposes of the DEFAULT clause, an
|
||||
# EVIDENCE-OF: R-36381-62919 For the purposes of the DEFAULT clause, an
|
||||
# expression is considered constant provided that it does not contain
|
||||
# any sub-queries or string constants enclosed in double quotes.
|
||||
# any sub-queries, column or table references, or string literals
|
||||
# enclosed in double-quotes instead of single-quotes.
|
||||
#
|
||||
do_createtable_tests 3.4.1 -error {
|
||||
default value of column [x] is not constant
|
||||
|
||||
+6
-5
@@ -135,9 +135,9 @@ reset_db
|
||||
#
|
||||
# This also tests that foreign key constraints are disabled by default.
|
||||
#
|
||||
# EVIDENCE-OF: R-59578-04990 Foreign key constraints are disabled by
|
||||
# EVIDENCE-OF: R-44261-39702 Foreign key constraints are disabled by
|
||||
# default (for backwards compatibility), so must be enabled separately
|
||||
# for each database connection separately.
|
||||
# for each database connection.
|
||||
#
|
||||
drop_all_tables
|
||||
do_test e_fkey-4.1 {
|
||||
@@ -163,9 +163,10 @@ do_test e_fkey-4.2 {
|
||||
} {world}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-15278-54456 The application can can also use a PRAGMA
|
||||
# EVIDENCE-OF: R-08013-37737 The application can also use a PRAGMA
|
||||
# foreign_keys statement to determine if foreign keys are currently
|
||||
# enabled.
|
||||
|
||||
#
|
||||
# This also tests the example code in section 2 of foreignkeys.in.
|
||||
#
|
||||
@@ -2990,8 +2991,8 @@ if {[clang_sanitize_address]==0} {
|
||||
# The setting of the recursive_triggers pragma does not affect foreign
|
||||
# key actions.
|
||||
#
|
||||
# EVIDENCE-OF: R-51769-32730 The PRAGMA recursive_triggers setting does
|
||||
# not not affect the operation of foreign key actions.
|
||||
# EVIDENCE-OF: R-44355-00270 The PRAGMA recursive_triggers setting does
|
||||
# not affect the operation of foreign key actions.
|
||||
#
|
||||
foreach recursive_triggers_setting [list 0 1 ON OFF] {
|
||||
drop_all_tables
|
||||
|
||||
+50
-6
@@ -312,8 +312,8 @@ do_eqp_test 4.2.3 {
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)}
|
||||
}
|
||||
do_eqp_test 4.2.4 {
|
||||
@@ -321,8 +321,8 @@ do_eqp_test 4.2.4 {
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)}
|
||||
}
|
||||
do_eqp_test 4.2.5 {
|
||||
@@ -330,8 +330,8 @@ do_eqp_test 4.2.5 {
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
|
||||
}
|
||||
|
||||
@@ -598,5 +598,49 @@ det 7.5 "SELECT count(*) FROM t2" {
|
||||
0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - eqp-8.* - test that queries that use the OP_Count
|
||||
# optimization return something sensible with EQP.
|
||||
#
|
||||
drop_all_tables
|
||||
|
||||
do_execsql_test 8.0 {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
|
||||
CREATE TABLE t2(a, b, c);
|
||||
}
|
||||
|
||||
det 8.1.1 "SELECT * FROM t2" {
|
||||
0 0 0 {SCAN TABLE t2}
|
||||
}
|
||||
|
||||
det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" {
|
||||
0 0 0 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
det 8.1.3 "SELECT count(*) FROM t2" {
|
||||
0 0 0 {SCAN TABLE t2}
|
||||
}
|
||||
|
||||
det 8.2.1 "SELECT * FROM t1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
det 8.2.2 "SELECT * FROM t1 WHERE b=?" {
|
||||
0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=?)}
|
||||
}
|
||||
|
||||
det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" {
|
||||
0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?)}
|
||||
}
|
||||
|
||||
det 8.2.4 "SELECT count(*) FROM t1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+10
-9
@@ -213,16 +213,17 @@ do_test fts3d-4.matches {
|
||||
{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
|
||||
{0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]
|
||||
|
||||
check_terms_all fts3d-4.1 {a four is one test that this three two was}
|
||||
puts [db eval {SELECT c FROM t1 } ]
|
||||
check_terms_all fts3d-4.1 {a four is test that this was}
|
||||
check_doclist_all fts3d-4.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]}
|
||||
check_doclist_all fts3d-4.1.2 four {}
|
||||
check_doclist_all fts3d-4.1.3 is {[1 0[1]] [3 0[1]]}
|
||||
check_doclist_all fts3d-4.1.4 one {}
|
||||
#check_doclist_all fts3d-4.1.4 one {}
|
||||
check_doclist_all fts3d-4.1.5 test {[1 0[3]] [2 0[3]] [3 0[3]]}
|
||||
check_doclist_all fts3d-4.1.6 that {[2 0[0]]}
|
||||
check_doclist_all fts3d-4.1.7 this {[1 0[0]] [3 0[0]]}
|
||||
check_doclist_all fts3d-4.1.8 three {}
|
||||
check_doclist_all fts3d-4.1.9 two {}
|
||||
#check_doclist_all fts3d-4.1.8 three {}
|
||||
#check_doclist_all fts3d-4.1.9 two {}
|
||||
check_doclist_all fts3d-4.1.10 was {[2 0[1]]}
|
||||
|
||||
check_terms fts3d-4.2 0 0 {a four test that was}
|
||||
@@ -239,16 +240,16 @@ check_doclist fts3d-4.3.3 0 1 is {[3 0[1]]}
|
||||
check_doclist fts3d-4.3.4 0 1 test {[3 0[3]]}
|
||||
check_doclist fts3d-4.3.5 0 1 this {[3 0[0]]}
|
||||
|
||||
check_terms fts3d-4.4 1 0 {a four is one test that this three two was}
|
||||
check_terms fts3d-4.4 1 0 {a four is test that this was}
|
||||
check_doclist fts3d-4.4.1 1 0 a {[1 0[2]] [2 0[2]] [3 0[2]]}
|
||||
check_doclist fts3d-4.4.2 1 0 four {[1] [2 0[4]] [3 0[4]]}
|
||||
check_doclist fts3d-4.4.2 1 0 four {[2 0[4]] [3 0[4]]}
|
||||
check_doclist fts3d-4.4.3 1 0 is {[1 0[1]] [3 0[1]]}
|
||||
check_doclist fts3d-4.4.4 1 0 one {[1] [2] [3]}
|
||||
#check_doclist fts3d-4.4.4 1 0 one {[1] [2] [3]}
|
||||
check_doclist fts3d-4.4.5 1 0 test {[1 0[3]] [2 0[3]] [3 0[3]]}
|
||||
check_doclist fts3d-4.4.6 1 0 that {[2 0[0]]}
|
||||
check_doclist fts3d-4.4.7 1 0 this {[1 0[0]] [3 0[0]]}
|
||||
check_doclist fts3d-4.4.8 1 0 three {[1] [2] [3]}
|
||||
check_doclist fts3d-4.4.9 1 0 two {[1] [2] [3]}
|
||||
#check_doclist fts3d-4.4.8 1 0 three {[1] [2] [3]}
|
||||
#check_doclist fts3d-4.4.9 1 0 two {[1] [2] [3]}
|
||||
check_doclist fts3d-4.4.10 1 0 was {[2 0[1]]}
|
||||
|
||||
# Optimize should leave the result in the level of the highest-level
|
||||
|
||||
@@ -59,6 +59,7 @@ do_execsql_test 1.2.1 {
|
||||
SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
|
||||
} {{a b c d e f a x y}}
|
||||
|
||||
|
||||
do_execsql_test 1.2.2 {
|
||||
SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1, 'pcxnal'))
|
||||
FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
|
||||
|
||||
@@ -509,4 +509,9 @@ do_test fts3expr-8.7 { test_fts3expr "((((blah!))))" } {PHRASE 3 0 blah}
|
||||
do_test fts3expr-8.8 { test_fts3expr "(,(blah-),)" } {PHRASE 3 0 blah}
|
||||
|
||||
set sqlite_fts3_enable_parentheses 0
|
||||
|
||||
do_test fts3expr-9.1 {
|
||||
test_fts3expr "f (e NEAR/2 a)"
|
||||
} {AND {PHRASE 3 0 f} {NEAR/2 {PHRASE 3 0 e} {PHRASE 3 0 a}}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 2014 May 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.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS3 module.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts3expr4
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3||!icu {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set sqlite_fts3_enable_parentheses 1
|
||||
|
||||
proc test_icu_fts3expr {expr} {
|
||||
db one {SELECT fts3_exprtest('icu', $expr, 'a', 'b', 'c')}
|
||||
}
|
||||
|
||||
proc do_icu_expr_test {tn expr res} {
|
||||
uplevel [list do_test $tn [list test_icu_fts3expr $expr] $res]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_icu_expr_test 1.1 "abcd" {PHRASE 3 0 abcd}
|
||||
do_icu_expr_test 1.2 " tag " {PHRASE 3 0 tag}
|
||||
do_icu_expr_test 1.3 {"x y z"} {PHRASE 3 0 x y z}
|
||||
do_icu_expr_test 1.4 {x OR y} {OR {PHRASE 3 0 x} {PHRASE 3 0 y}}
|
||||
do_icu_expr_test 1.5 {(x OR y)} {OR {PHRASE 3 0 x} {PHRASE 3 0 y}}
|
||||
do_icu_expr_test 1.6 { "(x OR y)" } {PHRASE 3 0 ( x or y )}
|
||||
|
||||
# In "col:word", if "col" is not the name of a column, the entire thing
|
||||
# is passed to the tokenizer.
|
||||
#
|
||||
do_icu_expr_test 1.7 {a:word} {PHRASE 0 0 word}
|
||||
do_icu_expr_test 1.8 {d:word} {PHRASE 3 0 d:word}
|
||||
|
||||
set sqlite_fts3_enable_parentheses 0
|
||||
|
||||
do_icu_expr_test 2.1 {
|
||||
f (e NEAR/2 a)
|
||||
} {AND {AND {AND {PHRASE 3 0 f} {PHRASE 3 0 (}} {NEAR/2 {PHRASE 3 0 e} {PHRASE 3 0 a}}} {PHRASE 3 0 )}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
# 2014 May 12
|
||||
#
|
||||
# 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 FTS4 module.
|
||||
#
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts4growth
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
source $testdir/genesis.tcl
|
||||
|
||||
do_execsql_test 1.1 { CREATE VIRTUAL TABLE x1 USING fts3; }
|
||||
|
||||
do_test 1.2 {
|
||||
foreach L {
|
||||
{"See here, young man," said Mulga Bill, "from Walgett to the sea,}
|
||||
{From Conroy's Gap to Castlereagh, there's none can ride like me.}
|
||||
{I'm good all round at everything as everybody knows,}
|
||||
{Although I'm not the one to talk -- I hate a man that blows.}
|
||||
} {
|
||||
execsql { INSERT INTO x1 VALUES($L) }
|
||||
}
|
||||
execsql { SELECT end_block, length(root) FROM x1_segdir }
|
||||
} {{0 114} 114 {0 118} 118 {0 95} 95 {0 115} 115}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO x1(x1) VALUES('optimize');
|
||||
SELECT level, end_block, length(root) FROM x1_segdir;
|
||||
} {0 {0 394} 394}
|
||||
|
||||
do_test 1.4 {
|
||||
foreach L {
|
||||
{But riding is my special gift, my chiefest, sole delight;}
|
||||
{Just ask a wild duck can it swim, a wildcat can it fight.}
|
||||
{There's nothing clothed in hair or hide, or built of flesh or steel,}
|
||||
{There's nothing walks or jumps, or runs, on axle, hoof, or wheel,}
|
||||
{But what I'll sit, while hide will hold and girths and straps are tight:}
|
||||
{I'll ride this here two-wheeled concern right straight away at sight."}
|
||||
} {
|
||||
execsql { INSERT INTO x1 VALUES($L) }
|
||||
}
|
||||
execsql {
|
||||
INSERT INTO x1(x1) VALUES('merge=4,4');
|
||||
SELECT level, end_block, length(root) FROM x1_segdir;
|
||||
}
|
||||
} {0 {0 110} 110 0 {0 132} 132 0 {0 129} 129 1 {128 658} 2}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
SELECT length(block) FROM x1_segments;
|
||||
} {658 {}}
|
||||
|
||||
do_test 1.6 {
|
||||
foreach L {
|
||||
{'Twas Mulga Bill, from Eaglehawk, that sought his own abode,}
|
||||
{That perched above Dead Man's Creek, beside the mountain road.}
|
||||
{He turned the cycle down the hill and mounted for the fray,}
|
||||
{But 'ere he'd gone a dozen yards it bolted clean away.}
|
||||
{It left the track, and through the trees, just like a silver steak,}
|
||||
{It whistled down the awful slope towards the Dead Man's Creek.}
|
||||
{It shaved a stump by half an inch, it dodged a big white-box:}
|
||||
{The very wallaroos in fright went scrambling up the rocks,}
|
||||
{The wombats hiding in their caves dug deeper underground,}
|
||||
{As Mulga Bill, as white as chalk, sat tight to every bound.}
|
||||
{It struck a stone and gave a spring that cleared a fallen tree,}
|
||||
{It raced beside a precipice as close as close could be;}
|
||||
{And then as Mulga Bill let out one last despairing shriek}
|
||||
{It made a leap of twenty feet into the Dead Man's Creek.}
|
||||
} {
|
||||
execsql { INSERT INTO x1 VALUES($L) }
|
||||
}
|
||||
execsql {
|
||||
SELECT level, end_block, length(root) FROM x1_segdir;
|
||||
}
|
||||
} {1 {128 658} 2 1 {130 1377} 6 0 {0 117} 117}
|
||||
|
||||
do_execsql_test 1.7 {
|
||||
SELECT sum(length(block)) FROM x1_segments WHERE blockid IN (129, 130);
|
||||
} {1377}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t1(docid, words);
|
||||
CREATE VIRTUAL TABLE x2 USING fts4;
|
||||
}
|
||||
fts_kjv_genesis
|
||||
do_test 2.2 {
|
||||
foreach id [db eval {SELECT docid FROM t1}] {
|
||||
execsql {
|
||||
INSERT INTO x2(docid, content) SELECT $id, words FROM t1 WHERE docid=$id
|
||||
}
|
||||
}
|
||||
foreach id [db eval {SELECT docid FROM t1}] {
|
||||
execsql {
|
||||
INSERT INTO x2(docid, content) SELECT NULL, words FROM t1 WHERE docid=$id
|
||||
}
|
||||
if {[db one {SELECT count(*) FROM x2_segdir WHERE level<2}]==2} break
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT count(*) FROM x2_segdir WHERE level=2;
|
||||
SELECT count(*) FROM x2_segdir WHERE level=3;
|
||||
} {6 0}
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
INSERT INTO x2(x2) VALUES('merge=4,4');
|
||||
SELECT count(*) FROM x2_segdir WHERE level=2;
|
||||
SELECT count(*) FROM x2_segdir WHERE level=3;
|
||||
} {6 1}
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
SELECT end_block FROM x2_segdir WHERE level=3;
|
||||
INSERT INTO x2(x2) VALUES('merge=4,4');
|
||||
SELECT end_block FROM x2_segdir WHERE level=3;
|
||||
INSERT INTO x2(x2) VALUES('merge=4,4');
|
||||
SELECT end_block FROM x2_segdir WHERE level=3;
|
||||
} {{3828 -3430} {3828 -10191} {3828 -14109}}
|
||||
|
||||
do_execsql_test 2.6 {
|
||||
SELECT sum(length(block)) FROM x2_segdir, x2_segments WHERE
|
||||
blockid BETWEEN start_block AND leaves_end_block
|
||||
AND level=3
|
||||
} {14109}
|
||||
|
||||
do_execsql_test 2.7 {
|
||||
INSERT INTO x2(x2) VALUES('merge=1000,4');
|
||||
SELECT end_block FROM x2_segdir WHERE level=3;
|
||||
} {{3828 86120}}
|
||||
|
||||
do_execsql_test 2.8 {
|
||||
SELECT sum(length(block)) FROM x2_segdir, x2_segments WHERE
|
||||
blockid BETWEEN start_block AND leaves_end_block
|
||||
AND level=3
|
||||
} {86120}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Test that delete markers are removed from FTS segments when possible.
|
||||
# It is only possible to remove delete markers when the output of the
|
||||
# merge operation will become the oldest segment in the index.
|
||||
#
|
||||
# 3.1 - when the oldest segment is created by an 'optimize'.
|
||||
# 3.2 - when the oldest segment is created by an incremental merge.
|
||||
# 3.3 - by a crisis merge.
|
||||
#
|
||||
|
||||
proc insert_doc {args} {
|
||||
foreach iDoc $args {
|
||||
set L [lindex {
|
||||
{In your eagerness to engage the Trojans,}
|
||||
{don’t any of you charge ahead of others,}
|
||||
{trusting in your strength and horsemanship.}
|
||||
{And don’t lag behind. That will hurt our charge.}
|
||||
{Any man whose chariot confronts an enemy’s}
|
||||
{should thrust with his spear at him from there.}
|
||||
{That’s the most effective tactic, the way}
|
||||
{men wiped out city strongholds long ago —}
|
||||
{their chests full of that style and spirit.}
|
||||
} [expr $iDoc%9]]
|
||||
execsql { REPLACE INTO x3(docid, content) VALUES($iDoc, $L) }
|
||||
}
|
||||
}
|
||||
|
||||
proc delete_doc {args} {
|
||||
foreach iDoc $args {
|
||||
execsql { DELETE FROM x3 WHERE docid = $iDoc }
|
||||
}
|
||||
}
|
||||
|
||||
proc second {x} { lindex $x 1 }
|
||||
db func second second
|
||||
|
||||
do_execsql_test 3.0 { CREATE VIRTUAL TABLE x3 USING fts4 }
|
||||
|
||||
do_test 3.1.1 {
|
||||
db transaction { insert_doc 1 2 3 4 5 6 }
|
||||
execsql { SELECT level, idx, second(end_block) FROM x3_segdir }
|
||||
} {0 0 412}
|
||||
do_test 3.1.2 {
|
||||
delete_doc 1 2 3 4 5 6
|
||||
execsql { SELECT count(*) FROM x3_segdir }
|
||||
} {0}
|
||||
do_test 3.1.3 {
|
||||
db transaction {
|
||||
insert_doc 1 2 3 4 5 6 7 8 9
|
||||
delete_doc 9 8 7
|
||||
}
|
||||
execsql { SELECT level, idx, second(end_block) FROM x3_segdir }
|
||||
} {0 0 591 0 1 65 0 2 72 0 3 76}
|
||||
do_test 3.1.4 {
|
||||
execsql { INSERT INTO x3(x3) VALUES('optimize') }
|
||||
execsql { SELECT level, idx, second(end_block) FROM x3_segdir }
|
||||
} {0 0 412}
|
||||
|
||||
do_test 3.2.1 {
|
||||
execsql { DELETE FROM x3 }
|
||||
insert_doc 8 7 6 5 4 3 2 1
|
||||
delete_doc 7 8
|
||||
execsql { SELECT count(*) FROM x3_segdir }
|
||||
} {10}
|
||||
do_test 3.2.2 {
|
||||
execsql { INSERT INTO x3(x3) VALUES('merge=500,10') }
|
||||
execsql { SELECT level, idx, second(end_block) FROM x3_segdir }
|
||||
} {1 0 412}
|
||||
|
||||
# This assumes the crisis merge happens when there are already 16
|
||||
# segments and one more is added.
|
||||
#
|
||||
do_test 3.3.1 {
|
||||
execsql { DELETE FROM x3 }
|
||||
insert_doc 1 2 3 4 5 6 7 8 9 10 11
|
||||
delete_doc 11 10 9 8 7
|
||||
execsql { SELECT count(*) FROM x3_segdir }
|
||||
} {16}
|
||||
|
||||
do_test 3.3.2 {
|
||||
insert_doc 12
|
||||
execsql { SELECT level, idx, second(end_block) FROM x3_segdir WHERE level=1 }
|
||||
} {1 0 412}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Check a theory on a bug in fts4 - that segments with idx==0 were not
|
||||
# being incrementally merged correctly. Theory turned out to be false.
|
||||
#
|
||||
do_execsql_test 4.1 {
|
||||
DROP TABLE IF EXISTS x4;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(docid, words);
|
||||
CREATE VIRTUAL TABLE x4 USING fts4(words);
|
||||
}
|
||||
do_test 4.2 {
|
||||
fts_kjv_genesis
|
||||
execsql { INSERT INTO x4 SELECT words FROM t1 }
|
||||
execsql { INSERT INTO x4 SELECT words FROM t1 }
|
||||
} {}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
SELECT level, idx, second(end_block) FROM x4_segdir
|
||||
} {0 0 117483 0 1 118006}
|
||||
|
||||
do_execsql_test 4.4 {
|
||||
INSERT INTO x4(x4) VALUES('merge=10,2');
|
||||
SELECT count(*) FROM x4_segdir;
|
||||
} {3}
|
||||
|
||||
do_execsql_test 4.5 {
|
||||
INSERT INTO x4(x4) VALUES('merge=10,2');
|
||||
SELECT count(*) FROM x4_segdir;
|
||||
} {3}
|
||||
|
||||
do_execsql_test 4.6 {
|
||||
INSERT INTO x4(x4) VALUES('merge=1000,2');
|
||||
SELECT count(*) FROM x4_segdir;
|
||||
} {1}
|
||||
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Check that segments are not promoted if the "end_block" field does not
|
||||
# contain a size.
|
||||
#
|
||||
do_execsql_test 5.1 {
|
||||
DROP TABLE IF EXISTS x2;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(docid, words);
|
||||
CREATE VIRTUAL TABLE x2 USING fts4;
|
||||
}
|
||||
fts_kjv_genesis
|
||||
|
||||
proc first {L} {lindex $L 0}
|
||||
db func first first
|
||||
|
||||
do_test 5.2 {
|
||||
foreach r [db eval { SELECT rowid FROM t1 }] {
|
||||
execsql {
|
||||
INSERT INTO x2(docid, content) SELECT docid, words FROM t1 WHERE rowid=$r
|
||||
}
|
||||
}
|
||||
foreach d [db eval { SELECT docid FROM t1 LIMIT -1 OFFSET 20 }] {
|
||||
execsql { DELETE FROM x2 WHERE docid = $d }
|
||||
}
|
||||
|
||||
execsql {
|
||||
INSERT INTO x2(x2) VALUES('optimize');
|
||||
SELECT level, idx, end_block FROM x2_segdir
|
||||
}
|
||||
} {2 0 {752 1926}}
|
||||
|
||||
do_execsql_test 5.3 {
|
||||
UPDATE x2_segdir SET end_block = CAST( first(end_block) AS INTEGER );
|
||||
SELECT end_block, typeof(end_block) FROM x2_segdir;
|
||||
} {752 integer}
|
||||
|
||||
do_execsql_test 5.4 {
|
||||
INSERT INTO x2 SELECT words FROM t1 LIMIT 50;
|
||||
SELECT level, idx, end_block FROM x2_segdir
|
||||
} {2 0 752 0 0 {758 5174}}
|
||||
|
||||
do_execsql_test 5.5 {
|
||||
UPDATE x2_segdir SET end_block = end_block || ' 1926' WHERE level=2;
|
||||
INSERT INTO x2 SELECT words FROM t1 LIMIT 40;
|
||||
SELECT level, idx, end_block FROM x2_segdir
|
||||
} {0 0 {752 1926} 0 1 {758 5174} 0 2 {763 4170}}
|
||||
|
||||
proc t1_to_x2 {} {
|
||||
foreach id [db eval {SELECT docid FROM t1 LIMIT 2}] {
|
||||
execsql {
|
||||
DELETE FROM x2 WHERE docid=$id;
|
||||
INSERT INTO x2(docid, content) SELECT $id, words FROM t1 WHERE docid=$id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Check that segments created by auto-merge are not promoted until they
|
||||
# are completed.
|
||||
#
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
CREATE VIRTUAL TABLE x5 USING fts4;
|
||||
INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 0;
|
||||
INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 25;
|
||||
INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 50;
|
||||
INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 75;
|
||||
SELECT count(*) FROM x5_segdir
|
||||
} {4}
|
||||
|
||||
do_execsql_test 6.2 {
|
||||
INSERT INTO x5(x5) VALUES('merge=2,4');
|
||||
SELECT level, idx, end_block FROM x5_segdir;
|
||||
} {0 0 {10 9216} 0 1 {21 9330} 0 2 {31 8850} 0 3 {40 8689} 1 0 {1320 -3117}}
|
||||
|
||||
do_execsql_test 6.3 {
|
||||
INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 100;
|
||||
SELECT level, idx, end_block FROM x5_segdir;
|
||||
} {
|
||||
0 0 {10 9216} 0 1 {21 9330} 0 2 {31 8850}
|
||||
0 3 {40 8689} 1 0 {1320 -3117} 0 4 {1329 8297}
|
||||
}
|
||||
|
||||
do_execsql_test 6.4 {
|
||||
INSERT INTO x5(x5) VALUES('merge=200,4');
|
||||
SELECT level, idx, end_block FROM x5_segdir;
|
||||
} {0 0 {1329 8297} 1 0 {1320 28009}}
|
||||
|
||||
do_execsql_test 6.5 {
|
||||
INSERT INTO x5 SELECT words FROM t1;
|
||||
SELECT level, idx, end_block FROM x5_segdir;
|
||||
} {
|
||||
0 1 {1329 8297} 0 0 {1320 28009} 0 2 {1449 118006}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Ensure that if part of an incremental merge is performed by an old
|
||||
# version that does not support storing segment sizes in the end_block
|
||||
# field, no size is stored in the final segment (as it would be incorrect).
|
||||
#
|
||||
do_execsql_test 7.1 {
|
||||
CREATE VIRTUAL TABLE x6 USING fts4;
|
||||
INSERT INTO x6 SELECT words FROM t1;
|
||||
INSERT INTO x6 SELECT words FROM t1;
|
||||
INSERT INTO x6 SELECT words FROM t1;
|
||||
INSERT INTO x6 SELECT words FROM t1;
|
||||
INSERT INTO x6 SELECT words FROM t1;
|
||||
INSERT INTO x6 SELECT words FROM t1;
|
||||
SELECT level, idx, end_block FROM x6_segdir;
|
||||
} {
|
||||
0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006}
|
||||
0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006}
|
||||
}
|
||||
|
||||
do_execsql_test 7.2 {
|
||||
INSERT INTO x6(x6) VALUES('merge=25,4');
|
||||
SELECT level, idx, end_block FROM x6_segdir;
|
||||
} {
|
||||
0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006}
|
||||
0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006}
|
||||
1 0 {16014 -51226}
|
||||
}
|
||||
|
||||
do_execsql_test 7.3 {
|
||||
UPDATE x6_segdir SET end_block = first(end_block) WHERE level=1;
|
||||
SELECT level, idx, end_block FROM x6_segdir;
|
||||
} {
|
||||
0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006}
|
||||
0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006}
|
||||
1 0 16014
|
||||
}
|
||||
|
||||
do_execsql_test 7.4 {
|
||||
INSERT INTO x6(x6) VALUES('merge=25,4');
|
||||
SELECT level, idx, end_block FROM x6_segdir;
|
||||
} {
|
||||
0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006}
|
||||
0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006}
|
||||
1 0 16014
|
||||
}
|
||||
|
||||
do_execsql_test 7.5 {
|
||||
INSERT INTO x6(x6) VALUES('merge=2500,4');
|
||||
SELECT level, idx, end_block FROM x6_segdir;
|
||||
} {
|
||||
0 0 {598 118006} 0 1 {718 118006} 1 0 16014
|
||||
}
|
||||
|
||||
do_execsql_test 7.6 {
|
||||
INSERT INTO x6(x6) VALUES('merge=2500,2');
|
||||
SELECT level, idx, start_block, leaves_end_block, end_block FROM x6_segdir;
|
||||
} {
|
||||
2 0 23695 24147 {41262 633507}
|
||||
}
|
||||
|
||||
do_execsql_test 7.7 {
|
||||
SELECT sum(length(block)) FROM x6_segments
|
||||
WHERE blockid BETWEEN 23695 AND 24147
|
||||
} {633507}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# 2014 May 12
|
||||
#
|
||||
# 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 FTS4 module.
|
||||
#
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts4growth2
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
source $testdir/genesis.tcl
|
||||
|
||||
do_execsql_test 1.0 { CREATE TABLE t1(docid, words); }
|
||||
fts_kjv_genesis
|
||||
|
||||
proc structure {} {
|
||||
puts [ db eval {SELECT level, count(*) FROM x1_segdir GROUP BY level} ]
|
||||
}
|
||||
|
||||
proc tt {val} {
|
||||
execsql {
|
||||
DELETE FROM x1
|
||||
WHERE docid IN (SELECT docid FROM t1 WHERE (rowid-1)%4==$val+0);
|
||||
}
|
||||
execsql {
|
||||
INSERT INTO x1(docid, content)
|
||||
SELECT docid, words FROM t1 WHERE (rowid%4)==$val+0;
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts4;
|
||||
INSERT INTO x1(x1) VALUES('automerge=2');
|
||||
}
|
||||
|
||||
do_test 1.2 {
|
||||
for {set i 0} {$i < 40} {incr i} {
|
||||
tt 0 ; tt 1 ; tt 2 ; tt 3
|
||||
}
|
||||
execsql {
|
||||
SELECT max(level) FROM x1_segdir;
|
||||
SELECT count(*) FROM x1_segdir WHERE level=2;
|
||||
}
|
||||
} {2 1}
|
||||
|
||||
do_test 1.3 {
|
||||
for {set i 0} {$i < 40} {incr i} {
|
||||
tt 0 ; tt 1 ; tt 2 ; tt 3
|
||||
}
|
||||
execsql {
|
||||
SELECT max(level) FROM x1_segdir;
|
||||
SELECT count(*) FROM x1_segdir WHERE level=2;
|
||||
}
|
||||
} {2 1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 2.1 {
|
||||
DELETE FROM t1 WHERE rowid>16;
|
||||
DROP TABLE IF EXISTS x1;
|
||||
CREATE VIRTUAL TABLE x1 USING fts4;
|
||||
}
|
||||
|
||||
db func second second
|
||||
proc second {L} {lindex $L 1}
|
||||
|
||||
for {set tn 0} {$tn < 40} {incr tn} {
|
||||
do_test 2.2.$tn {
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
tt 0 ; tt 1 ; tt 2 ; tt 3
|
||||
}
|
||||
execsql { SELECT max(level) FROM x1_segdir }
|
||||
} {1}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -53,6 +53,50 @@ do_execsql_test 2.2 { SELECT count(*) FROM t1_segdir; } 35
|
||||
do_execsql_test 2.3 { INSERT INTO t1(t1) VALUES('optimize') } {}
|
||||
do_execsql_test 2.4 { SELECT count(*) FROM t1_segdir; } 1
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Now test that the automerge=? option appears to work.
|
||||
#
|
||||
do_execsql_test 2.1 { CREATE VIRTUAL TABLE t2 USING fts4; }
|
||||
|
||||
set doc ""
|
||||
foreach c1 "a b c d e f g h i j" {
|
||||
foreach c2 "a b c d e f g h i j" {
|
||||
foreach c3 "a b c d e f g h i j" {
|
||||
lappend doc "$c1$c2$c3"
|
||||
}
|
||||
}
|
||||
}
|
||||
set doc [string repeat $doc 10]
|
||||
|
||||
foreach {tn am expected} {
|
||||
1 {automerge=2} {1 1 2 1 4 1 6 1}
|
||||
2 {automerge=4} {1 2 2 1 3 1}
|
||||
3 {automerge=8} {0 4 1 3 2 1}
|
||||
4 {automerge=1} {0 4 1 3 2 1}
|
||||
} {
|
||||
foreach {tn2 openclose} {1 {} 2 { db close ; sqlite3 db test.db }} {
|
||||
do_test 2.2.$tn.$tn2 {
|
||||
execsql { DELETE FROM t2 }
|
||||
execsql { INSERT INTO t2(t2) VALUES($am) };
|
||||
|
||||
eval $openclose
|
||||
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES($doc);
|
||||
INSERT INTO t2 VALUES($doc);
|
||||
INSERT INTO t2 VALUES($doc);
|
||||
INSERT INTO t2 VALUES($doc);
|
||||
INSERT INTO t2 VALUES($doc);
|
||||
COMMIT;
|
||||
}
|
||||
}
|
||||
|
||||
execsql { SELECT level, count(*) FROM t2_segdir GROUP BY level }
|
||||
} [list {*}$expected]
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
finish_test
|
||||
|
||||
@@ -165,6 +165,51 @@ do_execsql_test 5.4 { SELECT docid FROM t2 WHERE t2 MATCH 'c' } {3}
|
||||
|
||||
do_execsql_test 5.x { DROP TABLE t2 }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that if an indexed column name is a prefix of a notindexed column
|
||||
# name, the column is still correctly tokenized. This was a problem at one
|
||||
# point.
|
||||
do_execsql_test 6.1.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts4(
|
||||
poiCategory, poiCategoryId, notindexed=poiCategoryId
|
||||
);
|
||||
INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021);
|
||||
}
|
||||
|
||||
do_execsql_test 6.1.2 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH 'restaurant';
|
||||
} { Restaurant 6021 }
|
||||
do_execsql_test 6.1.3 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH 're*';
|
||||
} { Restaurant 6021 }
|
||||
do_execsql_test 6.1.4 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH '6021';
|
||||
} {}
|
||||
do_execsql_test 6.1.5 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH '60*';
|
||||
} {}
|
||||
|
||||
do_execsql_test 6.2.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE VIRTUAL TABLE t1 USING fts4(
|
||||
poiCategory, poiCategoryId, notindexed=poiCategory
|
||||
);
|
||||
INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021);
|
||||
}
|
||||
|
||||
do_execsql_test 6.2.2 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH 'restaurant';
|
||||
} {}
|
||||
do_execsql_test 6.2.3 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH 're*';
|
||||
} {}
|
||||
do_execsql_test 6.2.4 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH '6021';
|
||||
} { Restaurant 6021 }
|
||||
do_execsql_test 6.2.5 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH '60*';
|
||||
} { Restaurant 6021 }
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
+19
-5
@@ -1194,6 +1194,18 @@ do_test func-24.12 {
|
||||
WHEN 'program' THEN null ELSE t1 END) FROM tbl1
|
||||
}
|
||||
} {,is,free,software}
|
||||
# Tests to verify ticket http://www.sqlite.org/src/tktview/55746f9e65f8587c0
|
||||
do_test func-24.13 {
|
||||
execsql {
|
||||
SELECT typeof(group_concat(x)) FROM (SELECT '' AS x);
|
||||
}
|
||||
} {text}
|
||||
do_test func-24.14 {
|
||||
execsql {
|
||||
SELECT typeof(group_concat(x,''))
|
||||
FROM (SELECT '' AS x UNION ALL SELECT '');
|
||||
}
|
||||
} {text}
|
||||
|
||||
|
||||
# Use the test_isolation function to make sure that type conversions
|
||||
@@ -1301,11 +1313,13 @@ do_test func-29.3 {
|
||||
db eval {SELECT typeof(+x) FROM t29 ORDER BY id}
|
||||
} {integer null real blob text}
|
||||
if {[permutation] != "mmap"} {
|
||||
do_test func-29.4 {
|
||||
set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
|
||||
if {$x>100} {set x many}
|
||||
set x
|
||||
} {many}
|
||||
ifcapable !direct_read {
|
||||
do_test func-29.4 {
|
||||
set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
|
||||
if {$x>100} {set x many}
|
||||
set x
|
||||
} {many}
|
||||
}
|
||||
}
|
||||
do_test func-29.5 {
|
||||
db close
|
||||
|
||||
+1
-1
@@ -285,7 +285,7 @@ do_test fuzz-1.18 {
|
||||
)
|
||||
))
|
||||
}
|
||||
} {0 -4294967298}
|
||||
} {0 {{}}}
|
||||
|
||||
# At one point the following INSERT statement caused an assert() to fail.
|
||||
#
|
||||
|
||||
+22
-2
@@ -145,11 +145,11 @@ do_test index6-2.1 {
|
||||
execsql {
|
||||
CREATE TABLE t2(a,b);
|
||||
INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000;
|
||||
UPDATE t2 SET a=NULL WHERE b%5==0;
|
||||
UPDATE t2 SET a=NULL WHERE b%2==0;
|
||||
CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL;
|
||||
SELECT count(*) FROM t2 WHERE a IS NOT NULL;
|
||||
}
|
||||
} {800}
|
||||
} {500}
|
||||
do_test index6-2.2 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
@@ -157,6 +157,7 @@ do_test index6-2.2 {
|
||||
}
|
||||
} {/.* TABLE t2 USING INDEX t2a1 .*/}
|
||||
ifcapable stat4||stat3 {
|
||||
execsql ANALYZE
|
||||
do_test index6-2.3stat4 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
@@ -248,4 +249,23 @@ do_execsql_test index6-5.0 {
|
||||
SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b';
|
||||
} {6 6}
|
||||
|
||||
# Test case for ticket [2ea3e9fe6379fc3f6ce7e090ce483c1a3a80d6c9] from
|
||||
# 2014-04-13: Partial index causes assertion fault on UPDATE OR REPLACE.
|
||||
#
|
||||
do_execsql_test index6-6.0 {
|
||||
CREATE TABLE t6(a,b);
|
||||
CREATE UNIQUE INDEX t6ab ON t1(a,b);
|
||||
CREATE INDEX t6b ON t6(b) WHERE b=1;
|
||||
INSERT INTO t6(a,b) VALUES(123,456);
|
||||
SELECT * FROM t6;
|
||||
} {123 456}
|
||||
do_execsql_test index6-6.1 {
|
||||
UPDATE OR REPLACE t6 SET b=789;
|
||||
SELECT * FROM t6;
|
||||
} {123 789}
|
||||
do_execsql_test index6-6.2 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -413,6 +413,29 @@ do_execsql_test insert-11.1 {
|
||||
} {123456789 '123456789' '123456789'}
|
||||
|
||||
|
||||
# More columns of input than there are columns in the table.
|
||||
# Ticket http://www.sqlite.org/src/info/e9654505cfda9361
|
||||
#
|
||||
do_execsql_test insert-12.1 {
|
||||
CREATE TABLE t12a(a,b,c,d,e,f,g);
|
||||
INSERT INTO t12a VALUES(101,102,103,104,105,106,107);
|
||||
CREATE TABLE t12b(x);
|
||||
INSERT INTO t12b(x,rowid,x,x,x,x,x) SELECT * FROM t12a;
|
||||
SELECT rowid, x FROM t12b;
|
||||
} {102 101}
|
||||
do_execsql_test insert-12.2 {
|
||||
CREATE TABLE tab1( value INTEGER);
|
||||
INSERT INTO tab1 (value, _rowid_) values( 11, 1);
|
||||
INSERT INTO tab1 (value, _rowid_) SELECT 22,999;
|
||||
SELECT * FROM tab1;
|
||||
} {11 22}
|
||||
do_execsql_test insert-12.3 {
|
||||
CREATE TABLE t12c(a, b DEFAULT 'xyzzy', c);
|
||||
INSERT INTO t12c(a, rowid, c) SELECT 'one', 999, 'two';
|
||||
SELECT * FROM t12c;
|
||||
} {one xyzzy two}
|
||||
|
||||
|
||||
integrity_check insert-99.0
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -604,5 +604,21 @@ do_execsql_test misc1-19.2 {
|
||||
SELECT * FROM t19b;
|
||||
} {4 5 6}
|
||||
|
||||
# 2014-05-16: Tests for the SQLITE_TESTCTRL_FAULT_INSTALL feature.
|
||||
#
|
||||
unset -nocomplain fault_callbacks
|
||||
set fault_callbacks {}
|
||||
proc fault_callback {n} {
|
||||
lappend ::fault_callbacks $n
|
||||
return 0
|
||||
}
|
||||
do_test misc1-19.1 {
|
||||
sqlite3_test_control_fault_install fault_callback
|
||||
set fault_callbacks
|
||||
} {0}
|
||||
do_test misc1-19.2 {
|
||||
sqlite3_test_control_fault_install
|
||||
set fault_callbacks
|
||||
} {0}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
# 2014-05-07
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the nolock=1 and immutable=1 query
|
||||
# parameters and the SQLITE_IOCAP_IMMUTABLE device characteristic.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
unset -nocomplain tvfs_calls
|
||||
proc tvfs_reset {} {
|
||||
global tvfs_calls
|
||||
array set tvfs_calls {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0}
|
||||
}
|
||||
proc tvfs_callback {op args} {
|
||||
global tvfs_calls
|
||||
incr tvfs_calls($op)
|
||||
return SQLITE_OK
|
||||
}
|
||||
tvfs_reset
|
||||
|
||||
testvfs tvfs
|
||||
tvfs script tvfs_callback
|
||||
tvfs filter {xLock xUnlock xCheckReservedLock xAccess}
|
||||
|
||||
############################################################################
|
||||
# Verify that the nolock=1 query parameter for URI filenames disables all
|
||||
# calls to xLock and xUnlock for rollback databases.
|
||||
#
|
||||
do_test nolock-1.0 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
tvfs_reset
|
||||
sqlite db test.db -vfs tvfs
|
||||
db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);}
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock)
|
||||
} {xLock 7 xUnlock 5 xCheckReservedLock 0}
|
||||
|
||||
do_test nolock-1.1 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
tvfs_reset
|
||||
sqlite db file:test.db?nolock=0 -vfs tvfs -uri 1
|
||||
db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);}
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock)
|
||||
} {xLock 7 xUnlock 5 xCheckReservedLock 0}
|
||||
|
||||
do_test nolock-1.2 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
tvfs_reset
|
||||
sqlite db file:test.db?nolock=1 -vfs tvfs -uri 1
|
||||
db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);}
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock)
|
||||
} {xLock 0 xUnlock 0 xCheckReservedLock 0}
|
||||
|
||||
do_test nolock-1.3 {
|
||||
db close
|
||||
tvfs_reset
|
||||
sqlite db file:test.db?nolock=0 -vfs tvfs -uri 1 -readonly 1
|
||||
db eval {SELECT * FROM t1}
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock)
|
||||
} {xLock 2 xUnlock 2 xCheckReservedLock 0}
|
||||
|
||||
do_test nolock-1.4 {
|
||||
db close
|
||||
tvfs_reset
|
||||
sqlite db file:test.db?nolock=1 -vfs tvfs -uri 1 -readonly 1
|
||||
db eval {SELECT * FROM t1}
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock)
|
||||
} {xLock 0 xUnlock 0 xCheckReservedLock 0}
|
||||
|
||||
#############################################################################
|
||||
# Verify that immutable=1 disables both locking and xAccess calls to the
|
||||
# journal files.
|
||||
#
|
||||
do_test nolock-2.0 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
# begin by creating a test database
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1 VALUES('hello','world');
|
||||
CREATE TABLE t2(x,y);
|
||||
INSERT INTO t2 VALUES(12345,67890);
|
||||
SELECT * FROM t1, t2;
|
||||
}
|
||||
} {hello world 12345 67890}
|
||||
do_test nolock-2.1 {
|
||||
tvfs_reset
|
||||
sqlite3 db2 test.db -vfs tvfs
|
||||
db2 eval {SELECT * FROM t1, t2}
|
||||
} {hello world 12345 67890}
|
||||
do_test nolock-2.2 {
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
|
||||
xAccess $::tvfs_calls(xAccess)
|
||||
} {xLock 2 xUnlock 2 xCheckReservedLock 0 xAccess 4}
|
||||
|
||||
|
||||
do_test nolock-2.11 {
|
||||
db2 close
|
||||
tvfs_reset
|
||||
sqlite3 db2 file:test.db?immutable=0 -vfs tvfs -uri 1
|
||||
db2 eval {SELECT * FROM t1, t2}
|
||||
} {hello world 12345 67890}
|
||||
do_test nolock-2.12 {
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
|
||||
xAccess $::tvfs_calls(xAccess)
|
||||
} {xLock 2 xUnlock 2 xCheckReservedLock 0 xAccess 4}
|
||||
|
||||
|
||||
do_test nolock-2.21 {
|
||||
db2 close
|
||||
tvfs_reset
|
||||
sqlite3 db2 file:test.db?immutable=1 -vfs tvfs -uri 1
|
||||
db2 eval {SELECT * FROM t1, t2}
|
||||
} {hello world 12345 67890}
|
||||
do_test nolock-2.22 {
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
|
||||
xAccess $::tvfs_calls(xAccess)
|
||||
} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0}
|
||||
|
||||
do_test nolock-2.31 {
|
||||
db2 close
|
||||
tvfs_reset
|
||||
sqlite3 db2 file:test.db?immutable=1 -vfs tvfs -uri 1 -readonly 1
|
||||
db2 eval {SELECT * FROM t1, t2}
|
||||
} {hello world 12345 67890}
|
||||
do_test nolock-2.32 {
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
|
||||
xAccess $::tvfs_calls(xAccess)
|
||||
} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0}
|
||||
|
||||
############################################################################
|
||||
# Verify that the SQLITE_IOCAP_IMMUTABLE flag works
|
||||
#
|
||||
do_test nolock-3.1 {
|
||||
db2 close
|
||||
tvfs devchar immutable
|
||||
tvfs_reset
|
||||
sqlite3 db2 test.db -vfs tvfs
|
||||
db2 eval {SELECT * FROM t1, t2}
|
||||
} {hello world 12345 67890}
|
||||
do_test nolock-3.2 {
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
|
||||
xAccess $::tvfs_calls(xAccess)
|
||||
} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0}
|
||||
|
||||
do_test nolock-3.11 {
|
||||
db2 close
|
||||
tvfs_reset
|
||||
sqlite3 db2 test.db -vfs tvfs -readonly 1
|
||||
db2 eval {SELECT * FROM t1, t2}
|
||||
} {hello world 12345 67890}
|
||||
do_test nolock-3.12 {
|
||||
list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
|
||||
xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
|
||||
xAccess $::tvfs_calls(xAccess)
|
||||
} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0}
|
||||
|
||||
db2 close
|
||||
db close
|
||||
tvfs delete
|
||||
finish_test
|
||||
+2
-2
@@ -80,12 +80,12 @@ do_execsql_test 2.1a {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t2 WHERE a=0 ORDER BY a, b, c;
|
||||
} {~/B-TREE/}
|
||||
|
||||
do_execsql_test 2.1b {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 WHERE a=0 ORDER BY a, b, c;
|
||||
SELECT * FROM t1 WHERE likelihood(a=0, 0.05) ORDER BY a, b, c;
|
||||
} {/B-TREE/}
|
||||
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c;
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# 2014-04-25
|
||||
#
|
||||
# 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 file is testing ORDER BY optimizations on joins
|
||||
# that involve virtual tables.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix orderby7
|
||||
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE fts USING fts3(content TEXT);
|
||||
INSERT INTO fts(rowid,content)
|
||||
VALUES(1,'this is a test of the fts3 virtual'),
|
||||
(2,'table used as part of a join together'),
|
||||
(3,'with the DISTINCT keyword. There was'),
|
||||
(4,'a bug at one time (2013-06 through 2014-04)'),
|
||||
(5,'that prevented this from working correctly.'),
|
||||
(11,'a row that occurs twice'),
|
||||
(12,'a row that occurs twice');
|
||||
|
||||
CREATE TABLE t1(x TEXT PRIMARY KEY, y);
|
||||
INSERT OR IGNORE INTO t1 SELECT content, rowid+100 FROM fts;
|
||||
} {}
|
||||
do_execsql_test 1.1 {
|
||||
SELECT DISTINCT fts.rowid, t1.y
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x
|
||||
ORDER BY y;
|
||||
} {11 111 12 111}
|
||||
do_execsql_test 1.2 {
|
||||
SELECT DISTINCT fts.rowid, t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x
|
||||
ORDER BY 1;
|
||||
} {11 {a row that occurs twice} 12 {a row that occurs twice}}
|
||||
do_execsql_test 1.3 {
|
||||
SELECT DISTINCT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x
|
||||
ORDER BY 1;
|
||||
} {{a row that occurs twice}}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x
|
||||
ORDER BY 1;
|
||||
} {{a row that occurs twice} {a row that occurs twice}}
|
||||
do_execsql_test 1.5 {
|
||||
SELECT DISTINCT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x;
|
||||
} {{a row that occurs twice}}
|
||||
do_execsql_test 1.6 {
|
||||
SELECT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x;
|
||||
} {{a row that occurs twice} {a row that occurs twice}}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT DISTINCT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts.rowid=11
|
||||
AND content=x
|
||||
ORDER BY fts.rowid;
|
||||
} {{a row that occurs twice}}
|
||||
do_execsql_test 2.2 {
|
||||
SELECT DISTINCT t1.*
|
||||
FROM fts, t1
|
||||
WHERE fts.rowid=11
|
||||
AND content=x
|
||||
ORDER BY fts.rowid;
|
||||
} {{a row that occurs twice} 111}
|
||||
do_execsql_test 2.3 {
|
||||
SELECT DISTINCT t1.*
|
||||
FROM fts, t1
|
||||
WHERE fts.rowid=11
|
||||
AND content=x
|
||||
ORDER BY t1.y
|
||||
} {{a row that occurs twice} 111}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -112,6 +112,7 @@ set allquicktests [test_set $alltests -exclude {
|
||||
incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test
|
||||
vtab_err.test walslow.test walcrash.test walcrash3.test
|
||||
walthread.test rtree3.test indexfault.test securedel2.test
|
||||
fts4growth.test fts4growth2.test
|
||||
}]
|
||||
if {[info exists ::env(QUICKTEST_INCLUDE)]} {
|
||||
set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)]
|
||||
@@ -196,6 +197,7 @@ test_suite "fts3" -prefix "" -description {
|
||||
fts3corrupt2.test fts3first.test fts4langid.test fts4merge.test
|
||||
fts4check.test fts4unicode.test fts4noti.test
|
||||
fts3varint.test
|
||||
fts4growth.test fts4growth2.test
|
||||
}
|
||||
|
||||
test_suite "nofaultsim" -prefix "" -description {
|
||||
|
||||
@@ -32,6 +32,9 @@ do_test rdonly-1.1 {
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1}
|
||||
do_test rdonly-1.1.1 {
|
||||
sqlite3_db_readonly db main
|
||||
} {0}
|
||||
|
||||
# Changes the write version from 1 to 3. Verify that the database
|
||||
# can be read but not written.
|
||||
@@ -47,6 +50,9 @@ do_test rdonly-1.3 {
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1}
|
||||
do_test rdonly-1.3.1 {
|
||||
sqlite3_db_readonly db main
|
||||
} {1}
|
||||
do_test rdonly-1.4 {
|
||||
catchsql {
|
||||
INSERT INTO t1 VALUES(2)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix selectA
|
||||
|
||||
ifcapable !compound {
|
||||
finish_test
|
||||
@@ -1310,4 +1311,68 @@ do_execsql_test selectA-3.98 {
|
||||
SELECT n FROM xyz ORDER BY +n;
|
||||
} {MAD MAD+ MAD++}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# At one point the following code exposed a temp register reuse problem.
|
||||
#
|
||||
proc f {args} { return 1 }
|
||||
db func f f
|
||||
|
||||
do_execsql_test 4.1.1 {
|
||||
CREATE TABLE t4(a, b);
|
||||
CREATE TABLE t5(c, d);
|
||||
|
||||
INSERT INTO t5 VALUES(1, 'x');
|
||||
INSERT INTO t5 VALUES(2, 'x');
|
||||
INSERT INTO t4 VALUES(3, 'x');
|
||||
INSERT INTO t4 VALUES(4, 'x');
|
||||
|
||||
CREATE INDEX i1 ON t4(a);
|
||||
CREATE INDEX i2 ON t5(c);
|
||||
}
|
||||
|
||||
do_eqp_test 4.1.2 {
|
||||
SELECT c, d FROM t5
|
||||
UNION ALL
|
||||
SELECT a, b FROM t4 WHERE f()==f()
|
||||
ORDER BY 1,2
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t5 USING INDEX i2}
|
||||
1 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
2 0 0 {SCAN TABLE t4 USING INDEX i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
|
||||
}
|
||||
|
||||
do_execsql_test 4.1.3 {
|
||||
SELECT c, d FROM t5
|
||||
UNION ALL
|
||||
SELECT a, b FROM t4 WHERE f()==f()
|
||||
ORDER BY 1,2
|
||||
} {
|
||||
1 x 2 x 3 x 4 x
|
||||
}
|
||||
|
||||
do_execsql_test 4.2.1 {
|
||||
CREATE TABLE t6(a, b);
|
||||
CREATE TABLE t7(c, d);
|
||||
|
||||
INSERT INTO t7 VALUES(2, 9);
|
||||
INSERT INTO t6 VALUES(3, 0);
|
||||
INSERT INTO t6 VALUES(4, 1);
|
||||
INSERT INTO t7 VALUES(5, 6);
|
||||
INSERT INTO t6 VALUES(6, 0);
|
||||
INSERT INTO t7 VALUES(7, 6);
|
||||
|
||||
CREATE INDEX i6 ON t6(a);
|
||||
CREATE INDEX i7 ON t7(c);
|
||||
}
|
||||
|
||||
do_execsql_test 4.2.2 {
|
||||
SELECT c, f(d,c,d,c,d) FROM t7
|
||||
UNION ALL
|
||||
SELECT a, b FROM t6
|
||||
ORDER BY 1,2
|
||||
} {/2 . 3 . 4 . 5 . 6 . 7 ./}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+54
-2
@@ -302,8 +302,60 @@ do_test shell5-1.11 {
|
||||
sqlite3 db test.db
|
||||
db eval {SELECT *, '|' FROM t1}
|
||||
} {a b { } | x y {} | p q r |}
|
||||
|
||||
|
||||
db close
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
sqlite3 db test.db
|
||||
do_test shell5-2.1 {
|
||||
set fd [open shell5.csv w]
|
||||
puts $fd ",hello"
|
||||
close $fd
|
||||
catchcmd test.db [string trim {
|
||||
.mode csv
|
||||
CREATE TABLE t1(a, b);
|
||||
.import shell5.csv t1
|
||||
}]
|
||||
db eval { SELECT * FROM t1 }
|
||||
} {{} hello}
|
||||
|
||||
do_test shell5-2.2 {
|
||||
set fd [open shell5.csv w]
|
||||
puts $fd {"",hello}
|
||||
close $fd
|
||||
catchcmd test.db [string trim {
|
||||
.mode csv
|
||||
CREATE TABLE t2(a, b);
|
||||
.import shell5.csv t2
|
||||
}]
|
||||
db eval { SELECT * FROM t2 }
|
||||
} {{} hello}
|
||||
|
||||
do_test shell5-2.3 {
|
||||
set fd [open shell5.csv w]
|
||||
puts $fd {"x""y",hello}
|
||||
close $fd
|
||||
catchcmd test.db [string trim {
|
||||
.mode csv
|
||||
CREATE TABLE t3(a, b);
|
||||
.import shell5.csv t3
|
||||
}]
|
||||
db eval { SELECT * FROM t3 }
|
||||
} {x\"y hello}
|
||||
|
||||
do_test shell5-2.4 {
|
||||
set fd [open shell5.csv w]
|
||||
puts $fd {"xy""",hello}
|
||||
close $fd
|
||||
catchcmd test.db [string trim {
|
||||
.mode csv
|
||||
CREATE TABLE t4(a, b);
|
||||
.import shell5.csv t4
|
||||
}]
|
||||
db eval { SELECT * FROM t4 }
|
||||
} {xy\" hello}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/tclsh
|
||||
#
|
||||
# This script displays the field of rectangles used by --testset rtree
|
||||
# of speedtest1. Run this script as follows:
|
||||
#
|
||||
# rm test.db
|
||||
# ./speedtest1 --testset rtree --size 25 test.db
|
||||
# sqlite3 --separator ' ' test.db 'SELECT * FROM rt1' >data.txt
|
||||
# wish show_speedtest1_rtree.tcl
|
||||
#
|
||||
# The filename "data.txt" is hard coded into this script and so that name
|
||||
# must be used on lines 3 and 4 above. Elsewhere, different filenames can
|
||||
# be used. The --size N parameter can be adjusted as desired.
|
||||
#
|
||||
package require Tk
|
||||
set f [open data.txt rb]
|
||||
set data [read $f]
|
||||
close $f
|
||||
canvas .c
|
||||
frame .b
|
||||
button .b.b1 -text X-Y -command refill-xy
|
||||
button .b.b2 -text X-Z -command refill-xz
|
||||
button .b.b3 -text Y-Z -command refill-yz
|
||||
pack .b.b1 .b.b2 .b.b3 -side left
|
||||
pack .c -side top -fill both -expand 1
|
||||
pack .b -side top
|
||||
proc resize_canvas_to_fit {} {
|
||||
foreach {x0 y0 x1 y1} [.c bbox all] break
|
||||
set w [expr {$x1-$x0}]
|
||||
set h [expr {$y1-$y0}]
|
||||
.c config -width $w -height $h
|
||||
}
|
||||
proc refill-xy {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $x0 $y0 $x1 $y1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
proc refill-xz {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $x0 $z0 $x1 $z1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
proc refill-yz {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $y0 $z0 $y1 $z1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
refill-xy
|
||||
+1
-1
@@ -181,7 +181,7 @@ do_execsql_test skipscan1-3.2 {
|
||||
do_execsql_test skipscan1-3.2eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a;
|
||||
} {/* INDEX sqlite_autoindex_t3_1 (ANY(a) AND b=?)*/}
|
||||
} {/* PRIMARY KEY (ANY(a) AND b=?)*/}
|
||||
do_execsql_test skipscan1-3.2sort {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a;
|
||||
|
||||
@@ -74,6 +74,7 @@ do_execsql_test skipscan2-1.4 {
|
||||
-- of a skip-scan. So make a manual adjustment to the stat1 table
|
||||
-- to make it seem like there are many more.
|
||||
UPDATE sqlite_stat1 SET stat='10000 5000 20' WHERE idx='people_idx1';
|
||||
UPDATE sqlite_stat1 SET stat='10000 1' WHERE idx='sqlite_autoindex_people_1';
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
db cache flush
|
||||
@@ -185,6 +186,20 @@ do_execsql_test skipscan2-2.5eqp {
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX peoplew_idx1 */}
|
||||
|
||||
# A skip-scan on a PK index of a WITHOUT ROWID table.
|
||||
#
|
||||
do_execsql_test skipscan2-3.1 {
|
||||
CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID;
|
||||
}
|
||||
do_test skipscan2-3.2 {
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') }
|
||||
}
|
||||
execsql { ANALYZE }
|
||||
} {}
|
||||
do_eqp_test skipscan2-3.3eqp {
|
||||
SELECT * FROM t3 WHERE b=42;
|
||||
} {0 0 0 {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+185
-1
@@ -29,6 +29,7 @@ static const char zHelp[] =
|
||||
" --trace Turn on SQL tracing\n"
|
||||
" --utf16be Set text encoding to UTF-16BE\n"
|
||||
" --utf16le Set text encoding to UTF-16LE\n"
|
||||
" --verify Run additional verification steps.\n"
|
||||
" --without-rowid Use WITHOUT ROWID where appropriate\n"
|
||||
;
|
||||
|
||||
@@ -51,6 +52,7 @@ static struct Global {
|
||||
int bReprepare; /* True to reprepare the SQL on each rerun */
|
||||
int bSqlOnly; /* True to print the SQL once only */
|
||||
int bExplain; /* Print SQL with EXPLAIN prefix */
|
||||
int bVerify; /* Try to verify that results are correct */
|
||||
int szTest; /* Scale factor for test iterations */
|
||||
const char *zWR; /* Might be WITHOUT ROWID */
|
||||
const char *zNN; /* Might be NOT NULL */
|
||||
@@ -931,6 +933,183 @@ void testset_cte(void){
|
||||
|
||||
}
|
||||
|
||||
/* Generate two numbers between 1 and mx. The first number is less than
|
||||
** the second. Usually the numbers are near each other but can sometimes
|
||||
** be far apart.
|
||||
*/
|
||||
static void twoCoords(
|
||||
int p1, int p2, /* Parameters adjusting sizes */
|
||||
unsigned mx, /* Range of 1..mx */
|
||||
unsigned *pX0, unsigned *pX1 /* OUT: write results here */
|
||||
){
|
||||
unsigned d, x0, x1, span;
|
||||
|
||||
span = mx/100 + 1;
|
||||
if( speedtest1_random()%3==0 ) span *= p1;
|
||||
if( speedtest1_random()%p2==0 ) span = mx/2;
|
||||
d = speedtest1_random()%span + 1;
|
||||
x0 = speedtest1_random()%(mx-d) + 1;
|
||||
x1 = x0 + d;
|
||||
*pX0 = x0;
|
||||
*pX1 = x1;
|
||||
}
|
||||
|
||||
/* The following routine is an R-Tree geometry callback. It returns
|
||||
** true if the object overlaps a slice on the Y coordinate between the
|
||||
** two values given as arguments. In other words
|
||||
**
|
||||
** SELECT count(*) FROM rt1 WHERE id MATCH xslice(10,20);
|
||||
**
|
||||
** Is the same as saying:
|
||||
**
|
||||
** SELECT count(*) FROM rt1 WHERE y1>=10 AND y0<=20;
|
||||
*/
|
||||
static int xsliceGeometryCallback(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
double *aCoord,
|
||||
int *pRes
|
||||
){
|
||||
*pRes = aCoord[3]>=p->aParam[0] && aCoord[2]<=p->aParam[1];
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset for the R-Tree virtual table
|
||||
*/
|
||||
void testset_rtree(int p1, int p2){
|
||||
unsigned i, n;
|
||||
unsigned mxCoord;
|
||||
unsigned x0, x1, y0, y1, z0, z1;
|
||||
unsigned iStep;
|
||||
int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*100 );
|
||||
|
||||
mxCoord = 15000;
|
||||
n = g.szTest*100;
|
||||
speedtest1_begin_test(100, "%d INSERTs into an r-tree", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)");
|
||||
speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)"
|
||||
"VALUES(?1,?2,?3,?4,?5,?6,?7)");
|
||||
for(i=1; i<=n; i++){
|
||||
twoCoords(p1, p2, mxCoord, &x0, &x1);
|
||||
twoCoords(p1, p2, mxCoord, &y0, &y1);
|
||||
twoCoords(p1, p2, mxCoord, &z0, &z1);
|
||||
sqlite3_bind_int(g.pStmt, 1, i);
|
||||
sqlite3_bind_int(g.pStmt, 2, x0);
|
||||
sqlite3_bind_int(g.pStmt, 3, x1);
|
||||
sqlite3_bind_int(g.pStmt, 4, y0);
|
||||
sqlite3_bind_int(g.pStmt, 5, y1);
|
||||
sqlite3_bind_int(g.pStmt, 6, z0);
|
||||
sqlite3_bind_int(g.pStmt, 7, z1);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(101, "Copy from rtree to a regular table");
|
||||
speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)");
|
||||
speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1");
|
||||
speedtest1_end_test();
|
||||
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n);
|
||||
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
aCheck[i] = atoi(g.zResult);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
if( g.bVerify ){
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries");
|
||||
speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
if( aCheck[i]!=atoi(g.zResult) ){
|
||||
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
|
||||
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
|
||||
}
|
||||
}
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n);
|
||||
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
aCheck[i] = atoi(g.zResult);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
if( g.bVerify ){
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries");
|
||||
speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
if( aCheck[i]!=atoi(g.zResult) ){
|
||||
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
|
||||
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
|
||||
}
|
||||
}
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(125, "%d custom geometry callback queries", n);
|
||||
sqlite3_rtree_geometry_callback(g.db, "xslice", xsliceGeometryCallback, 0);
|
||||
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE id MATCH xslice(?1,?2)");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
if( aCheck[i]!=atoi(g.zResult) ){
|
||||
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
|
||||
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
|
||||
}
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
n = g.szTest*80;
|
||||
speedtest1_begin_test(130, "%d three-dimensional intersect box queries", n);
|
||||
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x1>=?1 AND x0<=?2"
|
||||
" AND y1>=?1 AND y0<=?2 AND z1>=?1 AND z0<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
aCheck[i] = atoi(g.zResult);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
n = g.szTest*100;
|
||||
speedtest1_begin_test(140, "%d rowid queries", n);
|
||||
speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1");
|
||||
for(i=1; i<=n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset used for debugging speedtest1 itself.
|
||||
*/
|
||||
@@ -1050,6 +1229,8 @@ int main(int argc, char **argv){
|
||||
zEncoding = "utf16le";
|
||||
}else if( strcmp(z,"utf16be")==0 ){
|
||||
zEncoding = "utf16be";
|
||||
}else if( strcmp(z,"verify")==0 ){
|
||||
g.bVerify = 1;
|
||||
}else if( strcmp(z,"without-rowid")==0 ){
|
||||
g.zWR = "WITHOUT ROWID";
|
||||
g.zPK = "PRIMARY KEY";
|
||||
@@ -1141,8 +1322,11 @@ int main(int argc, char **argv){
|
||||
testset_debug1();
|
||||
}else if( strcmp(zTSet,"cte")==0 ){
|
||||
testset_cte();
|
||||
}else if( strcmp(zTSet,"rtree")==0 ){
|
||||
testset_rtree(6, 147);
|
||||
}else{
|
||||
fatal_error("unknown testset: \"%s\"\n", zTSet);
|
||||
fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree\n",
|
||||
zTSet);
|
||||
}
|
||||
speedtest1_final();
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# 2014-04-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.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
# Test that ticket [b75a9ca6b0] has been fixed.
|
||||
#
|
||||
# Ticket [b75a9ca6b0] concerns queries that have both a GROUP BY
|
||||
# and an ORDER BY. This code verifies that SQLite is able to
|
||||
# optimize out the ORDER BY in some circumstances, but retains the
|
||||
# ORDER BY when necessary.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix tkt-b75a9ca6b0
|
||||
|
||||
do_execsql_test 1 {
|
||||
CREATE TABLE t1 (x, y);
|
||||
INSERT INTO t1 VALUES (1, 3);
|
||||
INSERT INTO t1 VALUES (2, 2);
|
||||
INSERT INTO t1 VALUES (3, 1);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE INDEX i1 ON t1(x, y);
|
||||
}
|
||||
|
||||
set idxscan {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}}
|
||||
set tblscan {0 0 0 {SCAN TABLE t1}}
|
||||
set grpsort {0 0 0 {USE TEMP B-TREE FOR GROUP BY}}
|
||||
set sort {0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
|
||||
|
||||
foreach {tn q res eqp} [subst -nocommands {
|
||||
1 "SELECT * FROM t1 GROUP BY x, y ORDER BY x,y"
|
||||
{1 3 2 2 3 1} {$idxscan}
|
||||
|
||||
2 "SELECT * FROM t1 GROUP BY x, y ORDER BY x"
|
||||
{1 3 2 2 3 1} {$idxscan $sort}
|
||||
|
||||
3 "SELECT * FROM t1 GROUP BY y, x ORDER BY y, x"
|
||||
{3 1 2 2 1 3} {$idxscan $sort}
|
||||
|
||||
4 "SELECT * FROM t1 GROUP BY x ORDER BY x"
|
||||
{1 3 2 2 3 1} {$idxscan}
|
||||
|
||||
5 "SELECT * FROM t1 GROUP BY y ORDER BY y"
|
||||
{3 1 2 2 1 3} {$tblscan $grpsort}
|
||||
|
||||
6 "SELECT * FROM t1 GROUP BY y ORDER BY x"
|
||||
{1 3 2 2 3 1} {$tblscan $grpsort $sort}
|
||||
|
||||
7 "SELECT * FROM t1 GROUP BY x, y ORDER BY x, y DESC"
|
||||
{1 3 2 2 3 1} {$idxscan $sort}
|
||||
|
||||
8 "SELECT * FROM t1 GROUP BY x, y ORDER BY x DESC, y DESC"
|
||||
{3 1 2 2 1 3} {$idxscan $sort}
|
||||
|
||||
9 "SELECT * FROM t1 GROUP BY x, y ORDER BY x ASC, y ASC"
|
||||
{1 3 2 2 3 1} {$idxscan}
|
||||
|
||||
10 "SELECT * FROM t1 GROUP BY x, y ORDER BY x COLLATE nocase, y"
|
||||
{1 3 2 2 3 1} {$idxscan $sort}
|
||||
|
||||
}] {
|
||||
do_execsql_test 1.$tn.1 $q $res
|
||||
do_eqp_test 1.$tn.2 $q $eqp
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,53 @@
|
||||
# 2014 April 26
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Test that ticket f67b41381a has been resolved.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix tkt-f67b41381a
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
ALTER TABLE t1 ADD COLUMN b DEFAULT 2;
|
||||
CREATE TABLE t2(a, b);
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
} {1 2}
|
||||
|
||||
db cache size 0
|
||||
foreach {tn tbls xfer} {
|
||||
1 { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b) } 1
|
||||
2 { CREATE TABLE t1(a, b DEFAULT 'x'); CREATE TABLE t2(a, b) } 0
|
||||
3 { CREATE TABLE t1(a, b DEFAULT 'x'); CREATE TABLE t2(a, b DEFAULT 'x') } 1
|
||||
4 { CREATE TABLE t1(a, b DEFAULT NULL); CREATE TABLE t2(a, b) } 0
|
||||
5 { CREATE TABLE t1(a DEFAULT 2, b); CREATE TABLE t2(a DEFAULT 1, b) } 1
|
||||
6 { CREATE TABLE t1(a DEFAULT 1, b); CREATE TABLE t2(a DEFAULT 1, b) } 1
|
||||
7 { CREATE TABLE t1(a DEFAULT 1, b DEFAULT 1);
|
||||
CREATE TABLE t2(a DEFAULT 3, b DEFAULT 1) } 1
|
||||
8 { CREATE TABLE t1(a DEFAULT 1, b DEFAULT 1);
|
||||
CREATE TABLE t2(a DEFAULT 3, b DEFAULT 3) } 0
|
||||
|
||||
} {
|
||||
|
||||
execsql { DROP TABLE t1; DROP TABLE t2 }
|
||||
execsql $tbls
|
||||
|
||||
set res 1
|
||||
db eval { EXPLAIN INSERT INTO t1 SELECT * FROM t2 } {
|
||||
if {$opcode == "Column"} { set res 0 }
|
||||
}
|
||||
|
||||
do_test 2.$tn [list set res] $xfer
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -136,6 +136,7 @@ ifcapable fts3 {
|
||||
"-- SELECT (SELECT max(idx) FROM 'main'.'x1_segdir' WHERE level = ?) + 1"
|
||||
"-- SELECT coalesce((SELECT max(blockid) FROM 'main'.'x1_segments') + 1, 1)"
|
||||
"-- REPLACE INTO 'main'.'x1_segdir' VALUES(?,?,?,?,?,?)"
|
||||
"-- SELECT level, idx, end_block FROM 'main'.'x1_segdir' WHERE level BETWEEN ? AND ? ORDER BY level DESC, idx ASC"
|
||||
}
|
||||
|
||||
do_trace_test 2.3 {
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ foreach idxmode {ordered unordered} {
|
||||
1 "SELECT * FROM t1 ORDER BY a"
|
||||
{0 0 0 {SCAN TABLE t1 USING INDEX i1}}
|
||||
{0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
|
||||
2 "SELECT * FROM t1 WHERE a >?"
|
||||
2 "SELECT * FROM t1 WHERE a > 100"
|
||||
{0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
|
||||
{0 0 0 {SCAN TABLE t1}}
|
||||
3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid"
|
||||
|
||||
+7
-1
@@ -811,7 +811,13 @@ do_test wal2-7.1.1 {
|
||||
do_test wal2-7.1.2 {
|
||||
forcecopy test.db test2.db
|
||||
forcecopy test.db-wal test2.db-wal
|
||||
hexio_write test2.db-wal 48 FF
|
||||
# The first 32 bytes of the WAL file contain the WAL header. Offset 48
|
||||
# is the first byte of the checksum for the first frame in the WAL.
|
||||
# The following three lines replaces the contents of that byte with
|
||||
# a different value.
|
||||
set newval FF
|
||||
if {$newval == [hexio_read test2.db-wal 48 1]} { set newval 00 }
|
||||
hexio_write test2.db-wal 48 $newval
|
||||
} {1}
|
||||
do_test wal2-7.1.3 {
|
||||
sqlite3 db2 test2.db
|
||||
|
||||
+2
-1
@@ -231,6 +231,7 @@ do_execsql_test where3-3.0 {
|
||||
CREATE TABLE t301(a INTEGER PRIMARY KEY,b,c);
|
||||
CREATE INDEX t301c ON t301(c);
|
||||
INSERT INTO t301 VALUES(1,2,3);
|
||||
INSERT INTO t301 VALUES(2,2,3);
|
||||
CREATE TABLE t302(x, y);
|
||||
INSERT INTO t302 VALUES(4,5);
|
||||
ANALYZE;
|
||||
@@ -251,7 +252,7 @@ do_execsql_test where3-3.2 {
|
||||
} {}
|
||||
do_execsql_test where3-3.3 {
|
||||
SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL;
|
||||
} {1 2 3}
|
||||
} {1 2 3 2 2 3}
|
||||
|
||||
if 0 { # Query planner no longer does this
|
||||
# Verify that when there are multiple tables in a join which must be
|
||||
|
||||
@@ -217,6 +217,59 @@ do_execsql_test 4.7 {
|
||||
ORDER BY a;
|
||||
} {3 4 3 4}
|
||||
|
||||
# Verify fix of a bug reported on the mailing list by Peter Reid
|
||||
#
|
||||
do_execsql_test 5.1 {
|
||||
DROP TABLE IF EXISTS t;
|
||||
CREATE TABLE t(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17);
|
||||
CREATE INDEX tc0 ON t(c0);
|
||||
CREATE INDEX tc1 ON t(c1);
|
||||
CREATE INDEX tc2 ON t(c2);
|
||||
CREATE INDEX tc3 ON t(c3);
|
||||
CREATE INDEX tc4 ON t(c4);
|
||||
CREATE INDEX tc5 ON t(c5);
|
||||
CREATE INDEX tc6 ON t(c6);
|
||||
CREATE INDEX tc7 ON t(c7);
|
||||
CREATE INDEX tc8 ON t(c8);
|
||||
CREATE INDEX tc9 ON t(c9);
|
||||
CREATE INDEX tc10 ON t(c10);
|
||||
CREATE INDEX tc11 ON t(c11);
|
||||
CREATE INDEX tc12 ON t(c12);
|
||||
CREATE INDEX tc13 ON t(c13);
|
||||
CREATE INDEX tc14 ON t(c14);
|
||||
CREATE INDEX tc15 ON t(c15);
|
||||
CREATE INDEX tc16 ON t(c16);
|
||||
CREATE INDEX tc17 ON t(c17);
|
||||
|
||||
INSERT INTO t(c0, c16) VALUES (1,1);
|
||||
|
||||
SELECT * FROM t WHERE
|
||||
c0=1 or c1=1 or c2=1 or c3=1 or
|
||||
c4=1 or c5=1 or c6=1 or c7=1 or
|
||||
c8=1 or c9=1 or c10=1 or c11=1 or
|
||||
c12=1 or c13=1 or c14=1 or c15=1 or
|
||||
c16=1 or c17=1;
|
||||
} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {}}
|
||||
do_execsql_test 5.2 {
|
||||
DELETE FROM t;
|
||||
INSERT INTO t(c0,c17) VALUES(1,1);
|
||||
SELECT * FROM t WHERE
|
||||
c0=1 or c1=1 or c2=1 or c3=1 or
|
||||
c4=1 or c5=1 or c6=1 or c7=1 or
|
||||
c8=1 or c9=1 or c10=1 or c11=1 or
|
||||
c12=1 or c13=1 or c14=1 or c15=1 or
|
||||
c16=1 or c17=1;
|
||||
} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1}
|
||||
do_execsql_test 5.3 {
|
||||
DELETE FROM t;
|
||||
INSERT INTO t(c0,c15) VALUES(1,1);
|
||||
SELECT * FROM t WHERE
|
||||
c0=1 or c1=1 or c2=1 or c3=1 or
|
||||
c4=1 or c5=1 or c6=1 or c7=1 or
|
||||
c8=1 or c9=1 or c10=1 or c11=1 or
|
||||
c12=1 or c13=1 or c14=1 or c15=1 or
|
||||
c16=1 or c17=1;
|
||||
} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {} {}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user