1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Merge the latest trunk changes into the sessions branch.

FossilOrigin-Name: 110cfd6920cf3011aeaf7e586f8db867bfc69fbb
This commit is contained in:
drh
2011-07-22 12:49:27 +00:00
66 changed files with 2402 additions and 935 deletions

View File

@@ -517,6 +517,9 @@ sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl
sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl
$(TCLSH_CMD) $(TOP)/tool/split-sqlite3c.tcl
# Rule to build the amalgamation # Rule to build the amalgamation
# #
sqlite3.lo: sqlite3.c sqlite3.lo: sqlite3.c
@@ -785,7 +788,7 @@ parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/addopcodes.awk
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h $(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
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h $(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
keywordhash.h: $(TOP)/tool/mkkeywordhash.c keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c $(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c

View File

@@ -43,16 +43,32 @@ TCC = $(TCC) -I$(TOP)\ext\rtree
# #
TCC = $(TCC) -DNDEBUG TCC = $(TCC) -DNDEBUG
# The library that programs using TCL must link against. # The locations of the Tcl header and library files. Also, the library that
# non-stubs enabled programs using Tcl must link against. These variables
# (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment
# prior to running nmake in order to match the actual installed location and
# version on this machine.
# #
LIBTCL = tcl85.lib !if "$(TCLINCDIR)" == ""
TCLINCDIR = c:\tcl\include TCLINCDIR = c:\tcl\include
!endif
!if "$(TCLLIBDIR)" == ""
TCLLIBDIR = c:\tcl\lib TCLLIBDIR = c:\tcl\lib
!endif
!if "$(LIBTCL)" == ""
LIBTCL = tcl85.lib
!endif
# This is the command to use for tclsh - normally just "tclsh", but we may # This is the command to use for tclsh - normally just "tclsh", but we may
# know the specific version we want to use # know the specific version we want to use. This variable (TCLSH_CMD) may be
# overridden via the environment prior to running nmake in order to select a
# specific Tcl shell to use.
# #
!if "$(TCLSH_CMD)" == ""
TCLSH_CMD = tclsh85 TCLSH_CMD = tclsh85
!endif
# Compiler options needed for programs that use the readline() library. # Compiler options needed for programs that use the readline() library.
# #
@@ -118,7 +134,7 @@ LTLIBOPTS = /MACHINE:$(PLATFORM)
!ENDIF !ENDIF
# nawk compatible awk. # nawk compatible awk.
NAWK = .\gawk.exe NAWK = gawk.exe
# You should not have to change anything below this line # You should not have to change anything below this line
############################################################################### ###############################################################################
@@ -439,7 +455,7 @@ EXTHDR = $(EXTHDR) \
# This is the default Makefile target. The objects listed here # This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments. # are what get build when you type just "make" with no arguments.
# #
all: libsqlite3.lib sqlite3.exe libtclsqlite3.lib all: dll libsqlite3.lib sqlite3.exe libtclsqlite3.lib
libsqlite3.lib: $(LIBOBJ) libsqlite3.lib: $(LIBOBJ)
$(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS) $(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS)
@@ -463,13 +479,16 @@ sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib sqlite3.h
-mkdir tsrc -mkdir tsrc
for %i in ($(SRC)) do copy /Y %i tsrc for %i in ($(SRC)) do copy /Y %i tsrc
del /Q tsrc\sqlite.h.in tsrc\parse.y del /Q tsrc\sqlite.h.in tsrc\parse.y
$(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl <tsrc\vdbe.c >vdbe.new $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl < tsrc\vdbe.c > vdbe.new
move vdbe.new tsrc\vdbe.c move vdbe.new tsrc\vdbe.c
echo > .target_source echo > .target_source
sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl
$(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl
sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl
$(TCLSH_CMD) $(TOP)/tool/split-sqlite3c.tcl
# Rule to build the amalgamation # Rule to build the amalgamation
# #
sqlite3.lo: sqlite3.c sqlite3.lo: sqlite3.c
@@ -720,10 +739,10 @@ tclsqlite3.exe: tclsqlite-shell.lo libsqlite3.lib
# Rules to build opcodes.c and opcodes.h # Rules to build opcodes.c and opcodes.h
# #
opcodes.c: opcodes.h $(TOP)\mkopcodec.awk opcodes.c: opcodes.h $(TOP)\mkopcodec.awk
$(NAWK) "/#define OP_/ { print }" opcodes.h | sort /+45 | $(NAWK) -f $(TOP)\mkopcodec.awk >opcodes.c $(NAWK) "/#define OP_/ { print }" opcodes.h | sort /+45 | $(NAWK) -f $(TOP)\mkopcodec.awk > opcodes.c
opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\mkopcodeh.awk opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\mkopcodeh.awk
type parse.h $(TOP)\src\vdbe.c | $(NAWK) -f $(TOP)\mkopcodeh.awk >opcodes.h type parse.h $(TOP)\src\vdbe.c | $(NAWK) -f $(TOP)\mkopcodeh.awk > opcodes.h
# Rules to build parse.c and parse.h - the outputs of lemon. # Rules to build parse.c and parse.h - the outputs of lemon.
# #
@@ -734,16 +753,16 @@ parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\addopcodes.awk
copy $(TOP)\src\parse.y . copy $(TOP)\src\parse.y .
.\lemon.exe $(OPT_FEATURE_FLAGS) $(OPTS) parse.y .\lemon.exe $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
move parse.h parse.h.temp move parse.h parse.h.temp
$(NAWK) -f $(TOP)\addopcodes.awk parse.h.temp >parse.h $(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
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP) >sqlite3.h $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP) > sqlite3.h
mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c
$(BCC) -Femkkeywordhash.exe $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c $(BCC) -Femkkeywordhash.exe $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c
keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
.\mkkeywordhash.exe >keywordhash.h .\mkkeywordhash.exe > keywordhash.h
@@ -839,7 +858,7 @@ test: testfixture.exe sqlite3.exe
spaceanal_tcl.h: $(TOP)\tool\spaceanal.tcl spaceanal_tcl.h: $(TOP)\tool\spaceanal.tcl
$(NAWK) -f $(TOP)/tool/tostr.awk \ $(NAWK) -f $(TOP)/tool/tostr.awk \
$(TOP)\tool\spaceanal.tcl >spaceanal_tcl.h $(TOP)\tool\spaceanal.tcl > spaceanal_tcl.h
sqlite3_analyzer.exe: $(TESTFIXTURE_SRC) spaceanal_tcl.h sqlite3_analyzer.exe: $(TESTFIXTURE_SRC) spaceanal_tcl.h
$(LTLINK) -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 \ $(LTLINK) -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 \
@@ -866,10 +885,10 @@ clean:
dll: sqlite3.dll dll: sqlite3.dll
sqlite3.def: libsqlite3.lib sqlite3.def: libsqlite3.lib
echo EXPORTS >sqlite3.def echo EXPORTS > sqlite3.def
dumpbin /all libsqlite3.lib \ dumpbin /all libsqlite3.lib \
| $(NAWK) "/ 1 _sqlite3_/ { sub(/^.* _/,\"\");print }" \ | $(NAWK) "/ 1 _sqlite3_/ { sub(/^.* _/,\"\");print }" \
| sort >>sqlite3.def | sort >> sqlite3.def
sqlite3.dll: $(LIBOBJ) sqlite3.def sqlite3.dll: $(LIBOBJ) sqlite3.def
link $(LTLINKOPTS) /DLL /DEF:sqlite3.def /OUT:$@ $(LIBOBJ) link $(LTLINKOPTS) /DLL /DEF:sqlite3.def /OUT:$@ $(LIBOBJ)

View File

@@ -1 +1 @@
3.7.7 3.7.8

18
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.7.7. # Generated by GNU Autoconf 2.62 for sqlite 3.7.8.
# #
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package. # Identity of this package.
PACKAGE_NAME='sqlite' PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite' PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.7.7' PACKAGE_VERSION='3.7.8'
PACKAGE_STRING='sqlite 3.7.7' PACKAGE_STRING='sqlite 3.7.8'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
# Factoring default headers for most tests. # Factoring default headers for most tests.
@@ -1485,7 +1485,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures sqlite 3.7.7 to adapt to many kinds of systems. \`configure' configures sqlite 3.7.8 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1550,7 +1550,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.7.7:";; short | recursive ) echo "Configuration of sqlite 3.7.8:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1666,7 +1666,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
sqlite configure 3.7.7 sqlite configure 3.7.8
generated by GNU Autoconf 2.62 generated by GNU Autoconf 2.62
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1680,7 +1680,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.7.7, which was It was created by sqlite $as_me 3.7.8, which was
generated by GNU Autoconf 2.62. Invocation command line was generated by GNU Autoconf 2.62. Invocation command line was
$ $0 $@ $ $0 $@
@@ -14030,7 +14030,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by sqlite $as_me 3.7.7, which was This file was extended by sqlite $as_me 3.7.8, which was
generated by GNU Autoconf 2.62. Invocation command line was generated by GNU Autoconf 2.62. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -14083,7 +14083,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\ ac_cs_version="\\
sqlite config.status 3.7.7 sqlite config.status 3.7.8
configured by $0, generated by GNU Autoconf 2.62, configured by $0, generated by GNU Autoconf 2.62,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

File diff suppressed because it is too large Load Diff

View File

@@ -27,7 +27,14 @@
# define SQLITE_ENABLE_FTS3 # define SQLITE_ENABLE_FTS3
#endif #endif
#ifdef SQLITE_ENABLE_FTS3 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* If not building as part of the core, include sqlite3ext.h. */
#ifndef SQLITE_CORE
# include "sqlite3ext.h"
extern const sqlite3_api_routines *sqlite3_api;
#endif
#include "sqlite3.h" #include "sqlite3.h"
#include "fts3_tokenizer.h" #include "fts3_tokenizer.h"
#include "fts3_hash.h" #include "fts3_hash.h"
@@ -290,7 +297,7 @@ struct Fts3Doclist {
int bFreeList; /* True if pList should be sqlite3_free()d */ int bFreeList; /* True if pList should be sqlite3_free()d */
char *pList; /* Pointer to position list following iDocid */ char *pList; /* Pointer to position list following iDocid */
int nList; /* Length of position list */ int nList; /* Length of position list */
} doclist; };
/* /*
** A "phrase" is a sequence of one or more tokens that must match in ** A "phrase" is a sequence of one or more tokens that must match in
@@ -490,19 +497,8 @@ int sqlite3Fts3InitTerm(sqlite3 *db);
/* fts3_aux.c */ /* fts3_aux.c */
int sqlite3Fts3InitAux(sqlite3 *db); int sqlite3Fts3InitAux(sqlite3 *db);
int sqlite3Fts3TermSegReaderCursor(
Fts3Cursor *pCsr, /* Virtual table cursor handle */
const char *zTerm, /* Term to query for */
int nTerm, /* Size of zTerm in bytes */
int isPrefix, /* True for a prefix search */
Fts3MultiSegReader **ppSegcsr /* OUT: Allocated seg-reader cursor */
);
void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *); void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *);
int sqlite3Fts3EvalStart(Fts3Cursor *, Fts3Expr *, int);
int sqlite3Fts3EvalNext(Fts3Cursor *pCsr);
int sqlite3Fts3MsrIncrStart( int sqlite3Fts3MsrIncrStart(
Fts3Table*, Fts3MultiSegReader*, int, const char*, int); Fts3Table*, Fts3MultiSegReader*, int, const char*, int);
int sqlite3Fts3MsrIncrNext( int sqlite3Fts3MsrIncrNext(
@@ -513,5 +509,5 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *); int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *);
#endif /* SQLITE_ENABLE_FTS3 */ #endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */ #endif /* _FTSINT_H */

View File

@@ -30,7 +30,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "sqlite3.h"
#include "fts3_hash.h" #include "fts3_hash.h"
/* /*

View File

@@ -19,6 +19,8 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#ifdef SQLITE_TEST
/* Required so that the "ifdef SQLITE_ENABLE_FTS3" below works */ /* Required so that the "ifdef SQLITE_ENABLE_FTS3" below works */
#include "fts3Int.h" #include "fts3Int.h"
@@ -319,3 +321,4 @@ int Sqlitetestfts3_Init(Tcl_Interp *interp){
); );
return TCL_OK; return TCL_OK;
} }
#endif /* ifdef SQLITE_TEST */

View File

@@ -23,12 +23,7 @@
** * The FTS3 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#include "sqlite3ext.h"
#ifndef SQLITE_CORE
SQLITE_EXTENSION_INIT1
#endif
#include "fts3Int.h" #include "fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include <assert.h> #include <assert.h>

10
main.mk
View File

@@ -386,6 +386,9 @@ sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl
echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c
cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c
sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl
tclsh $(TOP)/tool/split-sqlite3c.tcl
fts2amal.c: target_source $(TOP)/ext/fts2/mkfts2amal.tcl fts2amal.c: target_source $(TOP)/ext/fts2/mkfts2amal.tcl
tclsh $(TOP)/ext/fts2/mkfts2amal.tcl tclsh $(TOP)/ext/fts2/mkfts2amal.tcl
@@ -568,6 +571,13 @@ $(TEST_EXTENSION): $(TOP)/src/test_loadext.c
extensiontest: testfixture$(EXE) $(TEST_EXTENSION) extensiontest: testfixture$(EXE) $(TEST_EXTENSION)
./testfixture$(EXE) $(TOP)/test/loadext.test ./testfixture$(EXE) $(TOP)/test/loadext.test
# This target will fail if the SQLite amalgamation contains any exported
# symbols that do not begin with "sqlite3_". It is run as part of the
# releasetest.tcl script.
#
checksymbols: sqlite3.o
nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0
# Standard install and cleanup targets # Standard install and cleanup targets
# #

137
manifest
View File

@@ -1,12 +1,12 @@
C Fix\sthe\ssqlite3session_isempty()\smethod\sso\sthat\sit\sreturns,\sas\sdocumented,\snon-zero\swhen\sno\schanges\shave\sbeen\srecorded\sby\sthe\ssession\sobject. C Merge\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch.
D 2011-07-18T15:22:56.414 D 2011-07-22T12:49:27.667
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in c1d7a7f4fd8da6b1815032efca950e3d5125407e F Makefile.in 1e6988b3c11dee9bd5edc0c804bd4468d74a9cdc
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc 11082f65b452b908d93013292c17850378c39284 F Makefile.msc 8e04f517922b9e31a5bf975f07bb66df79ae7076
F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151 F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION 3fcdd7fbe3eb282df3978fe77288544543767961 F VERSION f724de7326e87b7f3b0a55f16ef4b4d993680d54
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531 F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248 F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
@@ -23,7 +23,7 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 405a958bdb3af382a809dccb08a44694923ddd61 F config.h.in 405a958bdb3af382a809dccb08a44694923ddd61
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure f9e97ee7cdc9848e2f3f5ef015fdf861f46fb1bf x F configure 93e7e695581fa7bef4949161453d9845c5592ad0 x
F configure.ac 298a759c086e72c013da459c2aec02a104f4224f F configure.ac 298a759c086e72c013da459c2aec02a104f4224f
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
@@ -62,19 +62,19 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c ca776037493d0081da70a6afc0df80f5ce347cb7 F ext/fts3/fts3.c f45ad45053a587ad1c005459b704b7ade8bd504e
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h fa493ccbad78a2c99ad1c984f651c0c202e68536 F ext/fts3/fts3Int.h 30063fdd0bc433b5db1532e3a363cb0f2f7e8eb3
F ext/fts3/fts3_aux.c 0ebfa7b86cf8ff6a0861605fcc63b83ec1b70691 F ext/fts3/fts3_aux.c 0ebfa7b86cf8ff6a0861605fcc63b83ec1b70691
F ext/fts3/fts3_expr.c 23791de01b3a5d313d76e02befd2601d4096bc2b F ext/fts3/fts3_expr.c 23791de01b3a5d313d76e02befd2601d4096bc2b
F ext/fts3/fts3_hash.c aad95afa01cf2a5ffaa448e4b0ab043880cd1efb F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
F ext/fts3/fts3_icu.c 6c8f395cdf9e1e3afa7fadb7e523dbbf381c6dfa F ext/fts3/fts3_icu.c 6c8f395cdf9e1e3afa7fadb7e523dbbf381c6dfa
F ext/fts3/fts3_porter.c 8d946908f4812c005d3d33fcbe78418b1f4eb70c F ext/fts3/fts3_porter.c 8d946908f4812c005d3d33fcbe78418b1f4eb70c
F ext/fts3/fts3_snippet.c 58b2ba2b934c1e2a2f6ac857d7f3c7e1a14b4532 F ext/fts3/fts3_snippet.c 58b2ba2b934c1e2a2f6ac857d7f3c7e1a14b4532
F ext/fts3/fts3_term.c a5457992723455a58804cb75c8cbd8978db5c2ef F ext/fts3/fts3_term.c a5457992723455a58804cb75c8cbd8978db5c2ef
F ext/fts3/fts3_test.c c0aae3219df989d3e827d07846097adf8cb09945 F ext/fts3/fts3_test.c 24fa13f330db011500acb95590da9eee24951894
F ext/fts3/fts3_tokenizer.c 6089986ebcfc19d4b7aabd2b92773368efa4354f F ext/fts3/fts3_tokenizer.c 9ff7ec66ae3c5c0340fa081958e64f395c71a106
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
F ext/fts3/fts3_tokenizer1.c 0dde8f307b8045565cf63797ba9acfaff1c50c68 F ext/fts3/fts3_tokenizer1.c 0dde8f307b8045565cf63797ba9acfaff1c50c68
F ext/fts3/fts3_write.c 194829c8fd024a448fc899e5ff02a8ed06595529 F ext/fts3/fts3_write.c 194829c8fd024a448fc899e5ff02a8ed06595529
@@ -115,7 +115,7 @@ F ext/session/sqlite3session.h 8dec372049532017d71c992609ca5450de7c5520
F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99 F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk f56d9895882f5cdd9f9f9ba8f8a679e9202288c1 F main.mk 47bb833f273c17812370a750b1a697cd14580b75
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@@ -138,15 +138,15 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 8c46f0ab69ad9549c75a3a91fed87abdaa743e2f F src/btree.c 8c46f0ab69ad9549c75a3a91fed87abdaa743e2f
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3 F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
F src/build.c 5a428625d21ad409514afb40ad083bee25dd957a F src/build.c 5e614e586d9f8a81c16c80b545b9e1747f96c1bb
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4 F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4
F src/date.c d3c11de76392ea62637bfac0f4655889fc2f5a85 F src/date.c a3c6842bad7ae632281811de112a8ba63ff08ab3
F src/delete.c 7a8683a38e86d48a0e67ef949fddac6daf46d89d F src/delete.c 614d6e012aa5b624e78f3b556243497825de196b
F src/expr.c ab46ab0f0c44979a8164ca31728d7d10ae5e8106 F src/expr.c 4bbdfaf66bc614be9254ce0c26a17429067a3e07
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 9fabba17a4d4778dc660f0cb9d781fc86d7b9d41 F src/fkey.c c8492fed772af1ed61251582707266227612b45b
F src/func.c 59bb046d7e3df1ab512ac339ccb0a6f996a17cb7 F src/func.c 59bb046d7e3df1ab512ac339ccb0a6f996a17cb7
F src/global.c c70a46f28680f8d7c097dbc0430ccf3b932e90b0 F src/global.c c70a46f28680f8d7c097dbc0430ccf3b932e90b0
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
@@ -156,13 +156,13 @@ F src/insert.c 1f1688a9da8b8e27114ba1909a6e74100791139b
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 3ae0d52da013a6326310655be6473fd472347b85 F src/loadext.c 99a161b27a499fc8ad40745b7b1900a26f0a5f51
F src/main.c 8a386605c22e4b2becfe96bab2ac7128b480d489 F src/main.c 8a386605c22e4b2becfe96bab2ac7128b480d489
F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9 F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3 F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f
F src/memjournal.c 0ebce851677a7ac035ba1512a7e65851b34530c6 F src/memjournal.c 0ebce851677a7ac035ba1512a7e65851b34530c6
F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f
@@ -172,12 +172,12 @@ F src/mutex_os2.c 882d735098c07c8c6a5472b8dd66e19675fe117f
F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579 F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579
F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33 F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d F src/os.c fcc717427a80b2ed225373f07b642dc1aad7490b
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
F src/os_unix.c 07acbb3e074e52b48a4248c06f66c9a91db1a0ce F src/os_unix.c dcd6d5782dd30e918dc3d111cdcb1883bfb95345
F src/os_win.c eafcd6b91cf204a7ef29ac1ef2a1b7132e132e58 F src/os_win.c c5eadb2c0fc11347296a660f77b9844090265c0c
F src/pager.c 120550e7ef01dafaa2cbb4a0528c0d87c8f12b41 F src/pager.c 120550e7ef01dafaa2cbb4a0528c0d87c8f12b41
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
@@ -188,18 +188,18 @@ F src/pragma.c ebcd20f1e654f5cb3aeef864ed69c4697719fbaa
F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4 F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4
F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1 F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff F src/select.c d219c4b68d603cc734b6f9b1e2780fee12a1fa0d
F src/shell.c 0e0173b3e79d956368013e759f084caa7995ecb1 F src/shell.c bbe7818ff5bc8614105ceb81ad67b8bdc0b671dd
F src/sqlite.h.in f292d325b466081f8980911316743192cce6832a F src/sqlite.h.in 4cd98228ea9cbb0359aaf725fdbebcd37c082c6a
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93
F src/sqliteInt.h 3c2f3f13d8ea942ddfee1df1b78013566eae8a74 F src/sqliteInt.h 113559f0c2202c4e648b5d647d7b2409604fb516
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 6a34149c9ff4a6f998a4cb8336d4481670b576b6 F src/tclsqlite.c e85bada4bf1796274a2cd7b3db9a663f8df31880
F src/test1.c 8eef932f1024f1076a8adb8a6f5d9c5267c9e969 F src/test1.c 693d9a63dfe2c68b167080c99cab82f267f5a38e
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432 F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
@@ -212,7 +212,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2 F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
F src/test_config.c 470765ec36636d2c598766342b58e4c841e24512 F src/test_config.c 70c74ef7a696c1b40d6415d48ee4c8f668cd16a8
F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094 F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5 F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5
@@ -224,7 +224,7 @@ F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
F src/test_journal.c 03313c693cca72959dcaaf79f8d76f21c01e19ff F src/test_journal.c 03313c693cca72959dcaaf79f8d76f21c01e19ff
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
F src/test_malloc.c 7ca7be34e0e09ef0ed6619544552ed95732e41f6 F src/test_malloc.c 7ca7be34e0e09ef0ed6619544552ed95732e41f6
F src/test_multiplex.c a7457a1ac46964b7f897d75ecfd447410ec067e6 F src/test_multiplex.c 991a60733dbde8c529043d466c5c44d180762561
F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
@@ -244,16 +244,16 @@ F src/test_vfstrace.c 0b884e06094a746da729119a2cabdc7aa790063d
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290 F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c c819d9f72168a035d545a5bdafe9b085b20df705 F src/tokenize.c c819d9f72168a035d545a5bdafe9b085b20df705
F src/trigger.c c836a6caac16ba96611558922106858f6ca3d6bf F src/trigger.c 1cfb80e2290ef66ea89cb4e821caae65a02c0d56
F src/update.c a81bda229f8c3b698f8dcf8e69485c97e1347102 F src/update.c 2d67e24d5a44d8b1c0839bf2ee0c391593e852bf
F src/utf.c c53eb7404b3eb5c1cbb5655c6a7a0e0ce6bd50f0 F src/utf.c c53eb7404b3eb5c1cbb5655c6a7a0e0ce6bd50f0
F src/util.c 0f33bbbdfcc4a2d8cf20c3b2a16ffc3b57c58a70 F src/util.c 06302ffd2b80408d4f6c7af71f7090e0cf8d8ff7
F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
F src/vdbe.c df52db6162fd94767b76bb4e9a7cb9207e83086f F src/vdbe.c 00061273468d03c6c5c0f6144ed219c0004cf849
F src/vdbe.h 322af148cceef120bb1ec9cff7f122e76abf94da F src/vdbe.h 322af148cceef120bb1ec9cff7f122e76abf94da
F src/vdbeInt.h 3de6588b36c833969aebab202e1766d586c37ec2 F src/vdbeInt.h 3de6588b36c833969aebab202e1766d586c37ec2
F src/vdbeapi.c 432a8a194accb9fe9fae45338f210174c6c961b4 F src/vdbeapi.c ddd061183e2c3015f676e53ee85fcaf306617e8e
F src/vdbeaux.c bb86d48ce99c288d17e8d79711713399c21f0a8d F src/vdbeaux.c 7d0b75a04ac466d25a90fefd1df83361a2ab0ad7
F src/vdbeblob.c a547f286b651641bdb43a567af66d0e776a39ea2 F src/vdbeblob.c a547f286b651641bdb43a567af66d0e776a39ea2
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
@@ -261,13 +261,13 @@ F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
F src/wal.c 0c70ad7b1cac6005fa5e2cbefd23ee05e391c290 F src/wal.c 0c70ad7b1cac6005fa5e2cbefd23ee05e391c290
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c 55403ce19c506be6a321c7f129aff693d6103db5 F src/where.c 106cd9ab3eb410dfa7d0598194c277664bb2e9a3
F test/8_3_names.test b93687beebd17f6ebf812405a6833bae5d1f4199 F test/8_3_names.test b93687beebd17f6ebf812405a6833bae5d1f4199
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 51756962d522e474338e9b2ebb26e7364d4aa125 F test/all.test 52fc8dee494092031a556911d404ca30a749a30b
F test/alter.test a3f570072b53d7c0fe463bab3f5affa8e113c487 F test/alter.test a3f570072b53d7c0fe463bab3f5affa8e113c487
F test/alter2.test 75f731508f1bf27ba09a6075c66cd02216ba464b F test/alter2.test e0c09d630d650ea32333781a4ed3c45eb02c4289
F test/alter3.test 8677e48d95536f7a6ed86a1a774744dadcc22b07 F test/alter3.test 8677e48d95536f7a6ed86a1a774744dadcc22b07
F test/alter4.test 1e5dd6b951e9f65ca66422edff02e56df82dd403 F test/alter4.test 1e5dd6b951e9f65ca66422edff02e56df82dd403
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
@@ -292,7 +292,7 @@ F test/auth.test b047105c32da7db70b842fd24056723125ecc2ff
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882 F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46 F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46
F test/autoindex1.test 860fc83f4fefb0c68ad062afc3ff43faa1534fc4 F test/autoindex1.test 058d0b331ae6840a61bbee910d8cbae27bfd5991
F test/autovacuum.test bb7c0885e6f8f1d633045de48f2b66082162766d F test/autovacuum.test bb7c0885e6f8f1d633045de48f2b66082162766d
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6 F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
@@ -333,7 +333,7 @@ F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49 F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
F test/collate3.test d28d2cfab2c3a3d4628ae4b2b7afc9965daa3b4c F test/collate3.test d28d2cfab2c3a3d4628ae4b2b7afc9965daa3b4c
F test/collate4.test 3d3f123f83fd8ccda6f48d617e44e661b9870c7d F test/collate4.test 3d3f123f83fd8ccda6f48d617e44e661b9870c7d
F test/collate5.test fe0f43c4740d7b71b959cac668d19e42f2e06e4d F test/collate5.test 67f1d3e848e230ff4802815a79acb0a8b5e69bd7
F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907 F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907
F test/collate7.test fac8db7aac3978466c04ae892cc74dcf2bc031aa F test/collate7.test fac8db7aac3978466c04ae892cc74dcf2bc031aa
F test/collate8.test df26649cfcbddf109c04122b340301616d3a88f6 F test/collate8.test df26649cfcbddf109c04122b340301616d3a88f6
@@ -379,6 +379,7 @@ F test/descidx1.test b1353c1a15cfbee97b13a1dcedaf0fe78163ba6a
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f
F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
F test/distinct.test 8c4d951fc40aba84421060e07b16099d2f4c2fdf
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
F test/e_createtable.test 4771686a586b6ae414f927c389b2c101cc05c028 F test/e_createtable.test 4771686a586b6ae414f927c389b2c101cc05c028
F test/e_delete.test e2ae0d3fce5efd70fef99025e932afffc5616fab F test/e_delete.test e2ae0d3fce5efd70fef99025e932afffc5616fab
@@ -390,7 +391,7 @@ F test/e_fts3.test 75bb0aee26384ef586165e21018a17f7cd843469
F test/e_insert.test 76d4bb5da9b28014d515d91ffe29a79a1e99f2bc F test/e_insert.test 76d4bb5da9b28014d515d91ffe29a79a1e99f2bc
F test/e_reindex.test a064f0878b8f848fbca38f1f61f82f15a3000c64 F test/e_reindex.test a064f0878b8f848fbca38f1f61f82f15a3000c64
F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
F test/e_select.test 7ac53674e822d4d77bbb4a9a4aaefa5fdc9e493f F test/e_select.test 8d7fac7a268eaeb80b9a7ba7964505b9d30f5458
F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92 F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92
F test/e_update.test b926341a65955d69a6375c9eb4fd82e7089bc83a F test/e_update.test b926341a65955d69a6375c9eb4fd82e7089bc83a
F test/e_uri.test 6f35b491f80dac005c8144f38b2dfb4d96483596 F test/e_uri.test 6f35b491f80dac005c8144f38b2dfb4d96483596
@@ -404,7 +405,7 @@ F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062 F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062
F test/exclusive2.test 343d55130c12c67b8bf10407acec043a6c26c86b F test/exclusive2.test 343d55130c12c67b8bf10407acec043a6c26c86b
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/exists.test 5e2d64b4eb5a9d08876599bdae2e1213d2d12e2a F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6 F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
@@ -467,7 +468,7 @@ F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18 F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9 F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9
F test/fts3atoken.test 402ef2f7c2fb4b3d4fa0587df6441c1447e799b3 F test/fts3atoken.test 402ef2f7c2fb4b3d4fa0587df6441c1447e799b3
F test/fts3auto.test f1cb0a55130897013ca5850dbee2945c2908a45a F test/fts3auto.test c1a30b37002b7c764a96937fbc71065b73d69494
F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0 F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
@@ -496,13 +497,13 @@ F test/fts3sort.test 63d52c1812904b751f9e1ff487472e44833f5402
F test/fts4aa.test 148d9eb54901af23b5d402b1f388f43e559e1728 F test/fts4aa.test 148d9eb54901af23b5d402b1f388f43e559e1728
F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 7ba2ca5a1e9bca900ba2c230cf04bd67184bc1bc F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6 F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167 F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c
F test/fuzzer1.test 3105b5a89a6cb0d475f0877debec942fe4143462 F test/fuzzer1.test ddfb04f3bd5cfdda3b1aa15b78d3ad055c9cc50f
F test/hook.test 4fd80e9c3ffb49de0379e2a026ef2fe7b9f3e534 F test/hook.test 4fd80e9c3ffb49de0379e2a026ef2fe7b9f3e534
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d
@@ -512,7 +513,7 @@ F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
F test/incrblob.test 76e787ca3301d9bfa6906031c626d26f8dd707de F test/incrblob.test 76e787ca3301d9bfa6906031c626d26f8dd707de
F test/incrblob2.test edc3a96e557bd61fb39acc8d2edd43371fbbaa19 F test/incrblob2.test edc3a96e557bd61fb39acc8d2edd43371fbbaa19
F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7 F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7
F test/incrblob_err.test c577c91d4ed9e8336cdb188b15d6ee2a6fe9604e F test/incrblob_err.test d2562d2771ebffd4b3af89ef64c140dd44371597
F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0 F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0
F test/incrvacuum.test 453d1e490d8f5ad2c9b3a54282a0690d6ae56462 F test/incrvacuum.test 453d1e490d8f5ad2c9b3a54282a0690d6ae56462
F test/incrvacuum2.test ae04573b73ad52179f56e194fff0fbe43b509d23 F test/incrvacuum2.test ae04573b73ad52179f56e194fff0fbe43b509d23
@@ -525,7 +526,7 @@ F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908 F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
F test/insert4.test b3e02648a5fc3075c29e13c369b5127bf859b5a2 F test/insert4.test 63ea672b0fc6d3a9a0ccee774a771510b1e684c4
F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766 F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1 F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1
@@ -551,7 +552,7 @@ F test/jrnlmode3.test c6522b276ba315fd1416198de6fc1da9e72409fb
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05 F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/like.test a47f52692aac96ba82508efba74819214cdebc17 F test/like.test 9cc5261d22f2108a27cedff8a972aa3284a4ba52
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e
F test/loadext.test 0393ce12d9616aa87597dd0ec88181de181f6db0 F test/loadext.test 0393ce12d9616aa87597dd0ec88181de181f6db0
@@ -601,11 +602,11 @@ F test/misc1.test e56baf44656dd68d6475a4b44521045a60241e9b
F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd
F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6 F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6
F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd F test/misc5.test 9f9338f8211c7f5d1cbe16331fa65d019501aa50
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3 F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
F test/multiplex.test 555080c87abfc72ba68e2f3df01d4a9a7a4fdf58 F test/multiplex.test b45367b1dac7dfa4c5b8ff0f3844260804a0034d
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
F test/nan.test dc212a22b36109fd1ae37154292444ef249c5ec2 F test/nan.test dc212a22b36109fd1ae37154292444ef249c5ec2
@@ -626,7 +627,7 @@ F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16 F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
F test/permutations.test 8331b2897502df0671dd1390a3c87db44fb8757c F test/permutations.test df39e810d98a966218ef1391afb4e25491af698f
F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850 F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
@@ -640,7 +641,7 @@ F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
F test/releasetest.tcl c0c0865f1dff08dde08a964ef49e83217ebedbf8 F test/releasetest.tcl fa302d03fd9acfce6d910553a33473bfcf561958
F test/rollback.test 1a83118ea6db4e7d8c10eaa63871b5e90502ffdc F test/rollback.test 1a83118ea6db4e7d8c10eaa63871b5e90502ffdc
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test e58e0acef38b527ed1b0b70d3ada588f804af287 F test/rowid.test e58e0acef38b527ed1b0b70d3ada588f804af287
@@ -666,7 +667,7 @@ F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343 F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532 F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b F test/selectB.test 0d072c5846071b569766e6cd7f923f646a8b2bfa
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25 F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
F test/session.test c1a17c11ef7d01c24fe2b9f7871190d949a8e718 F test/session.test c1a17c11ef7d01c24fe2b9f7871190d949a8e718
@@ -691,7 +692,7 @@ F test/speed3.test 5a419039e9da95d906adb2298af2849600c81c11
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
F test/sqllimits1.test e90a0ed94452076f6a10209d378e06b5f75ef0a0 F test/sqllimits1.test 0ebf7bed0b99c96f24e0b7fa5e59dbc42359c421
F test/stat.test c7b20ea43003dc2dc33335e231c27be8284c4a2a F test/stat.test c7b20ea43003dc2dc33335e231c27be8284c4a2a
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796 F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
@@ -705,7 +706,7 @@ F test/table.test 04ba066432430657712d167ebf28080fe878d305
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tclsqlite.test 1ce9b6340d6d412420634e129a2e3722c651056a F test/tclsqlite.test 1ce9b6340d6d412420634e129a2e3722c651056a
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a F test/temptable.test 1a21a597055dcf6002b6f1ee867632dccd6e925c
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05 F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
F test/tester.tcl 3b6143fdafff36c516cf0fd663a20cd420aae36f F test/tester.tcl 3b6143fdafff36c516cf0fd663a20cd420aae36f
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
@@ -729,6 +730,7 @@ F test/tkt-38cb5df375.test 9e9b19857dba0896a8efdaf334d405ba423492f2
F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7 F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7
F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00 F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
F test/tkt-54844eea3f.test a12b851128f46a695e4e378cca67409b9b8f5894
F test/tkt-5d863f876e.test 884072c2de496ddbb90c387c9ebc0d4f44a91b8e F test/tkt-5d863f876e.test 884072c2de496ddbb90c387c9ebc0d4f44a91b8e
F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84 F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9 F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
@@ -852,7 +854,7 @@ F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
F test/triggerA.test eaf11a29db2a11967d2d4b49d37f92bce598194e F test/triggerA.test eaf11a29db2a11967d2d4b49d37f92bce598194e
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
F test/triggerC.test 02c690febf608ae20b9af86184a9867f79855b1d F test/triggerC.test 02c690febf608ae20b9af86184a9867f79855b1d
F test/triggerD.test c6add3817351451e419f6ff9e9a259b02b6e2de7 F test/triggerD.test bfdac1143deee8fb12b6a3640d76e5669a567ff6
F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
@@ -889,10 +891,10 @@ F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
F test/wal.test 5617ad308bfdb8a8885220d8a261a6096a8d7e57 F test/wal.test 5617ad308bfdb8a8885220d8a261a6096a8d7e57
F test/wal2.test aa0fb2314b3235be4503c06873e41ebfc0757782 F test/wal2.test aa0fb2314b3235be4503c06873e41ebfc0757782
F test/wal3.test 5c396cc22497244d627306f4c1d360167353f8dd F test/wal3.test d512a5c8b4aa345722d11e8f1671db7eb15a0e39
F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30 F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
F test/wal5.test f06a0427e06db00347e32eb9fa99d6a5c0f2d088 F test/wal5.test f06a0427e06db00347e32eb9fa99d6a5c0f2d088
F test/wal6.test 07aa31ca8892d0527f2c5c5a9a2a87aa421dfaa8 F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4 F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4
@@ -921,6 +923,7 @@ F test/where9.test 24f19ad14bb1b831564ced5273e681e495662848
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/win32lock.test 0a16a7df4a51575bda27529ac992a5a94e4a38bd
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
F tool/build-shell.sh 12aa4391073a777fcb6dcc490b219a018ae98bac F tool/build-shell.sh 12aa4391073a777fcb6dcc490b219a018ae98bac
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
@@ -957,11 +960,11 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/symbols.sh bc2a3709940d47c8ac8e0a1fdf17ec801f015a00 F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5
F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576 F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings.sh 347d974d143cf132f953b565fbc03026f19fcb4d F tool/warnings.sh 2ebae31e1eb352696f3c2f7706a34c084b28c262
P 70c84e50209722a61d66fd737e42d49275745b62 P d04e0fd82a15aee963e35830caf8159b4b6ccd87 8ce2b74a82264550b0e19da3e0e1a145db940a1c
R 7d529af0ae98dc5a31387a39a49b9017 R a5737ded89a8c66dbf565b51f6981ff8
U dan U drh
Z 3511ba374807e0034b8197f50cf80466 Z 81f45685ad26c120405ad7cb74da4306

View File

@@ -1 +1 @@
d04e0fd82a15aee963e35830caf8159b4b6ccd87 110cfd6920cf3011aeaf7e586f8db867bfc69fbb

View File

@@ -2791,7 +2791,7 @@ Index *sqlite3CreateIndex(
/* A named index with an explicit CREATE INDEX statement */ /* A named index with an explicit CREATE INDEX statement */
zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
onError==OE_None ? "" : " UNIQUE", onError==OE_None ? "" : " UNIQUE",
pEnd->z - pName->z + 1, (int)(pEnd->z - pName->z) + 1,
pName->z); pName->z);
}else{ }else{
/* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */

View File

@@ -427,7 +427,9 @@ static int osLocaltime(time_t *t, struct tm *pTm){
#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \ #if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
&& (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S) && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
struct tm *pX; struct tm *pX;
#if SQLITE_THREADSAFE>0
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
sqlite3_mutex_enter(mutex); sqlite3_mutex_enter(mutex);
pX = localtime(t); pX = localtime(t);
#ifndef SQLITE_OMIT_BUILTIN_TEST #ifndef SQLITE_OMIT_BUILTIN_TEST

View File

@@ -378,7 +378,9 @@ void sqlite3DeleteFrom(
/* Collect rowids of every row to be deleted. /* Collect rowids of every row to be deleted.
*/ */
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,WHERE_DUPLICATES_OK); pWInfo = sqlite3WhereBegin(
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK
);
if( pWInfo==0 ) goto delete_from_cleanup; if( pWInfo==0 ) goto delete_from_cleanup;
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid); regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid);
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid); sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);

View File

@@ -902,6 +902,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
pNewItem->jointype = pOldItem->jointype; pNewItem->jointype = pOldItem->jointype;
pNewItem->iCursor = pOldItem->iCursor; pNewItem->iCursor = pOldItem->iCursor;
pNewItem->isPopulated = pOldItem->isPopulated; pNewItem->isPopulated = pOldItem->isPopulated;
pNewItem->isCorrelated = pOldItem->isCorrelated;
pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex); pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex);
pNewItem->notIndexed = pOldItem->notIndexed; pNewItem->notIndexed = pOldItem->notIndexed;
pNewItem->pIndex = pOldItem->pIndex; pNewItem->pIndex = pOldItem->pIndex;

View File

@@ -560,7 +560,7 @@ static void fkScanChildren(
** clause. If the constraint is not deferred, throw an exception for ** clause. If the constraint is not deferred, throw an exception for
** each row found. Otherwise, for deferred constraints, increment the ** each row found. Otherwise, for deferred constraints, increment the
** deferred constraint counter by nIncr for each row selected. */ ** deferred constraint counter by nIncr for each row selected. */
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0); pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0);
if( nIncr>0 && pFKey->isDeferred==0 ){ if( nIncr>0 && pFKey->isDeferred==0 ){
sqlite3ParseToplevel(pParse)->mayAbort = 1; sqlite3ParseToplevel(pParse)->mayAbort = 1;
} }

View File

@@ -84,6 +84,8 @@
# define sqlite3_create_module 0 # define sqlite3_create_module 0
# define sqlite3_create_module_v2 0 # define sqlite3_create_module_v2 0
# define sqlite3_declare_vtab 0 # define sqlite3_declare_vtab 0
# define sqlite3_vtab_config 0
# define sqlite3_vtab_on_conflict 0
#endif #endif
#ifdef SQLITE_OMIT_SHARED_CACHE #ifdef SQLITE_OMIT_SHARED_CACHE
@@ -107,6 +109,7 @@
#define sqlite3_blob_open 0 #define sqlite3_blob_open 0
#define sqlite3_blob_read 0 #define sqlite3_blob_read 0
#define sqlite3_blob_write 0 #define sqlite3_blob_write 0
#define sqlite3_blob_reopen 0
#endif #endif
/* /*
@@ -372,6 +375,9 @@ static const sqlite3_api_routines sqlite3Apis = {
0, 0,
0, 0,
#endif #endif
sqlite3_blob_reopen,
sqlite3_vtab_config,
sqlite3_vtab_on_conflict,
}; };
/* /*

View File

@@ -433,7 +433,7 @@ static void *memsys3MallocUnsafe(int nByte){
** This function assumes that the necessary mutexes, if any, are ** This function assumes that the necessary mutexes, if any, are
** already held by the caller. Hence "Unsafe". ** already held by the caller. Hence "Unsafe".
*/ */
void memsys3FreeUnsafe(void *pOld){ static void memsys3FreeUnsafe(void *pOld){
Mem3Block *p = (Mem3Block*)pOld; Mem3Block *p = (Mem3Block*)pOld;
int i; int i;
u32 size, x; u32 size, x;
@@ -508,7 +508,7 @@ static void *memsys3Malloc(int nBytes){
/* /*
** Free memory. ** Free memory.
*/ */
void memsys3Free(void *pPrior){ static void memsys3Free(void *pPrior){
assert( pPrior ); assert( pPrior );
memsys3Enter(); memsys3Enter();
memsys3FreeUnsafe(pPrior); memsys3FreeUnsafe(pPrior);
@@ -518,7 +518,7 @@ void memsys3Free(void *pPrior){
/* /*
** Change the size of an existing memory allocation ** Change the size of an existing memory allocation
*/ */
void *memsys3Realloc(void *pPrior, int nBytes){ static void *memsys3Realloc(void *pPrior, int nBytes){
int nOld; int nOld;
void *p; void *p;
if( pPrior==0 ){ if( pPrior==0 ){

View File

@@ -136,7 +136,7 @@ int sqlite3OsOpen(
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */ ** reaching the VFS. */
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f3f, pFlagsOut); rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 ); assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc; return rc;
} }

View File

@@ -677,7 +677,9 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
case ENODEV: case ENODEV:
case ENXIO: case ENXIO:
case ENOENT: case ENOENT:
#ifdef ESTALE /* ESTALE is not defined on Interix systems */
case ESTALE: case ESTALE:
#endif
case ENOSYS: case ENOSYS:
/* these should force the client to close the file and reconnect */ /* these should force the client to close the file and reconnect */
@@ -3672,7 +3674,7 @@ static void unixShmPurge(unixFile *pFd){
if( p && p->nRef==0 ){ if( p && p->nRef==0 ){
int i; int i;
assert( p->pInode==pFd->pInode ); assert( p->pInode==pFd->pInode );
if( p->mutex ) sqlite3_mutex_free(p->mutex); sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){ for(i=0; i<p->nRegion; i++){
if( p->h>=0 ){ if( p->h>=0 ){
munmap(p->apRegion[i], p->szRegion); munmap(p->apRegion[i], p->szRegion);

View File

@@ -402,6 +402,54 @@ static int winLogErrorAtLine(
return errcode; return errcode;
} }
/*
** The number of times that a ReadFile(), WriteFile(), and DeleteFile()
** will be retried following a locking error - probably caused by
** antivirus software. Also the initial delay before the first retry.
** The delay increases linearly with each retry.
*/
#ifndef SQLITE_WIN32_IOERR_RETRY
# define SQLITE_WIN32_IOERR_RETRY 10
#endif
#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
# define SQLITE_WIN32_IOERR_RETRY_DELAY 25
#endif
static int win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY;
static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
/*
** If a ReadFile() or WriteFile() error occurs, invoke this routine
** to see if it should be retried. Return TRUE to retry. Return FALSE
** to give up with an error.
*/
static int retryIoerr(int *pnRetry){
DWORD e;
if( *pnRetry>=win32IoerrRetry ){
return 0;
}
e = GetLastError();
if( e==ERROR_ACCESS_DENIED ||
e==ERROR_LOCK_VIOLATION ||
e==ERROR_SHARING_VIOLATION ){
Sleep(win32IoerrRetryDelay*(1+*pnRetry));
++*pnRetry;
return 1;
}
return 0;
}
/*
** Log a I/O error retry episode.
*/
static void logIoerr(int nRetry){
if( nRetry ){
sqlite3_log(SQLITE_IOERR,
"delayed %dms for lock/sharing conflict",
win32IoerrRetryDelay*nRetry*(nRetry+1)/2
);
}
}
#if SQLITE_OS_WINCE #if SQLITE_OS_WINCE
/************************************************************************* /*************************************************************************
** This section contains code for WinCE only. ** This section contains code for WinCE only.
@@ -820,6 +868,7 @@ static int winRead(
){ ){
winFile *pFile = (winFile*)id; /* file handle */ winFile *pFile = (winFile*)id; /* file handle */
DWORD nRead; /* Number of bytes actually read from file */ DWORD nRead; /* Number of bytes actually read from file */
int nRetry = 0; /* Number of retrys */
assert( id!=0 ); assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ); SimulateIOError(return SQLITE_IOERR_READ);
@@ -828,10 +877,12 @@ static int winRead(
if( seekWinFile(pFile, offset) ){ if( seekWinFile(pFile, offset) ){
return SQLITE_FULL; return SQLITE_FULL;
} }
if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
if( retryIoerr(&nRetry) ) continue;
pFile->lastErrno = GetLastError(); pFile->lastErrno = GetLastError();
return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath); return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
} }
logIoerr(nRetry);
if( nRead<(DWORD)amt ){ if( nRead<(DWORD)amt ){
/* Unread parts of the buffer must be zero-filled */ /* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[nRead], 0, amt-nRead); memset(&((char*)pBuf)[nRead], 0, amt-nRead);
@@ -853,6 +904,7 @@ static int winWrite(
){ ){
int rc; /* True if error has occured, else false */ int rc; /* True if error has occured, else false */
winFile *pFile = (winFile*)id; /* File handle */ winFile *pFile = (winFile*)id; /* File handle */
int nRetry = 0; /* Number of retries */
assert( amt>0 ); assert( amt>0 );
assert( pFile ); assert( pFile );
@@ -867,7 +919,12 @@ static int winWrite(
int nRem = amt; /* Number of bytes yet to be written */ int nRem = amt; /* Number of bytes yet to be written */
DWORD nWrite; /* Bytes written by each WriteFile() call */ DWORD nWrite; /* Bytes written by each WriteFile() call */
while( nRem>0 && WriteFile(pFile->h, aRem, nRem, &nWrite, 0) && nWrite>0 ){ while( nRem>0 ){
if( !WriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
if( retryIoerr(&nRetry) ) continue;
break;
}
if( nWrite<=0 ) break;
aRem += nWrite; aRem += nWrite;
nRem -= nWrite; nRem -= nWrite;
} }
@@ -883,6 +940,8 @@ static int winWrite(
return SQLITE_FULL; return SQLITE_FULL;
} }
return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath); return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);
}else{
logIoerr(nRetry);
} }
return SQLITE_OK; return SQLITE_OK;
} }
@@ -1299,6 +1358,20 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
case SQLITE_FCNTL_SYNC_OMITTED: { case SQLITE_FCNTL_SYNC_OMITTED: {
return SQLITE_OK; return SQLITE_OK;
} }
case SQLITE_FCNTL_WIN32_AV_RETRY: {
int *a = (int*)pArg;
if( a[0]>0 ){
win32IoerrRetry = a[0];
}else{
a[0] = win32IoerrRetry;
}
if( a[1]>0 ){
win32IoerrRetryDelay = a[1];
}else{
a[1] = win32IoerrRetryDelay;
}
return SQLITE_OK;
}
} }
return SQLITE_NOTFOUND; return SQLITE_NOTFOUND;
} }
@@ -2316,15 +2389,13 @@ static int winOpen(
** to MX_DELETION_ATTEMPTs deletion attempts are run before giving ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
** up and returning an error. ** up and returning an error.
*/ */
#define MX_DELETION_ATTEMPTS 5
static int winDelete( static int winDelete(
sqlite3_vfs *pVfs, /* Not used on win32 */ sqlite3_vfs *pVfs, /* Not used on win32 */
const char *zFilename, /* Name of file to delete */ const char *zFilename, /* Name of file to delete */
int syncDir /* Not used on win32 */ int syncDir /* Not used on win32 */
){ ){
int cnt = 0; int cnt = 0;
DWORD rc; int rc;
DWORD error = 0;
void *zConverted; void *zConverted;
UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(syncDir); UNUSED_PARAMETER(syncDir);
@@ -2335,34 +2406,30 @@ static int winDelete(
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
if( isNT() ){ if( isNT() ){
do{ rc = 1;
DeleteFileW(zConverted); while( GetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES &&
}while( ( ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES) (rc = DeleteFileW(zConverted))==0 && retryIoerr(&cnt) ){}
|| ((error = GetLastError()) == ERROR_ACCESS_DENIED)) rc = rc ? SQLITE_OK : SQLITE_ERROR;
&& (++cnt < MX_DELETION_ATTEMPTS)
&& (Sleep(100), 1) );
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE, ** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds. ** it's important to not reference them for WINCE builds.
*/ */
#if SQLITE_OS_WINCE==0 #if SQLITE_OS_WINCE==0
}else{ }else{
do{ rc = 1;
DeleteFileA(zConverted); while( GetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES &&
}while( ( ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES) (rc = DeleteFileA(zConverted))==0 && retryIoerr(&cnt) ){}
|| ((error = GetLastError()) == ERROR_ACCESS_DENIED)) rc = rc ? SQLITE_OK : SQLITE_ERROR;
&& (++cnt < MX_DELETION_ATTEMPTS)
&& (Sleep(100), 1) );
#endif #endif
} }
if( rc ){
rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
}else{
logIoerr(cnt);
}
free(zConverted); free(zConverted);
OSTRACE(("DELETE \"%s\" %s\n", zFilename, OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ? return rc;
"ok" : "failed" ));
return ( (rc == INVALID_FILE_ATTRIBUTES)
&& (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK :
winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
} }
/* /*

View File

@@ -996,11 +996,25 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
for(i=0; i<p->pSrc->nSrc; i++){ for(i=0; i<p->pSrc->nSrc; i++){
struct SrcList_item *pItem = &p->pSrc->a[i]; struct SrcList_item *pItem = &p->pSrc->a[i];
if( pItem->pSelect ){ if( pItem->pSelect ){
NameContext *pNC; /* Used to iterate name contexts */
int nRef = 0; /* Refcount for pOuterNC and outer contexts */
const char *zSavedContext = pParse->zAuthContext; const char *zSavedContext = pParse->zAuthContext;
/* Count the total number of references to pOuterNC and all of its
** parent contexts. After resolving references to expressions in
** pItem->pSelect, check if this value has changed. If so, then
** SELECT statement pItem->pSelect must be correlated. Set the
** pItem->isCorrelated flag if this is the case. */
for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef;
if( pItem->zName ) pParse->zAuthContext = pItem->zName; if( pItem->zName ) pParse->zAuthContext = pItem->zName;
sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
pParse->zAuthContext = zSavedContext; pParse->zAuthContext = zSavedContext;
if( pParse->nErr || db->mallocFailed ) return WRC_Abort; if( pParse->nErr || db->mallocFailed ) return WRC_Abort;
for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef;
assert( pItem->isCorrelated==0 && nRef<=0 );
pItem->isCorrelated = (nRef!=0);
} }
} }

View File

@@ -3721,6 +3721,7 @@ int sqlite3Select(
int distinct; /* Table to use for the distinct set */ int distinct; /* Table to use for the distinct set */
int rc = 1; /* Value to return from this function */ int rc = 1; /* Value to return from this function */
int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
int addrDistinctIndex; /* Address of an OP_OpenEphemeral instruction */
AggInfo sAggInfo; /* Information used by aggregate queries */ AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */ int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */ sqlite3 *db; /* The database connection */
@@ -3847,16 +3848,6 @@ int sqlite3Select(
} }
#endif #endif
/* If possible, rewrite the query to use GROUP BY instead of DISTINCT.
** GROUP BY might use an index, DISTINCT never does.
*/
assert( p->pGroupBy==0 || (p->selFlags & SF_Aggregate)!=0 );
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ){
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
p->selFlags &= ~SF_Distinct;
}
/* If there is both a GROUP BY and an ORDER BY clause and they are /* 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 ** identical, then disable the ORDER BY clause since the GROUP BY
** will cause elements to come out in the correct order. This is ** will cause elements to come out in the correct order. This is
@@ -3869,6 +3860,30 @@ int sqlite3Select(
pOrderBy = 0; 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:
**
** SELECT DISTINCT xyz FROM ... ORDER BY xyz
**
** is transformed to:
**
** SELECT xyz FROM ... GROUP BY xyz
**
** The second form is preferred as a single index (or temp-table) may be
** used for both the ORDER BY and DISTINCT processing. As originally
** written the query must use a temp-table for at least one of the ORDER
** BY and DISTINCT, and an index or separate temp-table for the other.
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(pOrderBy, p->pEList)==0
){
p->selFlags &= ~SF_Distinct;
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
pOrderBy = 0;
}
/* If there is an ORDER BY clause, then this sorting /* If there is an ORDER BY clause, then this sorting
** index might end up being unused if the data can be ** index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the ** extracted in pre-sorted order. If that is the case, then the
@@ -3904,22 +3919,21 @@ int sqlite3Select(
*/ */
if( p->selFlags & SF_Distinct ){ if( p->selFlags & SF_Distinct ){
KeyInfo *pKeyInfo; KeyInfo *pKeyInfo;
assert( isAgg || pGroupBy );
distinct = pParse->nTab++; distinct = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, p->pEList); pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0, addrDistinctIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO_HANDOFF); (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
}else{ }else{
distinct = -1; distinct = addrDistinctIndex = -1;
} }
/* Aggregate and non-aggregate queries are handled differently */ /* Aggregate and non-aggregate queries are handled differently */
if( !isAgg && pGroupBy==0 ){ if( !isAgg && pGroupBy==0 ){
/* This case is for non-aggregate queries ExprList *pDist = (isDistinct ? p->pEList : 0);
** Begin the database scan
*/ /* Begin the database scan. */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0);
if( pWInfo==0 ) goto select_end; if( pWInfo==0 ) goto select_end;
if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut; if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
@@ -3932,10 +3946,52 @@ int sqlite3Select(
p->addrOpenEphm[2] = -1; p->addrOpenEphm[2] = -1;
} }
/* Use the standard inner loop if( pWInfo->eDistinct ){
*/ VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
assert(!isDistinct);
selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, -1, pDest, assert( addrDistinctIndex>0 );
pOp = sqlite3VdbeGetOp(v, addrDistinctIndex);
assert( isDistinct );
assert( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
|| pWInfo->eDistinct==WHERE_DISTINCT_UNIQUE
);
distinct = -1;
if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED ){
int iJump;
int iExpr;
int iFlag = ++pParse->nMem;
int iBase = pParse->nMem+1;
int iBase2 = iBase + pEList->nExpr;
pParse->nMem += (pEList->nExpr*2);
/* Change the OP_OpenEphemeral coded earlier to an OP_Integer. The
** OP_Integer initializes the "first row" flag. */
pOp->opcode = OP_Integer;
pOp->p1 = 1;
pOp->p2 = iFlag;
sqlite3ExprCodeExprList(pParse, pEList, iBase, 1);
iJump = sqlite3VdbeCurrentAddr(v) + 1 + pEList->nExpr + 1 + 1;
sqlite3VdbeAddOp2(v, OP_If, iFlag, iJump-1);
for(iExpr=0; iExpr<pEList->nExpr; iExpr++){
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[iExpr].pExpr);
sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr);
sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
}
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iContinue);
sqlite3VdbeAddOp2(v, OP_Integer, 0, iFlag);
assert( sqlite3VdbeCurrentAddr(v)==iJump );
sqlite3VdbeAddOp3(v, OP_Move, iBase, iBase2, pEList->nExpr);
}else{
pOp->opcode = OP_Noop;
}
}
/* Use the standard inner loop. */
selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, pDest,
pWInfo->iContinue, pWInfo->iBreak); pWInfo->iContinue, pWInfo->iBreak);
/* End the database scan loop. /* End the database scan loop.
@@ -4045,7 +4101,7 @@ int sqlite3Select(
** in the right order to begin with. ** in the right order to begin with.
*/ */
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0);
if( pWInfo==0 ) goto select_end; if( pWInfo==0 ) goto select_end;
if( pGroupBy==0 ){ if( pGroupBy==0 ){
/* The optimizer is able to deliver rows in group by order so /* The optimizer is able to deliver rows in group by order so
@@ -4307,7 +4363,7 @@ int sqlite3Select(
** of output. ** of output.
*/ */
resetAccumulator(pParse, &sAggInfo); resetAccumulator(pParse, &sAggInfo);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, 0, flag);
if( pWInfo==0 ){ if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel); sqlite3ExprListDelete(db, pDel);
goto select_end; goto select_end;

View File

@@ -2632,6 +2632,9 @@ static const char zOptions[] =
#ifdef SQLITE_ENABLE_VFSTRACE #ifdef SQLITE_ENABLE_VFSTRACE
" -vfstrace enable tracing of all VFS calls\n" " -vfstrace enable tracing of all VFS calls\n"
#endif #endif
#ifdef SQLITE_ENABLE_MULTIPLEX
" -multiplex enable the multiplexor VFS\n"
#endif
; ;
static void usage(int showDetail){ static void usage(int showDetail){
fprintf(stderr, fprintf(stderr,
@@ -2732,6 +2735,11 @@ int main(int argc, char **argv){
int makeDefault int makeDefault
); );
vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( strcmp(argv[i],"-multiplex")==0 ){
extern int sqlite3_multiple_initialize(const char*,int);
sqlite3_multiplex_initialize(0, 1);
#endif #endif
}else if( strcmp(argv[i],"-vfs")==0 ){ }else if( strcmp(argv[i],"-vfs")==0 ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]); sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
@@ -2851,8 +2859,14 @@ int main(int argc, char **argv){
i++; i++;
}else if( strcmp(z,"-vfs")==0 ){ }else if( strcmp(z,"-vfs")==0 ){
i++; i++;
#ifdef SQLITE_ENABLE_VFSTRACE
}else if( strcmp(z,"-vfstrace")==0 ){ }else if( strcmp(z,"-vfstrace")==0 ){
i++; i++;
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( strcmp(z,"-multiplex")==0 ){
i++;
#endif
}else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){ }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
usage(1); usage(1);
}else{ }else{

View File

@@ -736,6 +736,23 @@ struct sqlite3_io_methods {
** Applications should not call [sqlite3_file_control()] with this ** Applications should not call [sqlite3_file_control()] with this
** opcode as doing so may disrupt the operation of the specialized VFSes ** opcode as doing so may disrupt the operation of the specialized VFSes
** that do require it. ** that do require it.
**
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
** retry counts and intervals for certain disk I/O operations for the
** windows [VFS] in order to work to provide robustness against
** anti-virus programs. By default, the windows VFS will retry file read,
** file write, and file delete opertions up to 10 times, with a delay
** of 25 milliseconds before the first retry and with the delay increasing
** by an additional 25 milliseconds with each subsequent retry. This
** opcode allows those to values (10 retries and 25 milliseconds of delay)
** to be adjusted. The values are changed for all database connections
** within the same process. The argument is a pointer to an array of two
** integers where the first integer i the new retry count and the second
** integer is the delay. If either integer is negative, then the setting
** is not changed but instead the prior value of that setting is written
** into the array entry, allowing the current retry settings to be
** interrogated. The zDbName parameter is ignored.
**
*/ */
#define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_GET_LOCKPROXYFILE 2
@@ -745,7 +762,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_FILE_POINTER 7
#define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_SYNC_OMITTED 8
#define SQLITE_FCNTL_WIN32_AV_RETRY 9
/* /*
** CAPI3REF: Mutex Handle ** CAPI3REF: Mutex Handle

View File

@@ -212,6 +212,9 @@ struct sqlite3_api_routines {
int (*wal_autocheckpoint)(sqlite3*,int); int (*wal_autocheckpoint)(sqlite3*,int);
int (*wal_checkpoint)(sqlite3*,const char*); int (*wal_checkpoint)(sqlite3*,const char*);
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
int (*vtab_config)(sqlite3*,int op,...);
int (*vtab_on_conflict)(sqlite3*);
}; };
/* /*
@@ -412,6 +415,9 @@ struct sqlite3_api_routines {
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint #define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
#define sqlite3_wal_hook sqlite3_api->wal_hook #define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
#endif /* SQLITE_CORE */ #endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;

View File

@@ -964,6 +964,7 @@ struct sqlite3 {
#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */ #define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
#define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */ #define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */
#define SQLITE_IdxRealAsInt 0x80 /* Store REAL as INT in indices */ #define SQLITE_IdxRealAsInt 0x80 /* Store REAL as INT in indices */
#define SQLITE_DistinctOpt 0x80 /* DISTINCT using indexes */
#define SQLITE_OptMask 0xff /* Mask of all disablable opts */ #define SQLITE_OptMask 0xff /* Mask of all disablable opts */
/* /*
@@ -1855,6 +1856,7 @@ struct SrcList {
u8 isPopulated; /* Temporary table associated with SELECT is populated */ u8 isPopulated; /* Temporary table associated with SELECT is populated */
u8 jointype; /* Type of join between this able and the previous */ u8 jointype; /* Type of join between this able and the previous */
u8 notIndexed; /* True if there is a NOT INDEXED clause */ u8 notIndexed; /* True if there is a NOT INDEXED clause */
u8 isCorrelated; /* True if sub-query is correlated */
#ifndef SQLITE_OMIT_EXPLAIN #ifndef SQLITE_OMIT_EXPLAIN
u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
#endif #endif
@@ -1974,6 +1976,7 @@ struct WhereInfo {
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
u8 eDistinct;
SrcList *pTabList; /* List of tables in the join */ SrcList *pTabList; /* List of tables in the join */
int iTop; /* The very beginning of the WHERE loop */ int iTop; /* The very beginning of the WHERE loop */
int iContinue; /* Jump here to continue with next record */ int iContinue; /* Jump here to continue with next record */
@@ -1985,6 +1988,9 @@ struct WhereInfo {
WhereLevel a[1]; /* Information about each nest loop in WHERE */ WhereLevel a[1]; /* Information about each nest loop in WHERE */
}; };
#define WHERE_DISTINCT_UNIQUE 1
#define WHERE_DISTINCT_ORDERED 2
/* /*
** A NameContext defines a context in which to resolve table and column ** A NameContext defines a context in which to resolve table and column
** names. The context consists of a list of tables (the pSrcList) field and ** names. The context consists of a list of tables (the pSrcList) field and
@@ -2747,7 +2753,7 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *,
#endif #endif
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16);
void sqlite3WhereEnd(WhereInfo*); void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);

View File

@@ -107,6 +107,11 @@ typedef struct IncrblobChannel IncrblobChannel;
/* /*
** There is one instance of this structure for each SQLite database ** There is one instance of this structure for each SQLite database
** that has been opened by the SQLite TCL interface. ** that has been opened by the SQLite TCL interface.
**
** If this module is built with SQLITE_TEST defined (to create the SQLite
** testfixture executable), then it may be configured to use either
** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements.
** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used.
*/ */
typedef struct SqliteDb SqliteDb; typedef struct SqliteDb SqliteDb;
struct SqliteDb { struct SqliteDb {
@@ -136,6 +141,9 @@ struct SqliteDb {
IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */
int nStep, nSort, nIndex; /* Statistics for most recent operation */ int nStep, nSort, nIndex; /* Statistics for most recent operation */
int nTransaction; /* Number of nested [transaction] methods */ int nTransaction; /* Number of nested [transaction] methods */
#ifdef SQLITE_TEST
int bLegacyPrepare; /* True to use sqlite3_prepare() */
#endif
}; };
struct IncrblobChannel { struct IncrblobChannel {
@@ -430,20 +438,33 @@ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
return pNew; return pNew;
} }
/*
** Free a single SqlPreparedStmt object.
*/
static void dbFreeStmt(SqlPreparedStmt *pStmt){
#ifdef SQLITE_TEST
if( sqlite3_sql(pStmt->pStmt)==0 ){
Tcl_Free((char *)pStmt->zSql);
}
#endif
sqlite3_finalize(pStmt->pStmt);
Tcl_Free((char *)pStmt);
}
/* /*
** Finalize and free a list of prepared statements ** Finalize and free a list of prepared statements
*/ */
static void flushStmtCache( SqliteDb *pDb ){ static void flushStmtCache(SqliteDb *pDb){
SqlPreparedStmt *pPreStmt; SqlPreparedStmt *pPreStmt;
SqlPreparedStmt *pNext;
while( pDb->stmtList ){ for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){
sqlite3_finalize( pDb->stmtList->pStmt ); pNext = pPreStmt->pNext;
pPreStmt = pDb->stmtList; dbFreeStmt(pPreStmt);
pDb->stmtList = pDb->stmtList->pNext;
Tcl_Free( (char*)pPreStmt );
} }
pDb->nStmt = 0; pDb->nStmt = 0;
pDb->stmtLast = 0; pDb->stmtLast = 0;
pDb->stmtList = 0;
} }
/* /*
@@ -1074,6 +1095,27 @@ static int DbTransPostCmd(
return rc; return rc;
} }
/*
** Unless SQLITE_TEST is defined, this function is a simple wrapper around
** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either
** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending
** on whether or not the [db_use_legacy_prepare] command has been used to
** configure the connection.
*/
static int dbPrepare(
SqliteDb *pDb, /* Database object */
const char *zSql, /* SQL to compile */
sqlite3_stmt **ppStmt, /* OUT: Prepared statement */
const char **pzOut /* OUT: Pointer to next SQL statement */
){
#ifdef SQLITE_TEST
if( pDb->bLegacyPrepare ){
return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut);
}
#endif
return sqlite3_prepare_v2(pDb->db, zSql, -1, ppStmt, pzOut);
}
/* /*
** Search the cache for a prepared-statement object that implements the ** Search the cache for a prepared-statement object that implements the
** first SQL statement in the buffer pointed to by parameter zIn. If ** first SQL statement in the buffer pointed to by parameter zIn. If
@@ -1144,7 +1186,7 @@ static int dbPrepareAndBind(
if( pPreStmt==0 ){ if( pPreStmt==0 ){
int nByte; int nByte;
if( SQLITE_OK!=sqlite3_prepare_v2(pDb->db, zSql, -1, &pStmt, pzOut) ){ if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
return TCL_ERROR; return TCL_ERROR;
} }
@@ -1171,6 +1213,14 @@ static int dbPrepareAndBind(
pPreStmt->nSql = (*pzOut - zSql); pPreStmt->nSql = (*pzOut - zSql);
pPreStmt->zSql = sqlite3_sql(pStmt); pPreStmt->zSql = sqlite3_sql(pStmt);
pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1]; pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1];
#ifdef SQLITE_TEST
if( pPreStmt->zSql==0 ){
char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1);
memcpy(zCopy, zSql, pPreStmt->nSql);
zCopy[pPreStmt->nSql] = '\0';
pPreStmt->zSql = zCopy;
}
#endif
} }
assert( pPreStmt ); assert( pPreStmt );
assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql );
@@ -1224,7 +1274,6 @@ static int dbPrepareAndBind(
return TCL_OK; return TCL_OK;
} }
/* /*
** Release a statement reference obtained by calling dbPrepareAndBind(). ** Release a statement reference obtained by calling dbPrepareAndBind().
** There should be exactly one call to this function for each call to ** There should be exactly one call to this function for each call to
@@ -1249,8 +1298,7 @@ static void dbReleaseStmt(
if( pDb->maxStmt<=0 || discard ){ if( pDb->maxStmt<=0 || discard ){
/* If the cache is turned off, deallocated the statement */ /* If the cache is turned off, deallocated the statement */
sqlite3_finalize(pPreStmt->pStmt); dbFreeStmt(pPreStmt);
Tcl_Free((char *)pPreStmt);
}else{ }else{
/* Add the prepared statement to the beginning of the cache list. */ /* Add the prepared statement to the beginning of the cache list. */
pPreStmt->pNext = pDb->stmtList; pPreStmt->pNext = pDb->stmtList;
@@ -1270,11 +1318,11 @@ static void dbReleaseStmt(
/* If we have too many statement in cache, remove the surplus from /* If we have too many statement in cache, remove the surplus from
** the end of the cache list. */ ** the end of the cache list. */
while( pDb->nStmt>pDb->maxStmt ){ while( pDb->nStmt>pDb->maxStmt ){
sqlite3_finalize(pDb->stmtLast->pStmt); SqlPreparedStmt *pLast = pDb->stmtLast;
pDb->stmtLast = pDb->stmtLast->pPrev; pDb->stmtLast = pLast->pPrev;
Tcl_Free((char*)pDb->stmtLast->pNext);
pDb->stmtLast->pNext = 0; pDb->stmtLast->pNext = 0;
pDb->nStmt--; pDb->nStmt--;
dbFreeStmt(pLast);
} }
} }
} }
@@ -1407,9 +1455,12 @@ static void dbEvalRowInfo(
** no further rows available. This is similar to SQLITE_DONE. ** no further rows available. This is similar to SQLITE_DONE.
*/ */
static int dbEvalStep(DbEvalContext *p){ static int dbEvalStep(DbEvalContext *p){
const char *zPrevSql = 0; /* Previous value of p->zSql */
while( p->zSql[0] || p->pPreStmt ){ while( p->zSql[0] || p->pPreStmt ){
int rc; int rc;
if( p->pPreStmt==0 ){ if( p->pPreStmt==0 ){
zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql);
rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt); rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt);
if( rc!=TCL_OK ) return rc; if( rc!=TCL_OK ) return rc;
}else{ }else{
@@ -1436,8 +1487,19 @@ static int dbEvalStep(DbEvalContext *p){
if( rcs!=SQLITE_OK ){ if( rcs!=SQLITE_OK ){
/* If a run-time error occurs, report the error and stop reading /* If a run-time error occurs, report the error and stop reading
** the SQL. */ ** the SQL. */
Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
dbReleaseStmt(pDb, pPreStmt, 1); dbReleaseStmt(pDb, pPreStmt, 1);
#if SQLITE_TEST
if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){
/* If the runtime error was an SQLITE_SCHEMA, and the database
** handle is configured to use the legacy sqlite3_prepare()
** interface, retry prepare()/step() on the same SQL statement.
** This only happens once. If there is a second SQLITE_SCHEMA
** error, the error will be returned to the caller. */
p->zSql = zPrevSql;
continue;
}
#endif
Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
return TCL_ERROR; return TCL_ERROR;
}else{ }else{
dbReleaseStmt(pDb, pPreStmt, 0); dbReleaseStmt(pDb, pPreStmt, 0);
@@ -3072,7 +3134,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{ }else{
flags &= ~SQLITE_OPEN_NOMUTEX; flags &= ~SQLITE_OPEN_NOMUTEX;
} }
}else if( strcmp(zArg, "-fullmutex")==0 ){ }else if( strcmp(zArg, "-fullmutex")==0 ){
int b; int b;
if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
if( b ){ if( b ){
@@ -3673,6 +3735,44 @@ static int init_all_cmd(
init_all(slave); init_all(slave);
return TCL_OK; return TCL_OK;
} }
/*
** Tclcmd: db_use_legacy_prepare DB BOOLEAN
**
** The first argument to this command must be a database command created by
** [sqlite3]. If the second argument is true, then the handle is configured
** to use the sqlite3_prepare_v2() function to prepare statements. If it
** is false, sqlite3_prepare().
*/
static int db_use_legacy_prepare_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
Tcl_CmdInfo cmdInfo;
SqliteDb *pDb;
int bPrepare;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
return TCL_ERROR;
}
if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0);
return TCL_ERROR;
}
pDb = (SqliteDb*)cmdInfo.objClientData;
if( Tcl_GetBooleanFromObj(interp, objv[2], &bPrepare) ){
return TCL_ERROR;
}
pDb->bLegacyPrepare = bPrepare;
Tcl_ResetResult(interp);
return TCL_OK;
}
#endif #endif
/* /*
@@ -3783,7 +3883,12 @@ static void init_all(Tcl_Interp *interp){
Sqlitetestfts3_Init(interp); Sqlitetestfts3_Init(interp);
#endif #endif
Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0); Tcl_CreateObjCommand(
interp, "load_testfixture_extensions", init_all_cmd, 0, 0
);
Tcl_CreateObjCommand(
interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0
);
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
Sqlitetestsse_Init(interp); Sqlitetestsse_Init(interp);

View File

@@ -5096,6 +5096,39 @@ static int file_control_lockproxy_test(
return TCL_OK; return TCL_OK;
} }
/*
** tclcmd: file_control_win32_av_retry DB NRETRY DELAY
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_WIN32_AV_RETRY opcode.
*/
static int file_control_win32_av_retry(
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;
int a[2];
char z[100];
if( objc!=4 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[2], &a[0]) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
Tcl_AppendResult(interp, z, (char*)0);
return TCL_OK;
}
/* /*
** tclcmd: sqlite3_vfs_list ** tclcmd: sqlite3_vfs_list
@@ -5574,6 +5607,94 @@ static int test_test_control(
return TCL_OK; return TCL_OK;
} }
#if SQLITE_OS_WIN
/*
** Information passed from the main thread into the windows file locker
** background thread.
*/
struct win32FileLocker {
HANDLE h; /* Handle of the file to be locked */
int delay1; /* Delay before locking */
int delay2; /* Delay before unlocking */
int ok; /* Finished ok */
int err; /* True if an error occurs */
};
#endif
#if SQLITE_OS_WIN
/*
** The background thread that does file locking.
*/
static void win32_file_locker(void *pAppData){
struct win32FileLocker *p = (struct win32FileLocker*)pAppData;
if( p->delay1 ) Sleep(p->delay1);
if( LockFile(p->h, 0, 0, 100000000, 0) ){
Sleep(p->delay2);
UnlockFile(p->h, 0, 0, 100000000, 0);
p->ok = 1;
}else{
p->err = 1;
}
CloseHandle(p->h);
p->h = 0;
p->delay1 = 0;
p->delay2 = 0;
}
#endif
#if SQLITE_OS_WIN
/*
** lock_win32_file FILENAME DELAY1 DELAY2
**
** Get an exclusive manditory lock on file for DELAY2 milliseconds.
** Wait DELAY1 milliseconds before acquiring the lock.
*/
static int win32_file_lock(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
static struct win32FileLocker x = { 0, 0, 0 };
const char *zFilename;
int retry = 0;
if( objc!=4 && objc!=1 ){
Tcl_WrongNumArgs(interp, 1, objv, "FILENAME DELAY1 DELAY2");
return TCL_ERROR;
}
if( objc==1 ){
char zBuf[200];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d",
x.ok, x.err, x.delay1, x.delay2, x.h);
Tcl_AppendResult(interp, zBuf, (char*)0);
return TCL_OK;
}
while( x.h && retry<30 ){
retry++;
Sleep(100);
}
if( x.h ){
Tcl_AppendResult(interp, "busy", (char*)0);
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[2], &x.delay1) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[3], &x.delay2) ) return TCL_ERROR;
zFilename = Tcl_GetString(objv[1]);
x.h = CreateFile(zFilename, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);
if( !x.h ){
Tcl_AppendResult(interp, "cannot open file: ", zFilename, (char*)0);
return TCL_ERROR;
}
_beginthread(win32_file_locker, 0, (void*)&x);
Sleep(0);
return TCL_OK;
}
#endif
/* /*
** optimization_control DB OPT BOOLEAN ** optimization_control DB OPT BOOLEAN
@@ -5754,6 +5875,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "restore_prng_state", restore_prng_state, 0 }, { "restore_prng_state", restore_prng_state, 0 },
{ "reset_prng_state", reset_prng_state, 0 }, { "reset_prng_state", reset_prng_state, 0 },
{ "optimization_control", optimization_control,0}, { "optimization_control", optimization_control,0},
#if SQLITE_OS_WIN
{ "lock_win32_file", win32_file_lock, 0 },
#endif
{ "tcl_objproc", runAsObjProc, 0 }, { "tcl_objproc", runAsObjProc, 0 },
/* sqlite3_column_*() API */ /* sqlite3_column_*() API */
@@ -5802,7 +5926,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_lasterrno_test", file_control_lasterrno_test, 0 }, { "file_control_lasterrno_test", file_control_lasterrno_test, 0 },
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, { "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
{ "file_control_chunksize_test", file_control_chunksize_test, 0 }, { "file_control_chunksize_test", file_control_chunksize_test, 0 },
{ "file_control_sizehint_test", file_control_sizehint_test, 0 }, { "file_control_sizehint_test", file_control_sizehint_test, 0 },
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
{ "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_vfs_list", vfs_list, 0 },
{ "sqlite3_create_function_v2", test_create_function_v2, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 },

View File

@@ -583,6 +583,7 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
LINKVAR( DEFAULT_PAGE_SIZE ); LINKVAR( DEFAULT_PAGE_SIZE );
LINKVAR( DEFAULT_FILE_FORMAT ); LINKVAR( DEFAULT_FILE_FORMAT );
LINKVAR( MAX_ATTACHED ); LINKVAR( MAX_ATTACHED );
LINKVAR( MAX_DEFAULT_PAGE_SIZE );
{ {
static const int cv_TEMP_STORE = SQLITE_TEMP_STORE; static const int cv_TEMP_STORE = SQLITE_TEMP_STORE;

View File

@@ -45,6 +45,7 @@
#include "sqlite3.h" #include "sqlite3.h"
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h>
#include "test_multiplex.h" #include "test_multiplex.h"
#ifndef SQLITE_CORE #ifndef SQLITE_CORE
@@ -78,20 +79,26 @@
/************************ Shim Definitions ******************************/ /************************ Shim Definitions ******************************/
#define SQLITE_MULTIPLEX_VFS_NAME "multiplex" #ifndef SQLITE_MULTIPLEX_VFS_NAME
# define SQLITE_MULTIPLEX_VFS_NAME "multiplex"
#endif
/* This is the limit on the chunk size. It may be changed by calling /* This is the limit on the chunk size. It may be changed by calling
** the xFileControl() interface. It will be rounded up to a ** the xFileControl() interface. It will be rounded up to a
** multiple of MAX_PAGE_SIZE. We default it here to 1GB. ** multiple of MAX_PAGE_SIZE. We default it here to 2GiB less 64KiB.
*/ */
#define SQLITE_MULTIPLEX_CHUNK_SIZE (MAX_PAGE_SIZE*16384) #ifndef SQLITE_MULTIPLEX_CHUNK_SIZE
# define SQLITE_MULTIPLEX_CHUNK_SIZE 2147418112
#endif
/* Default limit on number of chunks. Care should be taken /* Default limit on number of chunks. Care should be taken
** so that values for chunks numbers fit in the SQLITE_MULTIPLEX_EXT_FMT ** so that values for chunks numbers fit in the SQLITE_MULTIPLEX_EXT_FMT
** format specifier. It may be changed by calling ** format specifier. It may be changed by calling
** the xFileControl() interface. ** the xFileControl() interface.
*/ */
#define SQLITE_MULTIPLEX_MAX_CHUNKS 32 #ifndef SQLITE_MULTIPLEX_MAX_CHUNKS
# define SQLITE_MULTIPLEX_MAX_CHUNKS 32
#endif
/* If SQLITE_MULTIPLEX_EXT_OVWR is defined, the /* If SQLITE_MULTIPLEX_EXT_OVWR is defined, the
** last SQLITE_MULTIPLEX_EXT_SZ characters of the ** last SQLITE_MULTIPLEX_EXT_SZ characters of the
@@ -119,13 +126,15 @@ typedef struct multiplexConn multiplexConn;
** group. ** group.
*/ */
struct multiplexGroup { struct multiplexGroup {
sqlite3_file **pReal; /* Handles to each chunk */ struct multiplexReal { /* For each chunk */
char *bOpen; /* array of bools - 0 if chunk not opened */ sqlite3_file *p; /* Handle for the chunk */
char *z; /* Name of this chunk */
} *aReal; /* list of all chunks */
int nReal; /* Number of chunks */
char *zName; /* Base filename of this group */ char *zName; /* Base filename of this group */
int nName; /* Length of base filename */ int nName; /* Length of base filename */
int flags; /* Flags used for original opening */ int flags; /* Flags used for original opening */
int nChunkSize; /* Chunk size used for this group */ unsigned int szChunk; /* Chunk size used for this group */
int nMaxChunks; /* Max number of chunks for this group */
int bEnabled; /* TRUE to use Multiplex VFS for this file */ int bEnabled; /* TRUE to use Multiplex VFS for this file */
multiplexGroup *pNext, *pPrev; /* Doubly linked list of all group objects */ multiplexGroup *pNext, *pPrev; /* Doubly linked list of all group objects */
}; };
@@ -184,12 +193,6 @@ static struct {
/* List of multiplexGroup objects. /* List of multiplexGroup objects.
*/ */
multiplexGroup *pGroups; multiplexGroup *pGroups;
/* Storage for temp file names. Allocated during
** initialization to the max pathname of the underlying VFS.
*/
char *zName;
} gMultiplex; } gMultiplex;
/************************* Utility Routines *********************************/ /************************* Utility Routines *********************************/
@@ -265,7 +268,8 @@ static int multiplexGetTempname(sqlite3_vfs *pOrigVfs, int nBuf, char *zBuf){
attempts++; attempts++;
sqlite3_randomness(8, &zBuf[j]); sqlite3_randomness(8, &zBuf[j]);
for(i=0; i<8; i++){ for(i=0; i<8; i++){
zBuf[j+i] = (char)zChars[ ((unsigned char)zBuf[j+i])%(sizeof(zChars)-1) ]; unsigned char uc = (unsigned char)zBuf[j+i];
zBuf[j+i] = (char)zChars[uc%(sizeof(zChars)-1)];
} }
memcpy(&zBuf[j+i], ".tmp", 5); memcpy(&zBuf[j+i], ".tmp", 5);
rc = pOrigVfs->xAccess(pOrigVfs, zBuf, SQLITE_ACCESS_EXISTS, &exists); rc = pOrigVfs->xAccess(pOrigVfs, zBuf, SQLITE_ACCESS_EXISTS, &exists);
@@ -279,35 +283,69 @@ static int multiplexGetTempname(sqlite3_vfs *pOrigVfs, int nBuf, char *zBuf){
return rc; return rc;
} }
/* Compute the filename for the iChunk-th chunk
*/
static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
if( iChunk>=pGroup->nReal ){
struct multiplexReal *p;
p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p));
if( p==0 ){
return SQLITE_NOMEM;
}
memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal));
pGroup->aReal = p;
pGroup->nReal = iChunk+1;
}
if( pGroup->aReal[iChunk].z==0 ){
char *z;
int n = pGroup->nName;
pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+3 );
if( z==0 ){
return SQLITE_NOMEM;
}
memcpy(z, pGroup->zName, n+1);
if( iChunk>0 ){
#ifdef SQLITE_ENABLE_8_3_NAMES
if( n>3 && z[n-3]=='.' ){
n--;
}else if( n>4 && z[n-4]=='.' ){
n -= 2;
}
#endif
sqlite3_snprintf(3,&z[n],"%02d",iChunk);
}
}
return SQLITE_OK;
}
/* Translate an sqlite3_file* that is really a multiplexGroup* into /* Translate an sqlite3_file* that is really a multiplexGroup* into
** the sqlite3_file* for the underlying original VFS. ** the sqlite3_file* for the underlying original VFS.
*/ */
static sqlite3_file *multiplexSubOpen(multiplexConn *pConn, int iChunk, int *rc, int *pOutFlags){ static sqlite3_file *multiplexSubOpen(
multiplexGroup *pGroup = pConn->pGroup; multiplexGroup *pGroup,
int iChunk,
int *rc,
int *pOutFlags
){
sqlite3_file *pSubOpen = 0;
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
if( iChunk<pGroup->nMaxChunks ){ *rc = multiplexSubFilename(pGroup, iChunk);
sqlite3_file *pSubOpen = pGroup->pReal[iChunk]; /* Real file descriptor */ if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
if( !pGroup->bOpen[iChunk] ){ pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1); if( pSubOpen==0 ){
if( iChunk ){ *rc = SQLITE_NOMEM;
#ifdef SQLITE_MULTIPLEX_EXT_OVWR return 0;
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ, SQLITE_MULTIPLEX_EXT_FMT, iChunk); }
#else pGroup->aReal[iChunk].p = pSubOpen;
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+pGroup->nName, SQLITE_MULTIPLEX_EXT_FMT, iChunk); *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
#endif pGroup->flags, pOutFlags);
} if( *rc!=SQLITE_OK ){
*rc = pOrigVfs->xOpen(pOrigVfs, gMultiplex.zName, pSubOpen, pGroup->flags, pOutFlags); sqlite3_free(pSubOpen);
if( *rc==SQLITE_OK ){ pGroup->aReal[iChunk].p = 0;
pGroup->bOpen[iChunk] = -1; return 0;
return pSubOpen;
}
return NULL;
} }
*rc = SQLITE_OK;
return pSubOpen;
} }
*rc = SQLITE_FULL; return pSubOpen;
return NULL;
} }
/* /*
@@ -366,6 +404,36 @@ static int multiplexFuncInit(
return rc; return rc;
} }
/*
** Close a single sub-file in the connection group.
*/
static void multiplexSubClose(
multiplexGroup *pGroup,
int iChunk,
sqlite3_vfs *pOrigVfs
){
sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
if( pSubOpen ){
if( pOrigVfs ) pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
pSubOpen->pMethods->xClose(pSubOpen);
sqlite3_free(pGroup->aReal[iChunk].p);
}
sqlite3_free(pGroup->aReal[iChunk].z);
memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
}
/*
** Deallocate memory held by a multiplexGroup
*/
static void multiplexFreeComponents(multiplexGroup *pGroup){
int i;
for(i=0; i<pGroup->nReal; i++){ multiplexSubClose(pGroup, i, 0); }
sqlite3_free(pGroup->aReal);
pGroup->aReal = 0;
pGroup->nReal = 0;
}
/************************* VFS Method Wrappers *****************************/ /************************* VFS Method Wrappers *****************************/
/* /*
@@ -382,16 +450,17 @@ static int multiplexOpen(
int flags, /* Flags to control the opening */ int flags, /* Flags to control the opening */
int *pOutFlags /* Flags showing results of opening */ int *pOutFlags /* Flags showing results of opening */
){ ){
int rc = SQLITE_OK; /* Result code */ int rc = SQLITE_OK; /* Result code */
multiplexConn *pMultiplexOpen; /* The new multiplex file descriptor */ multiplexConn *pMultiplexOpen; /* The new multiplex file descriptor */
multiplexGroup *pGroup; /* Corresponding multiplexGroup object */ multiplexGroup *pGroup; /* Corresponding multiplexGroup object */
sqlite3_file *pSubOpen; /* Real file descriptor */ sqlite3_file *pSubOpen = 0; /* Real file descriptor */
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
int nName; int nName;
int i;
int sz; int sz;
char *zToFree = 0;
UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(pVfs);
memset(pConn, 0, pVfs->szOsFile);
/* We need to create a group structure and manage /* We need to create a group structure and manage
** access to this group of files. ** access to this group of files.
@@ -405,28 +474,22 @@ static int multiplexOpen(
** it. ** it.
*/ */
if( !zName ){ if( !zName ){
rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, gMultiplex.zName); zName = zToFree = sqlite3_malloc( pOrigVfs->mxPathname + 10 );
zName = gMultiplex.zName; if( zName==0 ){
rc = SQLITE_NOMEM;
}else{
rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, zToFree);
}
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
/* allocate space for group */ /* allocate space for group */
nName = multiplexStrlen30(zName); nName = multiplexStrlen30(zName);
sz = sizeof(multiplexGroup) /* multiplexGroup */ sz = sizeof(multiplexGroup) /* multiplexGroup */
+ (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS) /* pReal[] */ + nName + 1; /* zName */
+ (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS) /* *pReal */
+ SQLITE_MULTIPLEX_MAX_CHUNKS /* bOpen[] */
+ nName + 1; /* zName */
#ifndef SQLITE_MULTIPLEX_EXT_OVWR
sz += SQLITE_MULTIPLEX_EXT_SZ;
assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname);
#else
assert(nName >= SQLITE_MULTIPLEX_EXT_SZ);
assert(nName < pOrigVfs->mxPathname);
#endif
pGroup = sqlite3_malloc( sz ); pGroup = sqlite3_malloc( sz );
if( pGroup==0 ){ if( pGroup==0 ){
rc=SQLITE_NOMEM; rc = SQLITE_NOMEM;
} }
} }
@@ -436,32 +499,58 @@ static int multiplexOpen(
pMultiplexOpen->pGroup = pGroup; pMultiplexOpen->pGroup = pGroup;
memset(pGroup, 0, sz); memset(pGroup, 0, sz);
pGroup->bEnabled = -1; pGroup->bEnabled = -1;
pGroup->nChunkSize = SQLITE_MULTIPLEX_CHUNK_SIZE; pGroup->szChunk = SQLITE_MULTIPLEX_CHUNK_SIZE;
pGroup->nMaxChunks = SQLITE_MULTIPLEX_MAX_CHUNKS; if( flags & SQLITE_OPEN_URI ){
pGroup->pReal = (sqlite3_file **)p; const char *zChunkSize;
p += (sizeof(sqlite3_file *)*pGroup->nMaxChunks); zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
for(i=0; i<pGroup->nMaxChunks; i++){ if( zChunkSize ){
pGroup->pReal[i] = (sqlite3_file *)p; unsigned int n = 0;
p += pOrigVfs->szOsFile; int i;
for(i=0; zChunkSize[i]>='0' && zChunkSize[i]<='9'; i++){
n = n*10 + zChunkSize[i] - '0';
}
if( n>0 ){
pGroup->szChunk = (n+0xffff)&~0xffff;
}else{
/* A zero or negative chunksize disabled the multiplexor */
pGroup->bEnabled = 0;
}
}
} }
/* bOpen[] vals should all be zero from memset above */
pGroup->bOpen = p;
p += pGroup->nMaxChunks;
pGroup->zName = p; pGroup->zName = p;
/* save off base filename, name length, and original open flags */ /* save off base filename, name length, and original open flags */
memcpy(pGroup->zName, zName, nName+1); memcpy(pGroup->zName, zName, nName+1);
pGroup->nName = nName; pGroup->nName = nName;
pGroup->flags = flags; pGroup->flags = flags;
pSubOpen = multiplexSubOpen(pMultiplexOpen, 0, &rc, pOutFlags); rc = multiplexSubFilename(pGroup, 1);
if( rc==SQLITE_OK ){
pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags);
}
if( pSubOpen ){ if( pSubOpen ){
/* if this file is already larger than chunk size, disable int exists, rc2, rc3;
** the multiplex feature.
*/
sqlite3_int64 sz; sqlite3_int64 sz;
int rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
if( (rc2==SQLITE_OK) && (sz>pGroup->nChunkSize) ){ rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
pGroup->bEnabled = 0; if( rc2==SQLITE_OK ){
/* If the first overflow file exists and if the size of the main file
** is different from the chunk size, that means the chunk size is set
** set incorrectly. So fix it.
**
** Or, if the first overflow file does not exist and the main file is
** larger than the chunk size, that means the chunk size is too small.
** But we have no way of determining the intended chunk size, so
** just disable the multiplexor all togethre.
*/
rc3 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
SQLITE_ACCESS_EXISTS, &exists);
if( rc3==SQLITE_OK && exists && sz==(sz&0xffff0000) && sz>0
&& sz!=pGroup->szChunk ){
pGroup->szChunk = sz;
}else if( rc3==SQLITE_OK && !exists && sz>pGroup->szChunk ){
pGroup->bEnabled = 0;
}
} }
if( pSubOpen->pMethods->iVersion==1 ){ if( pSubOpen->pMethods->iVersion==1 ){
pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1; pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
}else{ }else{
@@ -472,17 +561,18 @@ static int multiplexOpen(
if( gMultiplex.pGroups ) gMultiplex.pGroups->pPrev = pGroup; if( gMultiplex.pGroups ) gMultiplex.pGroups->pPrev = pGroup;
gMultiplex.pGroups = pGroup; gMultiplex.pGroups = pGroup;
}else{ }else{
multiplexFreeComponents(pGroup);
sqlite3_free(pGroup); sqlite3_free(pGroup);
} }
} }
multiplexLeave(); multiplexLeave();
sqlite3_free(zToFree);
return rc; return rc;
} }
/* /*
** This is the xDelete method used for the "multiplex" VFS. ** This is the xDelete method used for the "multiplex" VFS.
** It attempts to delete the filename specified, as well ** It attempts to delete the filename specified.
** as additional files with the SQLITE_MULTIPLEX_EXT_FMT extension.
*/ */
static int multiplexDelete( static int multiplexDelete(
sqlite3_vfs *pVfs, /* The multiplex VFS */ sqlite3_vfs *pVfs, /* The multiplex VFS */
@@ -490,41 +580,7 @@ static int multiplexDelete(
int syncDir int syncDir
){ ){
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
int rc = SQLITE_OK; return pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
int nName = multiplexStrlen30(zName);
int i;
UNUSED_PARAMETER(pVfs);
multiplexEnter();
memcpy(gMultiplex.zName, zName, nName+1);
for(i=0; i<SQLITE_MULTIPLEX_MAX_CHUNKS; i++){
int rc2;
int exists = 0;
if( i ){
#ifdef SQLITE_MULTIPLEX_EXT_OVWR
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
gMultiplex.zName+nName-SQLITE_MULTIPLEX_EXT_SZ,
SQLITE_MULTIPLEX_EXT_FMT, i);
#else
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
gMultiplex.zName+nName,
SQLITE_MULTIPLEX_EXT_FMT, i);
#endif
}
rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName,
SQLITE_ACCESS_EXISTS, &exists);
if( rc2==SQLITE_OK && exists ){
/* if it exists, delete it */
rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir);
if( rc2!=SQLITE_OK ) rc = rc2;
}else{
/* stop at first "gap" */
break;
}
}
multiplexLeave();
return rc;
} }
static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){ static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
@@ -572,17 +628,8 @@ static int multiplexClose(sqlite3_file *pConn){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
multiplexGroup *pGroup = p->pGroup; multiplexGroup *pGroup = p->pGroup;
int rc = SQLITE_OK; int rc = SQLITE_OK;
int i;
multiplexEnter(); multiplexEnter();
/* close any open handles */ multiplexFreeComponents(pGroup);
for(i=0; i<pGroup->nMaxChunks; i++){
if( pGroup->bOpen[i] ){
sqlite3_file *pSubOpen = pGroup->pReal[i];
int rc2 = pSubOpen->pMethods->xClose(pSubOpen);
if( rc2!=SQLITE_OK ) rc = rc2;
pGroup->bOpen[i] = 0;
}
}
/* remove from linked list */ /* remove from linked list */
if( pGroup->pNext ) pGroup->pNext->pPrev = pGroup->pPrev; if( pGroup->pNext ) pGroup->pNext->pPrev = pGroup->pPrev;
if( pGroup->pPrev ){ if( pGroup->pPrev ){
@@ -610,17 +657,22 @@ static int multiplexRead(
int rc = SQLITE_OK; int rc = SQLITE_OK;
multiplexEnter(); multiplexEnter();
if( !pGroup->bEnabled ){ if( !pGroup->bEnabled ){
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
rc = ( !pSubOpen ) ? SQLITE_IOERR_READ : pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst); if( pSubOpen==0 ){
rc = SQLITE_IOERR_READ;
}else{
rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
}
}else{ }else{
while( iAmt > 0 ){ while( iAmt > 0 ){
int i = (int)(iOfst / pGroup->nChunkSize); int i = (int)(iOfst / pGroup->szChunk);
sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) - pGroup->nChunkSize; int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk;
if( extra<0 ) extra = 0; if( extra<0 ) extra = 0;
iAmt -= extra; iAmt -= extra;
rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst % pGroup->nChunkSize); rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt,
iOfst % pGroup->szChunk);
if( rc!=SQLITE_OK ) break; if( rc!=SQLITE_OK ) break;
pBuf = (char *)pBuf + iAmt; pBuf = (char *)pBuf + iAmt;
iOfst += iAmt; iOfst += iAmt;
@@ -650,17 +702,23 @@ static int multiplexWrite(
int rc = SQLITE_OK; int rc = SQLITE_OK;
multiplexEnter(); multiplexEnter();
if( !pGroup->bEnabled ){ if( !pGroup->bEnabled ){
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
rc = ( !pSubOpen ) ? SQLITE_IOERR_WRITE : pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst); if( pSubOpen==0 ){
rc = SQLITE_IOERR_WRITE;
}else{
rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
}
}else{ }else{
while( iAmt > 0 ){ while( iAmt > 0 ){
int i = (int)(iOfst / pGroup->nChunkSize); int i = (int)(iOfst / pGroup->szChunk);
sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) - pGroup->nChunkSize; int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) -
pGroup->szChunk;
if( extra<0 ) extra = 0; if( extra<0 ) extra = 0;
iAmt -= extra; iAmt -= extra;
rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst % pGroup->nChunkSize); rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt,
iOfst % pGroup->szChunk);
if( rc!=SQLITE_OK ) break; if( rc!=SQLITE_OK ) break;
pBuf = (char *)pBuf + iAmt; pBuf = (char *)pBuf + iAmt;
iOfst += iAmt; iOfst += iAmt;
@@ -685,38 +743,24 @@ static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
int rc = SQLITE_OK; int rc = SQLITE_OK;
multiplexEnter(); multiplexEnter();
if( !pGroup->bEnabled ){ if( !pGroup->bEnabled ){
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
rc = ( !pSubOpen ) ? SQLITE_IOERR_TRUNCATE : pSubOpen->pMethods->xTruncate(pSubOpen, size); if( pSubOpen==0 ){
rc = SQLITE_IOERR_TRUNCATE;
}else{
rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
}
}else{ }else{
int rc2; int rc2;
int i; int i;
sqlite3_file *pSubOpen; sqlite3_file *pSubOpen;
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
/* delete the chunks above the truncate limit */ /* delete the chunks above the truncate limit */
for(i=(int)(size / pGroup->nChunkSize)+1; i<pGroup->nMaxChunks; i++){ for(i=(int)(size / pGroup->szChunk)+1; i<pGroup->nReal; i++){
/* close any open chunks before deleting them */ multiplexSubClose(pGroup, i, pOrigVfs);
if( pGroup->bOpen[i] ){
pSubOpen = pGroup->pReal[i];
rc2 = pSubOpen->pMethods->xClose(pSubOpen);
if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE;
pGroup->bOpen[i] = 0;
}
#ifdef SQLITE_MULTIPLEX_EXT_OVWR
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ,
SQLITE_MULTIPLEX_EXT_FMT, i);
#else
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
gMultiplex.zName+pGroup->nName,
SQLITE_MULTIPLEX_EXT_FMT, i);
#endif
rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, 0);
if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE;
} }
pSubOpen = multiplexSubOpen(p, (int)(size / pGroup->nChunkSize), &rc2, NULL); pSubOpen = multiplexSubOpen(pGroup, (int)(size/pGroup->szChunk), &rc2,0);
if( pSubOpen ){ if( pSubOpen ){
rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->nChunkSize); rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk);
if( rc2!=SQLITE_OK ) rc = rc2; if( rc2!=SQLITE_OK ) rc = rc2;
}else{ }else{
rc = SQLITE_IOERR_TRUNCATE; rc = SQLITE_IOERR_TRUNCATE;
@@ -734,10 +778,9 @@ static int multiplexSync(sqlite3_file *pConn, int flags){
int rc = SQLITE_OK; int rc = SQLITE_OK;
int i; int i;
multiplexEnter(); multiplexEnter();
for(i=0; i<pGroup->nMaxChunks; i++){ for(i=0; i<pGroup->nReal; i++){
/* if we don't have it open, we don't need to sync it */ sqlite3_file *pSubOpen = pGroup->aReal[i].p;
if( pGroup->bOpen[i] ){ if( pSubOpen ){
sqlite3_file *pSubOpen = pGroup->pReal[i];
int rc2 = pSubOpen->pMethods->xSync(pSubOpen, flags); int rc2 = pSubOpen->pMethods->xSync(pSubOpen, flags);
if( rc2!=SQLITE_OK ) rc = rc2; if( rc2!=SQLITE_OK ) rc = rc2;
} }
@@ -757,39 +800,28 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
int i; int i;
multiplexEnter(); multiplexEnter();
if( !pGroup->bEnabled ){ if( !pGroup->bEnabled ){
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
rc = ( !pSubOpen ) ? SQLITE_IOERR_FSTAT : pSubOpen->pMethods->xFileSize(pSubOpen, pSize); if( pSubOpen==0 ){
rc = SQLITE_IOERR_FSTAT;
}else{
rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
}
}else{ }else{
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;
*pSize = 0; *pSize = 0;
for(i=0; i<pGroup->nMaxChunks; i++){ for(i=0; 1; i++){
sqlite3_file *pSubOpen = NULL; sqlite3_file *pSubOpen = 0;
/* if not opened already, check to see if the chunk exists */ int exists = 0;
if( pGroup->bOpen[i] ){ rc = multiplexSubFilename(pGroup, i);
pSubOpen = pGroup->pReal[i]; if( rc ) break;
rc2 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[i].z,
SQLITE_ACCESS_EXISTS, &exists);
if( rc2==SQLITE_OK && exists){
/* if it exists, open it */
pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
}else{ }else{
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ /* stop at first "gap" */
int exists = 0; break;
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
if( i ){
#ifdef SQLITE_MULTIPLEX_EXT_OVWR
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ,
SQLITE_MULTIPLEX_EXT_FMT, i);
#else
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
gMultiplex.zName+pGroup->nName,
SQLITE_MULTIPLEX_EXT_FMT, i);
#endif
}
rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName,
SQLITE_ACCESS_EXISTS, &exists);
if( rc2==SQLITE_OK && exists){
/* if it exists, open it */
pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
}else{
/* stop at first "gap" */
break;
}
} }
if( pSubOpen ){ if( pSubOpen ){
sqlite3_int64 sz; sqlite3_int64 sz;
@@ -797,7 +829,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
if( rc2!=SQLITE_OK ){ if( rc2!=SQLITE_OK ){
rc = rc2; rc = rc2;
}else{ }else{
if( sz>pGroup->nChunkSize ){ if( sz>pGroup->szChunk ){
rc = SQLITE_IOERR_FSTAT; rc = SQLITE_IOERR_FSTAT;
} }
*pSize += sz; *pSize += sz;
@@ -816,7 +848,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
static int multiplexLock(sqlite3_file *pConn, int lock){ static int multiplexLock(sqlite3_file *pConn, int lock){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
return pSubOpen->pMethods->xLock(pSubOpen, lock); return pSubOpen->pMethods->xLock(pSubOpen, lock);
} }
@@ -828,7 +860,7 @@ static int multiplexLock(sqlite3_file *pConn, int lock){
static int multiplexUnlock(sqlite3_file *pConn, int lock){ static int multiplexUnlock(sqlite3_file *pConn, int lock){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
return pSubOpen->pMethods->xUnlock(pSubOpen, lock); return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
} }
@@ -840,7 +872,7 @@ static int multiplexUnlock(sqlite3_file *pConn, int lock){
static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){ static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut); return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
} }
@@ -867,28 +899,20 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
break; break;
case MULTIPLEX_CTRL_SET_CHUNK_SIZE: case MULTIPLEX_CTRL_SET_CHUNK_SIZE:
if( pArg ) { if( pArg ) {
int nChunkSize = *(int *)pArg; unsigned int szChunk = *(unsigned*)pArg;
if( nChunkSize<1 ){ if( szChunk<1 ){
rc = SQLITE_MISUSE; rc = SQLITE_MISUSE;
}else{ }else{
/* Round up to nearest multiple of MAX_PAGE_SIZE. */ /* Round up to nearest multiple of MAX_PAGE_SIZE. */
nChunkSize = (nChunkSize + (MAX_PAGE_SIZE-1)); szChunk = (szChunk + (MAX_PAGE_SIZE-1));
nChunkSize &= ~(MAX_PAGE_SIZE-1); szChunk &= ~(MAX_PAGE_SIZE-1);
pGroup->nChunkSize = nChunkSize; pGroup->szChunk = szChunk;
rc = SQLITE_OK; rc = SQLITE_OK;
} }
} }
break; break;
case MULTIPLEX_CTRL_SET_MAX_CHUNKS: case MULTIPLEX_CTRL_SET_MAX_CHUNKS:
if( pArg ) { rc = SQLITE_OK;
int nMaxChunks = *(int *)pArg;
if(( nMaxChunks<1 ) || ( nMaxChunks>SQLITE_MULTIPLEX_MAX_CHUNKS )){
rc = SQLITE_MISUSE;
}else{
pGroup->nMaxChunks = nMaxChunks;
rc = SQLITE_OK;
}
}
break; break;
case SQLITE_FCNTL_SIZE_HINT: case SQLITE_FCNTL_SIZE_HINT:
case SQLITE_FCNTL_CHUNK_SIZE: case SQLITE_FCNTL_CHUNK_SIZE:
@@ -896,7 +920,7 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
rc = SQLITE_OK; rc = SQLITE_OK;
break; break;
default: default:
pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg); rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
} }
@@ -910,7 +934,7 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
static int multiplexSectorSize(sqlite3_file *pConn){ static int multiplexSectorSize(sqlite3_file *pConn){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
return pSubOpen->pMethods->xSectorSize(pSubOpen); return pSubOpen->pMethods->xSectorSize(pSubOpen);
} }
@@ -922,7 +946,7 @@ static int multiplexSectorSize(sqlite3_file *pConn){
static int multiplexDeviceCharacteristics(sqlite3_file *pConn){ static int multiplexDeviceCharacteristics(sqlite3_file *pConn){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen); return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
} }
@@ -940,9 +964,9 @@ static int multiplexShmMap(
){ ){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend, pp); return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp);
} }
return SQLITE_IOERR; return SQLITE_IOERR;
} }
@@ -957,7 +981,7 @@ static int multiplexShmLock(
){ ){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags); return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
} }
@@ -969,7 +993,7 @@ static int multiplexShmLock(
static void multiplexShmBarrier(sqlite3_file *pConn){ static void multiplexShmBarrier(sqlite3_file *pConn){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
pSubOpen->pMethods->xShmBarrier(pSubOpen); pSubOpen->pMethods->xShmBarrier(pSubOpen);
} }
@@ -980,7 +1004,7 @@ static void multiplexShmBarrier(sqlite3_file *pConn){
static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){ static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
multiplexConn *p = (multiplexConn*)pConn; multiplexConn *p = (multiplexConn*)pConn;
int rc; int rc;
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){ if( pSubOpen ){
return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag); return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
} }
@@ -1010,11 +1034,6 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
if( !gMultiplex.pMutex ){ if( !gMultiplex.pMutex ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
gMultiplex.zName = sqlite3_malloc(pOrigVfs->mxPathname);
if( !gMultiplex.zName ){
sqlite3_mutex_free(gMultiplex.pMutex);
return SQLITE_NOMEM;
}
gMultiplex.pGroups = NULL; gMultiplex.pGroups = NULL;
gMultiplex.isInitialized = 1; gMultiplex.isInitialized = 1;
gMultiplex.pOrigVfs = pOrigVfs; gMultiplex.pOrigVfs = pOrigVfs;
@@ -1047,7 +1066,8 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
gMultiplex.sIoMethodsV1.xCheckReservedLock = multiplexCheckReservedLock; gMultiplex.sIoMethodsV1.xCheckReservedLock = multiplexCheckReservedLock;
gMultiplex.sIoMethodsV1.xFileControl = multiplexFileControl; gMultiplex.sIoMethodsV1.xFileControl = multiplexFileControl;
gMultiplex.sIoMethodsV1.xSectorSize = multiplexSectorSize; gMultiplex.sIoMethodsV1.xSectorSize = multiplexSectorSize;
gMultiplex.sIoMethodsV1.xDeviceCharacteristics = multiplexDeviceCharacteristics; gMultiplex.sIoMethodsV1.xDeviceCharacteristics =
multiplexDeviceCharacteristics;
gMultiplex.sIoMethodsV2 = gMultiplex.sIoMethodsV1; gMultiplex.sIoMethodsV2 = gMultiplex.sIoMethodsV1;
gMultiplex.sIoMethodsV2.iVersion = 2; gMultiplex.sIoMethodsV2.iVersion = 2;
gMultiplex.sIoMethodsV2.xShmMap = multiplexShmMap; gMultiplex.sIoMethodsV2.xShmMap = multiplexShmMap;
@@ -1074,7 +1094,6 @@ int sqlite3_multiplex_shutdown(void){
if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE; if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE;
if( gMultiplex.pGroups ) return SQLITE_MISUSE; if( gMultiplex.pGroups ) return SQLITE_MISUSE;
gMultiplex.isInitialized = 0; gMultiplex.isInitialized = 0;
sqlite3_free(gMultiplex.zName);
sqlite3_mutex_free(gMultiplex.pMutex); sqlite3_mutex_free(gMultiplex.pMutex);
sqlite3_vfs_unregister(&gMultiplex.sThisVfs); sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
memset(&gMultiplex, 0, sizeof(gMultiplex)); memset(&gMultiplex, 0, sizeof(gMultiplex));
@@ -1176,16 +1195,16 @@ static int test_multiplex_dump(
Tcl_NewIntObj(pGroup->flags)); Tcl_NewIntObj(pGroup->flags));
/* count number of chunks with open handles */ /* count number of chunks with open handles */
for(i=0; i<pGroup->nMaxChunks; i++){ for(i=0; i<pGroup->nReal; i++){
if( pGroup->bOpen[i] ) nChunks++; if( pGroup->aReal[i].p!=0 ) nChunks++;
} }
Tcl_ListObjAppendElement(interp, pGroupTerm, Tcl_ListObjAppendElement(interp, pGroupTerm,
Tcl_NewIntObj(nChunks)); Tcl_NewIntObj(nChunks));
Tcl_ListObjAppendElement(interp, pGroupTerm, Tcl_ListObjAppendElement(interp, pGroupTerm,
Tcl_NewIntObj(pGroup->nChunkSize)); Tcl_NewIntObj(pGroup->szChunk));
Tcl_ListObjAppendElement(interp, pGroupTerm, Tcl_ListObjAppendElement(interp, pGroupTerm,
Tcl_NewIntObj(pGroup->nMaxChunks)); Tcl_NewIntObj(pGroup->nReal));
Tcl_ListObjAppendElement(interp, pResult, pGroupTerm); Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
} }

View File

@@ -117,15 +117,28 @@ void sqlite3BeginTrigger(
goto trigger_cleanup; goto trigger_cleanup;
} }
} }
if( !pTableName || db->mallocFailed ){
goto trigger_cleanup;
}
/* A long-standing parser bug is that this syntax was allowed:
**
** CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab ....
** ^^^^^^^^
**
** To maintain backwards compatibility, ignore the database
** name on pTableName if we are reparsing our of SQLITE_MASTER.
*/
if( db->init.busy && iDb!=1 ){
sqlite3DbFree(db, pTableName->a[0].zDatabase);
pTableName->a[0].zDatabase = 0;
}
/* If the trigger name was unqualified, and the table is a temp table, /* If the trigger name was unqualified, and the table is a temp table,
** then set iDb to 1 to create the trigger in the temporary database. ** then set iDb to 1 to create the trigger in the temporary database.
** If sqlite3SrcListLookup() returns 0, indicating the table does not ** If sqlite3SrcListLookup() returns 0, indicating the table does not
** exist, the error is caught by the block below. ** exist, the error is caught by the block below.
*/ */
if( !pTableName || db->mallocFailed ){
goto trigger_cleanup;
}
pTab = sqlite3SrcListLookup(pParse, pTableName); pTab = sqlite3SrcListLookup(pParse, pTableName);
if( db->init.busy==0 && pName2->n==0 && pTab if( db->init.busy==0 && pName2->n==0 && pTab
&& pTab->pSchema==db->aDb[1].pSchema ){ && pTab->pSchema==db->aDb[1].pSchema ){

View File

@@ -311,7 +311,9 @@ void sqlite3Update(
/* Begin the database scan /* Begin the database scan
*/ */
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid); sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0, WHERE_ONEPASS_DESIRED); pWInfo = sqlite3WhereBegin(
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED
);
if( pWInfo==0 ) goto update_cleanup; if( pWInfo==0 ) goto update_cleanup;
okOnePass = pWInfo->okOnePass; okOnePass = pWInfo->okOnePass;

View File

@@ -1149,12 +1149,15 @@ int sqlite3AbsInt32(int x){
#ifdef SQLITE_ENABLE_8_3_NAMES #ifdef SQLITE_ENABLE_8_3_NAMES
/* /*
** If SQLITE_ENABLE_8_3_NAME is set at compile-time and if the database ** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database
** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and ** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and
** if filename in z[] has a suffix (a.k.a. "extension") that is longer than ** if filename in z[] has a suffix (a.k.a. "extension") that is longer than
** three characters, then shorten the suffix on z[] to be the last three ** three characters, then shorten the suffix on z[] to be the last three
** characters of the original suffix. ** characters of the original suffix.
** **
** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always
** do the suffix shortening regardless of URI parameter.
**
** Examples: ** Examples:
** **
** test.db-journal => test.nal ** test.db-journal => test.nal
@@ -1162,9 +1165,12 @@ int sqlite3AbsInt32(int x){
** test.db-shm => test.shm ** test.db-shm => test.shm
*/ */
void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
#if SQLITE_ENABLE_8_3_NAMES<2
const char *zOk; const char *zOk;
zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names"); zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names");
if( zOk && sqlite3GetBoolean(zOk) ){ if( zOk && sqlite3GetBoolean(zOk) )
#endif
{
int i, sz; int i, sz;
sz = sqlite3Strlen30(z); sz = sqlite3Strlen30(z);
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}

View File

@@ -3182,7 +3182,7 @@ case OP_OpenEphemeral: {
if( pOp->p4.pKeyInfo ){ if( pOp->p4.pKeyInfo ){
int pgno; int pgno;
assert( pOp->p4type==P4_KEYINFO ); assert( pOp->p4type==P4_KEYINFO );
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY); rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
assert( pgno==MASTER_ROOT+1 ); assert( pgno==MASTER_ROOT+1 );
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1,

View File

@@ -488,7 +488,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY && cnt++ < SQLITE_MAX_SCHEMA_RETRY
&& (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){ && (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){
sqlite3_reset(pStmt); sqlite3_reset(pStmt);
v->expired = 0; assert( v->expired==0 );
} }
if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){ if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
/* This case occurs after failing to recompile an sql statement. /* This case occurs after failing to recompile an sql statement.

View File

@@ -1506,6 +1506,7 @@ void sqlite3VdbeMakeReady(
memset(zCsr, 0, zEnd-zCsr); memset(zCsr, 0, zEnd-zCsr);
zCsr += (zCsr - (u8*)0)&7; zCsr += (zCsr - (u8*)0)&7;
assert( EIGHT_BYTE_ALIGNMENT(zCsr) ); assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
p->expired = 0;
/* Memory for registers, parameters, cursor, etc, is allocated in two /* Memory for registers, parameters, cursor, etc, is allocated in two
** passes. On the first pass, we try to reuse unused space at the ** passes. On the first pass, we try to reuse unused space at the

View File

@@ -253,6 +253,7 @@ struct WhereCost {
#define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */ #define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */
#define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */ #define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */
#define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */ #define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */
#define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */
/* /*
** Initialize a preallocated WhereClause structure. ** Initialize a preallocated WhereClause structure.
@@ -1397,6 +1398,162 @@ static int referencesOtherTables(
return 0; return 0;
} }
/*
** This function searches the expression list passed as the second argument
** for an expression of type TK_COLUMN that refers to the same column and
** uses the same collation sequence as the iCol'th column of index pIdx.
** Argument iBase is the cursor number used for the table that pIdx refers
** to.
**
** If such an expression is found, its index in pList->a[] is returned. If
** no expression is found, -1 is returned.
*/
static int findIndexCol(
Parse *pParse, /* Parse context */
ExprList *pList, /* Expression list to search */
int iBase, /* Cursor for table associated with pIdx */
Index *pIdx, /* Index to match column of */
int iCol /* Column of index to match */
){
int i;
const char *zColl = pIdx->azColl[iCol];
for(i=0; i<pList->nExpr; i++){
Expr *p = pList->a[i].pExpr;
if( p->op==TK_COLUMN
&& p->iColumn==pIdx->aiColumn[iCol]
&& p->iTable==iBase
){
CollSeq *pColl = sqlite3ExprCollSeq(pParse, p);
if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){
return i;
}
}
}
return -1;
}
/*
** This routine determines if pIdx can be used to assist in processing a
** DISTINCT qualifier. In other words, it tests whether or not using this
** index for the outer loop guarantees that rows with equal values for
** all expressions in the pDistinct list are delivered grouped together.
**
** For example, the query
**
** SELECT DISTINCT a, b, c FROM tbl WHERE a = ?
**
** can benefit from any index on columns "b" and "c".
*/
static int isDistinctIndex(
Parse *pParse, /* Parsing context */
WhereClause *pWC, /* The WHERE clause */
Index *pIdx, /* The index being considered */
int base, /* Cursor number for the table pIdx is on */
ExprList *pDistinct, /* The DISTINCT expressions */
int nEqCol /* Number of index columns with == */
){
Bitmask mask = 0; /* Mask of unaccounted for pDistinct exprs */
int i; /* Iterator variable */
if( pIdx->zName==0 || pDistinct==0 || pDistinct->nExpr>=BMS ) return 0;
testcase( pDistinct->nExpr==BMS-1 );
/* Loop through all the expressions in the distinct list. If any of them
** are not simple column references, return early. Otherwise, test if the
** WHERE clause contains a "col=X" clause. If it does, the expression
** can be ignored. If it does not, and the column does not belong to the
** same table as index pIdx, return early. Finally, if there is no
** matching "col=X" expression and the column is on the same table as pIdx,
** set the corresponding bit in variable mask.
*/
for(i=0; i<pDistinct->nExpr; i++){
WhereTerm *pTerm;
Expr *p = pDistinct->a[i].pExpr;
if( p->op!=TK_COLUMN ) return 0;
pTerm = findTerm(pWC, p->iTable, p->iColumn, ~(Bitmask)0, WO_EQ, 0);
if( pTerm ){
Expr *pX = pTerm->pExpr;
CollSeq *p1 = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
CollSeq *p2 = sqlite3ExprCollSeq(pParse, p);
if( p1==p2 ) continue;
}
if( p->iTable!=base ) return 0;
mask |= (((Bitmask)1) << i);
}
for(i=nEqCol; mask && i<pIdx->nColumn; i++){
int iExpr = findIndexCol(pParse, pDistinct, base, pIdx, i);
if( iExpr<0 ) break;
mask &= ~(((Bitmask)1) << iExpr);
}
return (mask==0);
}
/*
** Return true if the DISTINCT expression-list passed as the third argument
** is redundant. A DISTINCT list is redundant if the database contains a
** UNIQUE index that guarantees that the result of the query will be distinct
** anyway.
*/
static int isDistinctRedundant(
Parse *pParse,
SrcList *pTabList,
WhereClause *pWC,
ExprList *pDistinct
){
Table *pTab;
Index *pIdx;
int i;
int iBase;
/* If there is more than one table or sub-select in the FROM clause of
** this query, then it will not be possible to show that the DISTINCT
** clause is redundant. */
if( pTabList->nSrc!=1 ) return 0;
iBase = pTabList->a[0].iCursor;
pTab = pTabList->a[0].pTab;
/* If any of the expressions is an IPK column on table iBase, then return
** true. Note: The (p->iTable==iBase) part of this test may be false if the
** current SELECT is a correlated sub-query.
*/
for(i=0; i<pDistinct->nExpr; i++){
Expr *p = pDistinct->a[i].pExpr;
if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
}
/* Loop through all indices on the table, checking each to see if it makes
** the DISTINCT qualifier redundant. It does so if:
**
** 1. The index is itself UNIQUE, and
**
** 2. All of the columns in the index are either part of the pDistinct
** list, or else the WHERE clause contains a term of the form "col=X",
** where X is a constant value. The collation sequences of the
** comparison and select-list expressions must match those of the index.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->onError==OE_None ) continue;
for(i=0; i<pIdx->nColumn; i++){
int iCol = pIdx->aiColumn[i];
if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx)
&& 0>findIndexCol(pParse, pDistinct, iBase, pIdx, i)
){
break;
}
}
if( i==pIdx->nColumn ){
/* This index implies that the DISTINCT qualifier is redundant. */
return 1;
}
}
return 0;
}
/* /*
** This routine decides if pIdx can be used to satisfy the ORDER BY ** This routine decides if pIdx can be used to satisfy the ORDER BY
@@ -1433,7 +1590,10 @@ static int isSortingIndex(
struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
assert( pOrderBy!=0 ); if( !pOrderBy ) return 0;
if( wsFlags & WHERE_COLUMN_IN ) return 0;
if( pIdx->bUnordered ) return 0;
nTerm = pOrderBy->nExpr; nTerm = pOrderBy->nExpr;
assert( nTerm>0 ); assert( nTerm>0 );
@@ -1746,6 +1906,10 @@ static void bestAutomaticIndex(
WhereTerm *pWCEnd; /* End of pWC->a[] */ WhereTerm *pWCEnd; /* End of pWC->a[] */
Table *pTable; /* Table tht might be indexed */ Table *pTable; /* Table tht might be indexed */
if( pParse->nQueryLoop<=(double)1 ){
/* There is no point in building an automatic index for a single scan */
return;
}
if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){ if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){
/* Automatic indices are disabled at run-time */ /* Automatic indices are disabled at run-time */
return; return;
@@ -1758,6 +1922,10 @@ static void bestAutomaticIndex(
/* The NOT INDEXED clause appears in the SQL. */ /* The NOT INDEXED clause appears in the SQL. */
return; return;
} }
if( pSrc->isCorrelated ){
/* The source is a correlated sub-query. No point in indexing it. */
return;
}
assert( pParse->nQueryLoop >= (double)1 ); assert( pParse->nQueryLoop >= (double)1 );
pTable = pSrc->pTab; pTable = pSrc->pTab;
@@ -2689,6 +2857,7 @@ static void bestBtreeIndex(
Bitmask notReady, /* Mask of cursors not available for indexing */ Bitmask notReady, /* Mask of cursors not available for indexing */
Bitmask notValid, /* Cursors not available for any purpose */ Bitmask notValid, /* Cursors not available for any purpose */
ExprList *pOrderBy, /* The ORDER BY clause */ ExprList *pOrderBy, /* The ORDER BY clause */
ExprList *pDistinct, /* The select-list if query is DISTINCT */
WhereCost *pCost /* Lowest cost query plan */ WhereCost *pCost /* Lowest cost query plan */
){ ){
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
@@ -2829,7 +2998,8 @@ static void bestBtreeIndex(
int nInMul = 1; /* Number of distinct equalities to lookup */ int nInMul = 1; /* Number of distinct equalities to lookup */
int estBound = 100; /* Estimated reduction in search space */ int estBound = 100; /* Estimated reduction in search space */
int nBound = 0; /* Number of range constraints seen */ int nBound = 0; /* Number of range constraints seen */
int bSort = 0; /* True if external sort required */ int bSort = !!pOrderBy; /* True if external sort required */
int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */
int bLookup = 0; /* True if not a covering index */ int bLookup = 0; /* True if not a covering index */
WhereTerm *pTerm; /* A single term of the WHERE clause */ WhereTerm *pTerm; /* A single term of the WHERE clause */
#ifdef SQLITE_ENABLE_STAT2 #ifdef SQLITE_ENABLE_STAT2
@@ -2893,17 +3063,20 @@ static void bestBtreeIndex(
** naturally scan rows in the required order, set the appropriate flags ** naturally scan rows in the required order, set the appropriate flags
** in wsFlags. Otherwise, if there is an ORDER BY clause but the index ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index
** will scan rows in a different order, set the bSort variable. */ ** will scan rows in a different order, set the bSort variable. */
if( pOrderBy ){ if( isSortingIndex(
if( (wsFlags & WHERE_COLUMN_IN)==0 pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, nEq, wsFlags, &rev)
&& pProbe->bUnordered==0 ){
&& isSortingIndex(pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, bSort = 0;
nEq, wsFlags, &rev) wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY;
){ wsFlags |= (rev ? WHERE_REVERSE : 0);
wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; }
wsFlags |= (rev ? WHERE_REVERSE : 0);
}else{ /* If there is a DISTINCT qualifier and this index will scan rows in
bSort = 1; ** order of the DISTINCT expressions, clear bDist and set the appropriate
} ** flags in wsFlags. */
if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq) ){
bDist = 0;
wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT;
} }
/* If currently calculating the cost of using an index (not the IPK /* If currently calculating the cost of using an index (not the IPK
@@ -2938,12 +3111,13 @@ static void bestBtreeIndex(
} }
#ifdef SQLITE_ENABLE_STAT2 #ifdef SQLITE_ENABLE_STAT2
/* If the constraint is of the form x=VALUE and histogram /* If the constraint is of the form x=VALUE or x IN (E1,E2,...)
** and we do not think that values of x are unique and if histogram
** data is available for column x, then it might be possible ** data is available for column x, then it might be possible
** to get a better estimate on the number of rows based on ** to get a better estimate on the number of rows based on
** VALUE and how common that value is according to the histogram. ** VALUE and how common that value is according to the histogram.
*/ */
if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 ){ if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 && aiRowEst[1]>1 ){
if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){ if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
testcase( pFirstTerm->eOperator==WO_EQ ); testcase( pFirstTerm->eOperator==WO_EQ );
testcase( pFirstTerm->eOperator==WO_ISNULL ); testcase( pFirstTerm->eOperator==WO_ISNULL );
@@ -3020,6 +3194,9 @@ static void bestBtreeIndex(
if( bSort ){ if( bSort ){
cost += nRow*estLog(nRow)*3; cost += nRow*estLog(nRow)*3;
} }
if( bDist ){
cost += nRow*estLog(nRow)*3;
}
/**** Cost of using this index has now been computed ****/ /**** Cost of using this index has now been computed ****/
@@ -3165,7 +3342,7 @@ static void bestIndex(
}else }else
#endif #endif
{ {
bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, 0, pCost);
} }
} }
@@ -4127,7 +4304,7 @@ static Bitmask codeOneLoopStart(
if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){ if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */ WhereInfo *pSubWInfo; /* Info for single OR-term scan */
/* Loop through table entries that match term pOrTerm. */ /* Loop through table entries that match term pOrTerm. */
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0, pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0, 0,
WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE |
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY); WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY);
if( pSubWInfo ){ if( pSubWInfo ){
@@ -4368,6 +4545,7 @@ WhereInfo *sqlite3WhereBegin(
SrcList *pTabList, /* A list of all tables to be scanned */ SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */ Expr *pWhere, /* The WHERE clause */
ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */ ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */
u16 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */ u16 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */
){ ){
int i; /* Loop counter */ int i; /* Loop counter */
@@ -4428,6 +4606,10 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->savedNQueryLoop = pParse->nQueryLoop; pWInfo->savedNQueryLoop = pParse->nQueryLoop;
pMaskSet = (WhereMaskSet*)&pWC[1]; pMaskSet = (WhereMaskSet*)&pWC[1];
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
if( db->flags & SQLITE_DistinctOpt ) pDistinct = 0;
/* Split the WHERE clause into separate subexpressions where each /* Split the WHERE clause into separate subexpressions where each
** subexpression is separated by an AND operator. ** subexpression is separated by an AND operator.
*/ */
@@ -4495,6 +4677,15 @@ WhereInfo *sqlite3WhereBegin(
goto whereBeginError; goto whereBeginError;
} }
/* Check if the DISTINCT qualifier, if there is one, is redundant.
** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to
** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT.
*/
if( pDistinct && isDistinctRedundant(pParse, pTabList, pWC, pDistinct) ){
pDistinct = 0;
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
/* Chose the best index to use for each table in the FROM clause. /* Chose the best index to use for each table in the FROM clause.
** **
** This loop fills in the following fields: ** This loop fills in the following fields:
@@ -4578,6 +4769,7 @@ WhereInfo *sqlite3WhereBegin(
int doNotReorder; /* True if this table should not be reordered */ int doNotReorder; /* True if this table should not be reordered */
WhereCost sCost; /* Cost information from best[Virtual]Index() */ WhereCost sCost; /* Cost information from best[Virtual]Index() */
ExprList *pOrderBy; /* ORDER BY clause for index to optimize */ ExprList *pOrderBy; /* ORDER BY clause for index to optimize */
ExprList *pDist; /* DISTINCT clause for index to optimize */
doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0; doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
if( j!=iFrom && doNotReorder ) break; if( j!=iFrom && doNotReorder ) break;
@@ -4588,6 +4780,7 @@ WhereInfo *sqlite3WhereBegin(
} }
mask = (isOptimal ? m : notReady); mask = (isOptimal ? m : notReady);
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0); pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
pDist = (i==0 ? pDistinct : 0);
if( pTabItem->pIndex==0 ) nUnconstrained++; if( pTabItem->pIndex==0 ) nUnconstrained++;
WHERETRACE(("=== trying table %d with isOptimal=%d ===\n", WHERETRACE(("=== trying table %d with isOptimal=%d ===\n",
@@ -4602,7 +4795,7 @@ WhereInfo *sqlite3WhereBegin(
#endif #endif
{ {
bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy, bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
&sCost); pDist, &sCost);
} }
assert( isOptimal || (sCost.used&notReady)==0 ); assert( isOptimal || (sCost.used&notReady)==0 );
@@ -4663,6 +4856,10 @@ WhereInfo *sqlite3WhereBegin(
if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){ if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){
*ppOrderBy = 0; *ppOrderBy = 0;
} }
if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){
assert( pWInfo->eDistinct==0 );
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
andFlags &= bestPlan.plan.wsFlags; andFlags &= bestPlan.plan.wsFlags;
pLevel->plan = bestPlan.plan; pLevel->plan = bestPlan.plan;
testcase( bestPlan.plan.wsFlags & WHERE_INDEXED ); testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );

View File

@@ -38,6 +38,7 @@ run_test_suite pcache10
run_test_suite pcache50 run_test_suite pcache50
run_test_suite pcache90 run_test_suite pcache90
run_test_suite pcache100 run_test_suite pcache100
run_test_suite prepare
if {$::tcl_platform(platform)=="unix"} { if {$::tcl_platform(platform)=="unix"} {
ifcapable !default_autovacuum { ifcapable !default_autovacuum {

View File

@@ -137,6 +137,7 @@ do_test alter2-1.8 {
do_test alter2-1.9 { do_test alter2-1.9 {
# ALTER TABLE abc ADD COLUMN d; # ALTER TABLE abc ADD COLUMN d;
alter_table abc {CREATE TABLE abc(a, b, c, d);} alter_table abc {CREATE TABLE abc(a, b, c, d);}
if {[permutation] == "prepare"} { db cache flush }
execsql { SELECT * FROM abc; } execsql { SELECT * FROM abc; }
execsql { execsql {
UPDATE abc SET d = 11 WHERE c IS NULL AND a<4; UPDATE abc SET d = 11 WHERE c IS NULL AND a<4;

View File

@@ -248,4 +248,14 @@ do_execsql_test autoindex1-600 {
0 1 1 {SEARCH SUBQUERY 1 AS y USING AUTOMATIC COVERING INDEX (sheep_no=?) (~8 rows)} 0 1 1 {SEARCH SUBQUERY 1 AS y USING AUTOMATIC COVERING INDEX (sheep_no=?) (~8 rows)}
} }
do_execsql_test autoindex1-700 {
CREATE TABLE t5(a, b, c);
EXPLAIN QUERY PLAN SELECT a FROM t5 WHERE b=10 ORDER BY c;
} {
0 0 0 {SCAN TABLE t5 (~100000 rows)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
finish_test finish_test

View File

@@ -57,17 +57,17 @@ do_test collate5-1.1 {
execsql { execsql {
SELECT DISTINCT a FROM collate5t1; SELECT DISTINCT a FROM collate5t1;
} }
} {A B N} } {a b n}
do_test collate5-1.2 { do_test collate5-1.2 {
execsql { execsql {
SELECT DISTINCT b FROM collate5t1; SELECT DISTINCT b FROM collate5t1;
} }
} {{} Apple apple banana} } {apple Apple banana {}}
do_test collate5-1.3 { do_test collate5-1.3 {
execsql { execsql {
SELECT DISTINCT a, b FROM collate5t1; SELECT DISTINCT a, b FROM collate5t1;
} }
} {A Apple a apple B banana N {}} } {a apple A Apple b banana n {}}
# Ticket #3376 # Ticket #3376
# #

166
test/distinct.test Normal file
View File

@@ -0,0 +1,166 @@
# 2011 July 1
#
# 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 the DISTINCT modifier.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix distinct
proc is_distinct_noop {sql} {
set sql1 $sql
set sql2 [string map {DISTINCT ""} $sql]
set program1 [list]
set program2 [list]
db eval "EXPLAIN $sql1" {
if {$opcode != "Noop"} { lappend program1 $opcode }
}
db eval "EXPLAIN $sql2" {
if {$opcode != "Noop"} { lappend program2 $opcode }
}
return [expr {$program1==$program2}]
}
proc do_distinct_noop_test {tn sql} {
uplevel [list do_test $tn [list is_distinct_noop $sql] 1]
}
proc do_distinct_not_noop_test {tn sql} {
uplevel [list do_test $tn [list is_distinct_noop $sql] 0]
}
proc do_temptables_test {tn sql temptables} {
uplevel [list do_test $tn [subst -novar {
set ret ""
db eval "EXPLAIN [set sql]" {
if {$opcode == "OpenEphemeral"} {
if {$p5 != "10" && $p5!="00"} { error "p5 = $p5" }
if {$p5 == "10"} {
lappend ret hash
} else {
lappend ret btree
}
}
}
set ret
}] $temptables]
}
#-------------------------------------------------------------------------
# The following tests - distinct-1.* - check that the planner correctly
# detects cases where a UNIQUE index means that a DISTINCT clause is
# redundant. Currently the planner only detects such cases when there
# is a single table in the FROM clause.
#
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, c, d);
CREATE UNIQUE INDEX i1 ON t1(b, c);
CREATE UNIQUE INDEX i2 ON t1(d COLLATE nocase);
CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
CREATE TABLE t3(c1 PRIMARY KEY, c2);
CREATE INDEX i3 ON t3(c2);
}
foreach {tn noop sql} {
1 1 "SELECT DISTINCT b, c FROM t1"
2 1 "SELECT DISTINCT c FROM t1 WHERE b = ?"
3 1 "SELECT DISTINCT rowid FROM t1"
4 1 "SELECT DISTINCT rowid, a FROM t1"
5 1 "SELECT DISTINCT x FROM t2"
6 1 "SELECT DISTINCT * FROM t2"
7 1 "SELECT DISTINCT * FROM (SELECT * FROM t2)"
8 1 "SELECT DISTINCT * FROM t1"
8 0 "SELECT DISTINCT a, b FROM t1"
9 0 "SELECT DISTINCT c FROM t1 WHERE b IN (1,2)"
10 0 "SELECT DISTINCT c FROM t1"
11 0 "SELECT DISTINCT b FROM t1"
12 0 "SELECT DISTINCT a, d FROM t1"
13 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t1"
14 1 "SELECT DISTINCT a, d COLLATE nocase FROM t1"
15 0 "SELECT DISTINCT a, d COLLATE binary FROM t1"
16 1 "SELECT DISTINCT a, b, c COLLATE binary FROM t1"
16 0 "SELECT DISTINCT t1.rowid FROM t1, t2"
17 0 { /* Technically, it would be possible to detect that DISTINCT
** is a no-op in cases like the following. But SQLite does not
** do so. */
SELECT DISTINCT t1.rowid FROM t1, t2 WHERE t1.rowid=t2.rowid }
18 1 "SELECT DISTINCT c1, c2 FROM t3"
19 1 "SELECT DISTINCT c1 FROM t3"
20 1 "SELECT DISTINCT * FROM t3"
21 0 "SELECT DISTINCT c2 FROM t3"
22 0 "SELECT DISTINCT * FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
23 1 "SELECT DISTINCT rowid FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
24 0 "SELECT DISTINCT rowid/2 FROM t1"
25 1 "SELECT DISTINCT rowid/2, rowid FROM t1"
26 1 "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?"
} {
if {$noop} {
do_distinct_noop_test 1.$tn $sql
} else {
do_distinct_not_noop_test 1.$tn $sql
}
}
#-------------------------------------------------------------------------
# The following tests - distinct-2.* - test cases where an index is
# used to deliver results in order of the DISTINCT expressions.
#
drop_all_tables
do_execsql_test 2.0 {
CREATE TABLE t1(a, b, c);
CREATE INDEX i1 ON t1(a, b);
CREATE INDEX i2 ON t1(b COLLATE nocase, c COLLATE nocase);
INSERT INTO t1 VALUES('a', 'b', 'c');
INSERT INTO t1 VALUES('A', 'B', 'C');
INSERT INTO t1 VALUES('a', 'b', 'c');
INSERT INTO t1 VALUES('A', 'B', 'C');
}
foreach {tn sql temptables res} {
1 "a, b FROM t1" {} {A B a b}
2 "b, a FROM t1" {} {B A b a}
3 "a, b, c FROM t1" {hash} {a b c A B C}
4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
5 "b FROM t1 WHERE a = 'a'" {} {b}
6 "b FROM t1" {hash} {b B}
7 "a FROM t1" {} {A a}
8 "b COLLATE nocase FROM t1" {} {b}
9 "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {} {B}
} {
do_execsql_test 2.$tn.1 "SELECT DISTINCT $sql" $res
do_temptables_test 2.$tn.2 "SELECT DISTINCT $sql" $temptables
}
do_execsql_test 2.A {
SELECT (SELECT DISTINCT o.a FROM t1 AS i) FROM t1 AS o;
} {a A a A}
finish_test

View File

@@ -1238,8 +1238,8 @@ do_select_tests e_select-5 {
3.1 "SELECT x FROM h2" {One Two Three Four one two three four} 3.1 "SELECT x FROM h2" {One Two Three Four one two three four}
3.2 "SELECT x FROM h1, h2 ON (x=b)" {One one Four four} 3.2 "SELECT x FROM h1, h2 ON (x=b)" {One one Four four}
4.1 "SELECT DISTINCT x FROM h2" {four one three two} 4.1 "SELECT DISTINCT x FROM h2" {One Two Three Four}
4.2 "SELECT DISTINCT x FROM h1, h2 ON (x=b)" {four one} 4.2 "SELECT DISTINCT x FROM h1, h2 ON (x=b)" {One Four}
} }
# EVIDENCE-OF: R-02054-15343 For the purposes of detecting duplicate # EVIDENCE-OF: R-02054-15343 For the purposes of detecting duplicate
@@ -1253,11 +1253,11 @@ do_select_tests e_select-5.5 {
# sequence to compare text values with apply. # sequence to compare text values with apply.
# #
do_select_tests e_select-5.6 { do_select_tests e_select-5.6 {
1 "SELECT DISTINCT b FROM h1" {I IV four i iv one} 1 "SELECT DISTINCT b FROM h1" {one I i four IV iv}
2 "SELECT DISTINCT b COLLATE nocase FROM h1" {four i iv one} 2 "SELECT DISTINCT b COLLATE nocase FROM h1" {one I four IV}
3 "SELECT DISTINCT x FROM h2" {four one three two} 3 "SELECT DISTINCT x FROM h2" {One Two Three Four}
4 "SELECT DISTINCT x COLLATE binary FROM h2" { 4 "SELECT DISTINCT x COLLATE binary FROM h2" {
Four One Three Two four one three two One Two Three Four one two three four
} }
} }

View File

@@ -159,7 +159,7 @@ foreach jm {rollback wal} {
sql1 { DROP INDEX IF EXISTS i2 } sql1 { DROP INDEX IF EXISTS i2 }
sql2 { CREATE INDEX aux.i2 ON t2(x) } sql2 { CREATE INDEX aux.i2 ON t2(x) }
sql1 { DROP INDEX IF EXISTS i2 } sql1 { DROP INDEX IF EXISTS i2 }
sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' } sql2 { SELECT * FROM aux.sqlite_master WHERE type = 'index' }
} {} } {}
# VIEW objects. # VIEW objects.

View File

@@ -107,15 +107,17 @@ proc do_fts3query_test {tn args} {
" $matchinfo_asc " $matchinfo_asc
} }
# fts3_make_deferrable TABLE TOKEN # fts3_make_deferrable TABLE TOKEN ?NROW?
# #
proc fts3_make_deferrable {tbl token} { proc fts3_make_deferrable {tbl token {nRow 0}} {
set stmt [sqlite3_prepare db "SELECT * FROM $tbl" -1 dummy] set stmt [sqlite3_prepare db "SELECT * FROM $tbl" -1 dummy]
set name [sqlite3_column_name $stmt 0] set name [sqlite3_column_name $stmt 0]
sqlite3_finalize $stmt sqlite3_finalize $stmt
set nRow [db one "SELECT count(*) FROM $tbl"] if {$nRow==0} {
set nRow [db one "SELECT count(*) FROM $tbl"]
}
set pgsz [db one "PRAGMA page_size"] set pgsz [db one "PRAGMA page_size"]
execsql BEGIN execsql BEGIN
for {set i 0} {$i < ($nRow * $pgsz * 1.2)/100} {incr i} { for {set i 0} {$i < ($nRow * $pgsz * 1.2)/100} {incr i} {
@@ -653,6 +655,50 @@ foreach {tn pending create} {
catchsql { COMMIT } catchsql { COMMIT }
} }
foreach {tn create} {
1 "fts4(x)"
2 "fts4(x, order=DESC)"
} {
execsql [subst {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING $create;
}]
foreach {x} {
"F E N O T K X V A X I E X A P G Q V H U"
"R V A E T C V Q N I E L O N U G J K L U"
"U Y I G W M V F J L X I D C H F P J Q B"
"S G D Z X R P G S S Y B K A S G A I L L"
"L S I C H T Z S R Q P R N K J X L F M J"
"C C C D P X B Z C M A D A C X S B T X V"
"W Y J M D R G V R K B X S A W R I T N C"
"P K L W T M S P O Y Y V V O E H Q A I R"
"C D Y I C Z F H J C O Y A Q F L S B D K"
"P G S C Y C Y V I M B D S Z D D Y W I E"
"Z K Z U E E S F Y X T U A L W O U J C Q"
"P A T Z S W L P L Q V Y Y I P W U X S S"
"I U I H U O F Z F R H R F T N D X A G M"
"N A B M S H K X S O Y D T X S B R Y H Z"
"L U D A S K I L S V Z J P U B E B Y H M"
} {
execsql { INSERT INTO t1 VALUES($x) }
}
# Add extra documents to the database such that token "B" will be considered
# deferrable if considering the other tokens means that 2 or fewer documents
# will be loaded into memory.
#
fts3_make_deferrable t1 B 2
# B is not deferred in either of the first two tests below, since filtering
# on "M" or "D" returns 10 documents or so. But filtering on "M * D" only
# returns 2, so B is deferred in this case.
#
do_fts3query_test 7.$tn.1 t1 {"M B"}
do_fts3query_test 7.$tn.2 t1 {"B D"}
do_fts3query_test 7.$tn.3 -deferred B t1 {"M B D"}
}
set sqlite_fts3_enable_parentheses $sfep set sqlite_fts3_enable_parentheses $sfep
finish_test finish_test

View File

@@ -17,24 +17,26 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
do_test func3-1.1 { ifcapable utf16 {
set destroyed 0 do_test func3-1.1 {
proc destroy {} { set ::destroyed 1 } set destroyed 0
sqlite3_create_function_v2 db f2 -1 any -func f2 -destroy destroy proc destroy {} { set ::destroyed 1 }
set destroyed sqlite3_create_function_v2 db f2 -1 any -func f2 -destroy destroy
} 0 set destroyed
do_test func3-1.2 { } 0
sqlite3_create_function_v2 db f2 -1 utf8 -func f2 do_test func3-1.2 {
set destroyed sqlite3_create_function_v2 db f2 -1 utf8 -func f2
} 0 set destroyed
do_test func3-1.3 { } 0
sqlite3_create_function_v2 db f2 -1 utf16le -func f2 do_test func3-1.3 {
set destroyed sqlite3_create_function_v2 db f2 -1 utf16le -func f2
} 0 set destroyed
do_test func3-1.4 { } 0
sqlite3_create_function_v2 db f2 -1 utf16be -func f2 do_test func3-1.4 {
set destroyed sqlite3_create_function_v2 db f2 -1 utf16be -func f2
} 1 set destroyed
} 1
}
do_test func3-2.1 { do_test func3-2.1 {
set destroyed 0 set destroyed 0

View File

@@ -1376,7 +1376,7 @@ do_test fuzzer1-2.3 {
AND f2.distance<=200 AND f2.distance<=200
AND streetname.n>=f2.word AND streetname.n<=(f2.word || x'F7BFBFBF') AND streetname.n>=f2.word AND streetname.n<=(f2.word || x'F7BFBFBF')
} }
} {steelewood tallia tallu talwyn taymouth thelema trailer {tyler finley}} } {{tyler finley} trailer taymouth steelewood tallia tallu talwyn thelema}
finish_test finish_test

View File

@@ -35,6 +35,7 @@ do_malloc_test 1 -tclprep {
} }
} -tclbody { } -tclbody {
set ::blob [db incrblob blobs v 1] set ::blob [db incrblob blobs v 1]
fconfigure $::blob -translation binary
set rc [catch {puts -nonewline $::blob $::data}] set rc [catch {puts -nonewline $::blob $::data}]
if {$rc} { error "out of memory" } if {$rc} { error "out of memory" }
} }
@@ -71,8 +72,7 @@ do_malloc_test 3 -tclprep {
if {$rc} { if {$rc} {
error "out of memory" error "out of memory"
} }
} }
do_ioerr_test incrblob_err-4 -cksum 1 -sqlprep { do_ioerr_test incrblob_err-4 -cksum 1 -sqlprep {
CREATE TABLE blobs(k, v BLOB); CREATE TABLE blobs(k, v BLOB);
@@ -87,6 +87,7 @@ do_ioerr_test incrblob_err-5 -cksum 1 -sqlprep {
INSERT INTO blobs VALUES(1, zeroblob(length(CAST($::data AS BLOB)))); INSERT INTO blobs VALUES(1, zeroblob(length(CAST($::data AS BLOB))));
} -tclbody { } -tclbody {
set ::blob [db incrblob blobs v 1] set ::blob [db incrblob blobs v 1]
fconfigure $::blob -translation binary
puts -nonewline $::blob $::data puts -nonewline $::blob $::data
close $::blob close $::blob
} }
@@ -96,6 +97,7 @@ do_ioerr_test incrblob_err-6 -cksum 1 -sqlprep {
INSERT INTO blobs VALUES(1, $::data || $::data || $::data); INSERT INTO blobs VALUES(1, $::data || $::data || $::data);
} -tclbody { } -tclbody {
set ::blob [db incrblob blobs v 1] set ::blob [db incrblob blobs v 1]
fconfigure $::blob -translation binary
seek $::blob -20 end seek $::blob -20 end
puts -nonewline $::blob "12345678900987654321" puts -nonewline $::blob "12345678900987654321"
close $::blob close $::blob

View File

@@ -112,7 +112,7 @@ do_test insert4-2.4.1 {
INSERT INTO t3 SELECT DISTINCT * FROM t2; INSERT INTO t3 SELECT DISTINCT * FROM t2;
SELECT * FROM t3; SELECT * FROM t3;
} }
} {1 9 9 1} } {9 1 1 9}
xferopt_test insert4-2.4.2 0 xferopt_test insert4-2.4.2 0
do_test insert4-2.4.3 { do_test insert4-2.4.3 {
catchsql { catchsql {

View File

@@ -70,12 +70,15 @@ do_test like-1.4 {
} }
} {ABC abc} } {ABC abc}
do_test like-1.5.1 { do_test like-1.5.1 {
# Use sqlite3_exec() to verify fix for ticket [25ee81271091] 2011-06-26
sqlite3_exec db {PRAGMA case_sensitive_like=on}
} {0 {}}
do_test like-1.5.2 {
execsql { execsql {
PRAGMA case_sensitive_like=on;
SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1; SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
} }
} {abc} } {abc}
do_test like-1.5.2 { do_test like-1.5.3 {
execsql { execsql {
PRAGMA case_sensitive_like; -- no argument; does not change setting PRAGMA case_sensitive_like; -- no argument; does not change setting
SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1; SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;

View File

@@ -505,7 +505,7 @@ ifcapable subquery {
) )
ORDER BY LOWER(artist) ASC; ORDER BY LOWER(artist) ASC;
} }
} {one} } {two}
} }
# Ticket #1370. Do not overwrite small files (less than 1024 bytes) # Ticket #1370. Do not overwrite small files (less than 1024 bytes)

View File

@@ -49,6 +49,7 @@ proc multiplex_set {db name chunk_size max_chunks} {
# and files with the chunk extension. # and files with the chunk extension.
proc multiplex_delete {name} { proc multiplex_delete {name} {
global g_max_chunks global g_max_chunks
forcedelete $name
for {set i 0} {$i<$g_max_chunks} {incr i} { for {set i 0} {$i<$g_max_chunks} {incr i} {
forcedelete [multiplex_name $name $i] forcedelete [multiplex_name $name $i]
forcedelete [multiplex_name $name-journal $i] forcedelete [multiplex_name $name-journal $i]
@@ -78,10 +79,9 @@ do_test multiplex-1.8 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.9.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK} do_test multiplex-1.9.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.9.2 { sqlite3 db test.db } {} do_test multiplex-1.9.2 { sqlite3 db test.db } {}
do_test multiplex-1.9.3 { multiplex_set db main 32768 16 } {SQLITE_OK} do_test multiplex-1.9.3 { multiplex_set db main 32768 16 } {SQLITE_OK}
do_test multiplex-1.9.4 { multiplex_set db main 32768 -1 } {SQLITE_MISUSE} do_test multiplex-1.9.4 { multiplex_set db main 32768 -1 } {SQLITE_OK}
do_test multiplex-1.9.5 { multiplex_set db main -1 16 } {SQLITE_MISUSE}
do_test multiplex-1.9.6 { multiplex_set db main 31 16 } {SQLITE_OK} do_test multiplex-1.9.6 { multiplex_set db main 31 16 } {SQLITE_OK}
do_test multiplex-1.9.7 { multiplex_set db main 32768 100 } {SQLITE_MISUSE} do_test multiplex-1.9.7 { multiplex_set db main 32768 100 } {SQLITE_OK}
do_test multiplex-1.9.8 { multiplex_set db main 1073741824 1 } {SQLITE_OK} do_test multiplex-1.9.8 { multiplex_set db main 1073741824 1 } {SQLITE_OK}
do_test multiplex-1.9.9 { db close } {} do_test multiplex-1.9.9 { db close } {}
do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown } {SQLITE_OK} do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown } {SQLITE_OK}
@@ -89,10 +89,9 @@ do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.10.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK} do_test multiplex-1.10.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.10.2 { sqlite3 db test.db } {} do_test multiplex-1.10.2 { sqlite3 db test.db } {}
do_test multiplex-1.10.3 { lindex [ catchsql { SELECT multiplex_control(2, 32768); } ] 0 } {0} do_test multiplex-1.10.3 { lindex [ catchsql { SELECT multiplex_control(2, 32768); } ] 0 } {0}
do_test multiplex-1.10.4 { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 } {1} do_test multiplex-1.10.4 { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 } {0}
do_test multiplex-1.10.5 { lindex [ catchsql { SELECT multiplex_control(2, -1); } ] 0 } {1}
do_test multiplex-1.10.6 { lindex [ catchsql { SELECT multiplex_control(2, 31); } ] 0 } {0} do_test multiplex-1.10.6 { lindex [ catchsql { SELECT multiplex_control(2, 31); } ] 0 } {0}
do_test multiplex-1.10.7 { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 } {1} do_test multiplex-1.10.7 { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 } {0}
do_test multiplex-1.10.8 { lindex [ catchsql { SELECT multiplex_control(2, 1073741824); } ] 0 } {0} do_test multiplex-1.10.8 { lindex [ catchsql { SELECT multiplex_control(2, 1073741824); } ] 0 } {0}
do_test multiplex-1.10.9 { db close } {} do_test multiplex-1.10.9 { db close } {}
do_test multiplex-1.10.10 { sqlite3_multiplex_shutdown } {SQLITE_OK} do_test multiplex-1.10.10 { sqlite3_multiplex_shutdown } {SQLITE_OK}
@@ -146,8 +145,9 @@ do_test multiplex-1.13.7 { sqlite3_multiplex_shutdown }
sqlite3_multiplex_initialize "" 1 sqlite3_multiplex_initialize "" 1
multiplex_set db main 32768 16 multiplex_set db main 32768 16
file delete -force test.x
do_test multiplex-2.1.2 { do_test multiplex-2.1.2 {
sqlite3 db test.db sqlite3 db test.x
execsql { execsql {
PRAGMA page_size=1024; PRAGMA page_size=1024;
PRAGMA auto_vacuum=OFF; PRAGMA auto_vacuum=OFF;
@@ -159,7 +159,7 @@ do_test multiplex-2.1.2 {
INSERT INTO t1 VALUES(2, randomblob(1100)); INSERT INTO t1 VALUES(2, randomblob(1100));
} }
} {} } {}
do_test multiplex-2.1.3 { file size [multiplex_name test.db 0] } {4096} do_test multiplex-2.1.3 { file size [multiplex_name test.x 0] } {4096}
do_test multiplex-2.1.4 { do_test multiplex-2.1.4 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {} } {}
@@ -167,10 +167,10 @@ do_test multiplex-2.1.4 {
do_test multiplex-2.2.1 { do_test multiplex-2.2.1 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {} } {}
do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144} do_test multiplex-2.2.3 { file size [multiplex_name test.x 0] } {6144}
do_test multiplex-2.3.1 { do_test multiplex-2.3.1 {
sqlite3 db2 test2.db sqlite3 db2 test2.x
db2 close db2 close
} {} } {}
@@ -181,7 +181,7 @@ do_test multiplex-2.4.1 {
do_test multiplex-2.4.2 { do_test multiplex-2.4.2 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {} } {}
do_test multiplex-2.4.4 { file size [multiplex_name test.db 0] } {7168} do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168}
do_test multiplex-2.4.99 { do_test multiplex-2.4.99 {
db close db close
sqlite3_multiplex_shutdown sqlite3_multiplex_shutdown
@@ -189,9 +189,9 @@ do_test multiplex-2.4.99 {
do_test multiplex-2.5.1 { do_test multiplex-2.5.1 {
multiplex_delete test.db multiplex_delete test.x
sqlite3_multiplex_initialize "" 1 sqlite3_multiplex_initialize "" 1
sqlite3 db test.db sqlite3 db test.x
multiplex_set db main 4096 16 multiplex_set db main 4096 16
} {SQLITE_OK} } {SQLITE_OK}
@@ -236,8 +236,8 @@ do_test multiplex-2.5.8 {
db eval {SELECT a,length(b) FROM t1 WHERE a=4} db eval {SELECT a,length(b) FROM t1 WHERE a=4}
} {4 4000} } {4 4000}
do_test multiplex-2.5.9 { file size [multiplex_name test.db 0] } [list $g_chunk_size] do_test multiplex-2.5.9 { file size [multiplex_name test.x 0] } [list $g_chunk_size]
do_test multiplex-2.5.10 { file size [multiplex_name test.db 1] } [list $g_chunk_size] do_test multiplex-2.5.10 { file size [multiplex_name test.x 1] } [list $g_chunk_size]
do_test multiplex-2.5.99 { do_test multiplex-2.5.99 {
db close db close
@@ -523,50 +523,6 @@ do_faultsim_test multiplex-5.5 -prep {
multiplex_set db main 32768 16 multiplex_set db main 32768 16
} }
# test that mismatch filesize is detected
#
# Do not run this test if $::G(perm:presql) is set. If it is set, then the
# expected IO error will occur within the Tcl [sqlite3] wrapper, not within
# the first SQL statement executed below. This breaks the test case.
#
if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
set all_journal_modes {delete persist truncate memory off}
foreach jmode $all_journal_modes {
do_test multiplex-5.6.1.$jmode {
sqlite3_multiplex_shutdown
multiplex_delete test.db
sqlite3 db test.db
db eval {
PRAGMA page_size = 1024;
PRAGMA auto_vacuum = off;
}
db eval "PRAGMA journal_mode = $jmode;"
} $jmode
do_test multiplex-5.6.2.$jmode {
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, randomblob(15000));
INSERT INTO t1 VALUES(2, randomblob(15000));
INSERT INTO t1 VALUES(3, randomblob(15000));
INSERT INTO t1 VALUES(4, randomblob(15000));
INSERT INTO t1 VALUES(5, randomblob(15000));
}
db close
sqlite3_multiplex_initialize "" 1
sqlite3 db test.db
multiplex_set db main 4096 16
} {SQLITE_OK}
do_test multiplex-5.6.3.$jmode {
catchsql {
INSERT INTO t1 VALUES(6, randomblob(15000));
}
} {1 {disk I/O error}}
do_test multiplex-5.6.4.$jmode {
db close
} {}
}
}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# Test that you can vacuum a multiplex'ed DB. # Test that you can vacuum a multiplex'ed DB.
@@ -575,8 +531,9 @@ ifcapable vacuum {
sqlite3_multiplex_shutdown sqlite3_multiplex_shutdown
do_test multiplex-6.0.0 { do_test multiplex-6.0.0 {
multiplex_delete test.db multiplex_delete test.db
multiplex_delete test.x
sqlite3_multiplex_initialize "" 1 sqlite3_multiplex_initialize "" 1
sqlite3 db test.db sqlite3 db test.x
multiplex_set db main 4096 16 multiplex_set db main 4096 16
} {SQLITE_OK} } {SQLITE_OK}
@@ -592,8 +549,8 @@ do_test multiplex-6.1.0 {
INSERT INTO t1 VALUES(2, randomblob($g_chunk_size)); INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
} }
} {} } {}
do_test multiplex-6.2.1 { file size [multiplex_name test.db 0] } [list $g_chunk_size] do_test multiplex-6.2.1 { file size [multiplex_name test.x 0] } [list $g_chunk_size]
do_test multiplex-6.2.2 { file size [multiplex_name test.db 1] } [list $g_chunk_size] do_test multiplex-6.2.2 { file size [multiplex_name test.x 1] } [list $g_chunk_size]
do_test multiplex-6.3.0 { do_test multiplex-6.3.0 {
execsql { VACUUM } execsql { VACUUM }
@@ -601,7 +558,7 @@ do_test multiplex-6.3.0 {
do_test multiplex-6.99 { do_test multiplex-6.99 {
db close db close
multiplex_delete test.db multiplex_delete test.x
sqlite3_multiplex_shutdown sqlite3_multiplex_shutdown
} {SQLITE_OK} } {SQLITE_OK}

View File

@@ -783,6 +783,15 @@ test_suite "no_optimization" -description {
optimization_control $::dbhandle all 0 optimization_control $::dbhandle all 0
} }
test_suite "prepare" -description {
Run tests with the db connection using sqlite3_prepare() instead of _v2().
} -dbconfig {
db_use_legacy_prepare $::dbhandle 1
#$::dbhandle cache size 0
} -files [
test_set $allquicktests -exclude *malloc* *ioerr* *fault*
]
# End of tests # End of tests
############################################################################# #############################################################################

View File

@@ -155,10 +155,10 @@ array set ::Configs {
array set ::Platforms { array set ::Platforms {
Linux-x86_64 { Linux-x86_64 {
"Debug-One" "checksymbols test"
"Secure-Delete" test "Secure-Delete" test
"Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test"
"Update-Delete-Limit" test "Update-Delete-Limit" test
"Debug-One" test
"Extra-Robustness" test "Extra-Robustness" test
"Device-Two" test "Device-Two" test
"Ftrapv" test "Ftrapv" test
@@ -177,6 +177,7 @@ array set ::Platforms {
} }
} }
# End of configuration section. # End of configuration section.
######################################################################### #########################################################################
######################################################################### #########################################################################

View File

@@ -355,7 +355,7 @@ for {set ii 3} {$ii <= 4} {incr ii} {
SELECT DISTINCT (a/10) FROM t1 UNION ALL SELECT DISTINCT(d%2) FROM t2 SELECT DISTINCT (a/10) FROM t1 UNION ALL SELECT DISTINCT(d%2) FROM t2
) )
} }
} {0 1 0 1} } {0 1 1 0}
do_test selectB-$ii.20 { do_test selectB-$ii.20 {
execsql { execsql {

View File

@@ -319,18 +319,22 @@ do_test sqllimits1-5.14.4 {
catch {sqlite3_bind_text $::STMT 1 $::str1 -1} res catch {sqlite3_bind_text $::STMT 1 $::str1 -1} res
set res set res
} {SQLITE_TOOBIG} } {SQLITE_TOOBIG}
do_test sqllimits1-5.14.5 { ifcapable utf16 {
catch {sqlite3_bind_text16 $::STMT 1 $::str1 -1} res do_test sqllimits1-5.14.5 {
set res catch {sqlite3_bind_text16 $::STMT 1 $::str1 -1} res
} {SQLITE_TOOBIG} set res
} {SQLITE_TOOBIG}
}
do_test sqllimits1-5.14.6 { do_test sqllimits1-5.14.6 {
catch {sqlite3_bind_text $::STMT 1 $::str1 $np1} res catch {sqlite3_bind_text $::STMT 1 $::str1 $np1} res
set res set res
} {SQLITE_TOOBIG} } {SQLITE_TOOBIG}
do_test sqllimits1-5.14.7 { ifcapable utf16 {
catch {sqlite3_bind_text16 $::STMT 1 $::str1 $np1} res do_test sqllimits1-5.14.7 {
set res catch {sqlite3_bind_text16 $::STMT 1 $::str1 $np1} res
} {SQLITE_TOOBIG} set res
} {SQLITE_TOOBIG}
}
do_test sqllimits1-5.14.8 { do_test sqllimits1-5.14.8 {
set n [expr {$np1-1}] set n [expr {$np1-1}]
catch {sqlite3_bind_text $::STMT 1 $::str1 $n} res catch {sqlite3_bind_text $::STMT 1 $::str1 $n} res

View File

@@ -292,6 +292,7 @@ do_test temptable-5.1 {
execsql { execsql {
CREATE TEMP TABLE mask(a,b,c) CREATE TEMP TABLE mask(a,b,c)
} db2 } db2
if {[permutation]=="prepare"} { db2 cache flush }
execsql { execsql {
CREATE INDEX mask ON t2(x); CREATE INDEX mask ON t2(x);
SELECT * FROM t2; SELECT * FROM t2;

67
test/tkt-54844eea3f.test Normal file
View File

@@ -0,0 +1,67 @@
# 2011 July 8
#
# 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 that bug [54844eea3f] has been fixed.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix tkt-54844eea3f
do_test 1.0 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(4);
CREATE TABLE t2(b INTEGER PRIMARY KEY);
INSERT INTO t2 VALUES(1);
INSERT INTO t2 VALUES(2);
INSERT INTO t2 SELECT b+2 FROM t2;
INSERT INTO t2 SELECT b+4 FROM t2;
INSERT INTO t2 SELECT b+8 FROM t2;
INSERT INTO t2 SELECT b+16 FROM t2;
CREATE TABLE t3(c INTEGER PRIMARY KEY);
INSERT INTO t3 VALUES(1);
INSERT INTO t3 VALUES(2);
INSERT INTO t3 VALUES(3);
}
} {}
do_test 1.1 {
execsql {
SELECT 'test-2', t3.c, (
SELECT count(*)
FROM t1 JOIN (SELECT DISTINCT t3.c AS p FROM t2) AS x ON t1.a=x.p
)
FROM t3;
}
} {test-2 1 1 test-2 2 0 test-2 3 0}
do_test 1.2 {
execsql {
CREATE TABLE t4(a, b, c);
INSERT INTO t4 VALUES('a', 1, 'one');
INSERT INTO t4 VALUES('a', 2, 'two');
INSERT INTO t4 VALUES('b', 1, 'three');
INSERT INTO t4 VALUES('b', 2, 'four');
SELECT (
SELECT c FROM (
SELECT * FROM t4 WHERE a=out.a ORDER BY b LIMIT 10 OFFSET 1
) WHERE b=out.b
) FROM t4 AS out;
}
} {{} two {} four}
finish_test

View File

@@ -14,6 +14,12 @@
# the use of these columns in triggers will refer to the column and not # the use of these columns in triggers will refer to the column and not
# to the actual ROWID. Ticket [34d2ae1c6d08b5271ba5e5592936d4a1d913ffe3] # to the actual ROWID. Ticket [34d2ae1c6d08b5271ba5e5592936d4a1d913ffe3]
# #
# Also, verify that triggers created like this:
#
# CREATE TRIGGER attached.trig AFTER INSERT ON attached.tab ...
#
# can be reparsed as a main database. Ticket [d6ddba6706353915ceedc56b4e3]
#
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -171,4 +177,43 @@ do_test triggerD-3.2 {
} {10003 20004} } {10003 20004}
#############################################################################
#
# Ticket [d6ddba6706353915ceedc56b4e3e72ecb4d77ba4]
#
# The following syntax really should not be allowed:
#
# CREATE TRIGGER xyz.trig BEFORE UPDATE ON xyz.tab BEGIN ...
#
# But a long-standing bug does allow it. And the "xyz.tab" slips into
# the sqlite_master table. We cannot fix the bug simply by disallowing
# "xyz.tab" since that could break legacy applications. We have to
# fix the system so that the "xyz." on "xyz.tab" is ignored.
# Verify that this is the case.
#
do_test triggerD-4.1 {
db close
file delete -force test.db test2.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(x);
ATTACH 'test2.db' AS db2;
CREATE TABLE db2.t2(y);
CREATE TABLE db2.log(z);
CREATE TRIGGER db2.trig AFTER INSERT ON db2.t2 BEGIN
INSERT INTO log(z) VALUES(new.y);
END;
INSERT INTO t2 VALUES(123);
SELECT * FROM log;
}
} {123}
do_test triggerD-4.2 {
sqlite3 db2 test2.db
db2 eval {
INSERT INTO t2 VALUES(234);
SELECT * FROM log;
}
} {123 234}
db2 close
finish_test finish_test

View File

@@ -707,7 +707,7 @@ T delete
# and continues. # and continues.
# #
set nConn 50 set nConn 50
if { [string match *BSD $tcl_platform(os)] } { set nConn 35 } if { [string match *BSD $tcl_platform(os)] } { set nConn 25 }
do_test wal3-9.0 { do_test wal3-9.0 {
file delete -force test.db test.db-journal test.db wal file delete -force test.db test.db-journal test.db wal
sqlite3 db test.db sqlite3 db test.db
@@ -784,4 +784,3 @@ do_multiclient_test tn {
} }
finish_test finish_test

View File

@@ -43,19 +43,11 @@ foreach jmode $all_journal_modes {
} {1 2} } {1 2}
# Under Windows, you'll get an error trying to delete # Under Windows, you'll get an error trying to delete
# a file this is already opened. For now, make sure # a file this is already opened. Close the first connection
# we get that error, then close the first connection
# so the other tests work. # so the other tests work.
if {$tcl_platform(platform)=="windows"} { if {$tcl_platform(platform)=="windows"} {
if {$jmode=="persist" || $jmode=="truncate"} { if {$jmode=="persist" || $jmode=="truncate"} {
do_test wal6-1.2.$jmode.win { db close
sqlite3 db2 test.db
catchsql {
PRAGMA journal_mode=WAL;
} db2
} {1 {disk I/O error}}
db2 close
db close
} }
} }
@@ -87,4 +79,3 @@ if {$tcl_platform(platform)=="windows"} {
} }
finish_test finish_test

108
test/win32lock.test Normal file
View File

@@ -0,0 +1,108 @@
# 2011 July 11
#
# 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 recovery from transient manditory locks
# that sometimes appear on database files due to anti-virus software.
#
if {$tcl_platform(platform)!="windows"} return
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix win32lock
db close
sqlite3_shutdown
test_sqlite3_log xLog
proc xLog {error_code msg} {
lappend ::log $msg
}
sqlite3 db test.db
do_test win32lock-1.1 {
db eval {
PRAGMA cache_size=10;
CREATE TABLE t1(x,y);
INSERT INTO t1 VALUES(1,randomblob(100000));
INSERT INTO t1 VALUES(2,randomblob(50000));
INSERT INTO t1 VALUES(3,randomblob(25000));
INSERT INTO t1 VALUES(4,randomblob(12500));
SELECT x, length(y) FROM t1 ORDER BY rowid;
}
} {1 100000 2 50000 3 25000 4 12500}
unset -nocomplain delay1 rc msg
set delay1 50
set rc 0
set old_pending_byte [sqlite3_test_control_pending_byte 0x40000000]
while {1} {
sqlite3_sleep 10
lock_win32_file test.db 0 $::delay1
set rc [catch {db eval {SELECT x, length(y) FROM t1 ORDER BY rowid}} msg]
if {$rc} {
do_test win32lock-1.2-$delay1-fin {
set ::msg
} {disk I/O error}
break
} else {
do_test win32lock-1.2-$delay1 {
set ::msg
} {1 100000 2 50000 3 25000 4 12500}
if {$::log!=""} {
do_test win32lock-1.2-$delay1-log1 {
regsub {\d+} $::log # x
set x
} {{delayed #ms for lock/sharing conflict}}
}
incr delay1 50
}
set ::log {}
}
do_test win32lock-2.0 {
file_control_win32_av_retry db -1 -1
} {0 10 25}
do_test win32lock-2.1 {
file_control_win32_av_retry db 1 1
} {0 1 1}
set delay1 50
while {1} {
sqlite3_sleep 10
lock_win32_file test.db 0 $::delay1
set rc [catch {db eval {SELECT x, length(y) FROM t1 ORDER BY rowid}} msg]
if {$rc} {
do_test win32lock-2.2-$delay1-fin {
set ::msg
} {disk I/O error}
break
} else {
do_test win32lock-2.2-$delay1 {
set ::msg
} {1 100000 2 50000 3 25000 4 12500}
if {$::log!=""} {
do_test win32lock-2.2-$delay1-log1 {
regsub {\d+} $::log # x
set x
} {{delayed #ms for lock/sharing conflict}}
}
incr delay1 50
}
set ::log {}
}
file_control_win32_av_retry db 10 25
sqlite3_test_control_pending_byte $old_pending_byte
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize
finish_test

View File

@@ -12,10 +12,10 @@ gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \
-DSQLITE_ENABLE_ICU \ -DSQLITE_ENABLE_ICU \
sqlite3.c sqlite3.c
nm sqlite3.o | grep ' T ' | sort -k 3 nm sqlite3.o | grep ' [TD] ' | sort -k 3
echo '****** Surplus symbols from a build including RTREE, FTS4 & ICU ******' echo '****** Surplus symbols from a build including RTREE, FTS4 & ICU ******'
nm sqlite3.o | grep ' T ' | grep -v ' sqlite3_' nm sqlite3.o | grep ' [TD] ' | grep -v ' .*sqlite3_'
echo '****** Dependencies of the core. No extensions. No OS interface *******' echo '****** Dependencies of the core. No extensions. No OS interface *******'
gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT2 \ gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT2 \

View File

@@ -8,7 +8,11 @@ echo '********** No optimizations. Includes FTS4 and RTREE *********'
gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
-ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
sqlite3.c sqlite3.c
echo '********** Optimized -O3. Includes FTS4 and RTREE *********' echo '********** No optimizations. ENABLE_STAT2. THREADSAFE=0 *******'
gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
-ansi -DSQLITE_ENABLE_STAT2 -DSQLITE_THREADSAFE=0 \
sqlite3.c
echo '********** Optimized -O3. Includes FTS4 and RTREE ************'
gcc -O3 -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ gcc -O3 -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
-ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
sqlite3.c sqlite3.c