Bring in the latest trunk changes.
FossilOrigin-Name: 75d8517703f7efa33437079108e2c4ef0de1a118bbe1f4a86afdc34da09d3008
This commit is contained in:
commit
32b5fdcaea
@ -89,6 +89,9 @@ TCC += $(OPT_FEATURE_FLAGS)
|
||||
# ie. make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1".
|
||||
TCC += $(OPTS)
|
||||
|
||||
# Add in compile-time options for some libraries used by extensions
|
||||
TCC += @HAVE_ZLIB@
|
||||
|
||||
# Version numbers and release number for the SQLite being compiled.
|
||||
#
|
||||
VERSION = @VERSION@
|
||||
|
27
Makefile.msc
27
Makefile.msc
@ -974,7 +974,7 @@ LTLINK = $(TCC) -Fe$@
|
||||
# If requested, link to the RPCRT4 library.
|
||||
#
|
||||
!IF $(USE_RPCRT4_LIB)!=0
|
||||
LTLINK = $(LTLINK) rpcrt4.lib
|
||||
LTLIBS = $(LTLIBS) rpcrt4.lib
|
||||
!ENDIF
|
||||
|
||||
# If a platform was set, force the linker to target that.
|
||||
@ -1072,7 +1072,7 @@ LDFLAGS = $(LDOPTS)
|
||||
#
|
||||
!IF $(NO_TCL)==0
|
||||
LTLIBPATHS = /LIBPATH:$(TCLLIBDIR)
|
||||
LTLIBS = $(LIBTCL)
|
||||
LTLIBS = $(LTLIBS) $(LIBTCL)
|
||||
!ENDIF
|
||||
|
||||
# If ICU support is enabled, add the linker options for it.
|
||||
@ -2075,6 +2075,24 @@ FTS5_SRC = \
|
||||
$(TOP)\ext\fts5\fts5_varint.c \
|
||||
$(TOP)\ext\fts5\fts5_vocab.c
|
||||
|
||||
LSM1_SRC = \
|
||||
$(TOP)\ext\lsm1\lsm.h \
|
||||
$(TOP)\ext\lsm1\lsmInt.h \
|
||||
$(TOP)\ext\lsm1\lsm_ckpt.c \
|
||||
$(TOP)\ext\lsm1\lsm_file.c \
|
||||
$(TOP)\ext\lsm1\lsm_log.c \
|
||||
$(TOP)\ext\lsm1\lsm_main.c \
|
||||
$(TOP)\ext\lsm1\lsm_mem.c \
|
||||
$(TOP)\ext\lsm1\lsm_mutex.c \
|
||||
$(TOP)\ext\lsm1\lsm_shared.c \
|
||||
$(TOP)\ext\lsm1\lsm_sorted.c \
|
||||
$(TOP)\ext\lsm1\lsm_str.c \
|
||||
$(TOP)\ext\lsm1\lsm_tree.c \
|
||||
$(TOP)\ext\lsm1\lsm_unix.c \
|
||||
$(TOP)\ext\lsm1\lsm_varint.c \
|
||||
$(TOP)\ext\lsm1\lsm_vtab.c \
|
||||
$(TOP)\ext\lsm1\lsm_win32.c
|
||||
|
||||
fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
|
||||
copy $(TOP)\ext\fts5\fts5parse.y .
|
||||
del /Q fts5parse.h 2>NUL
|
||||
@ -2086,6 +2104,10 @@ fts5.c: $(FTS5_SRC)
|
||||
$(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
|
||||
copy $(TOP)\ext\fts5\fts5.h .
|
||||
|
||||
lsm1.c: $(LSM1_SRC)
|
||||
$(TCLSH_CMD) $(TOP)\ext\lsm1\tool\mklsm1c.tcl
|
||||
copy $(TOP)\ext\lsm1\lsm.h .
|
||||
|
||||
fts5.lo: fts5.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c fts5.c
|
||||
|
||||
@ -2315,4 +2337,5 @@ clean:
|
||||
del /Q sqlite-*-output.vsix 2>NUL
|
||||
del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL
|
||||
del /Q fts5.* fts5parse.* 2>NUL
|
||||
del /Q lsm.h lsm1.c 2>NUL
|
||||
# <</mark>>
|
||||
|
32
README.md
32
README.md
@ -207,8 +207,8 @@ The amalgamation source file is more than 200K lines long. Some symbolic
|
||||
debuggers (most notably MSVC) are unable to deal with files longer than 64K
|
||||
lines. To work around this, a separate Tcl script, tool/split-sqlite3c.tcl,
|
||||
can be run on the amalgamation to break it up into a single small C file
|
||||
called **sqlite3-all.c** that does #include on about five other files
|
||||
named **sqlite3-1.c**, **sqlite3-2.c**, ..., **sqlite3-5.c**. In this way,
|
||||
called **sqlite3-all.c** that does #include on about seven other files
|
||||
named **sqlite3-1.c**, **sqlite3-2.c**, ..., **sqlite3-7.c**. In this way,
|
||||
all of the source code is contained within a single translation unit so
|
||||
that the compiler can do extra cross-procedure optimization, but no
|
||||
individual source file exceeds 32K lines in length.
|
||||
@ -237,7 +237,8 @@ Key files:
|
||||
trying to understand how the library works internally.
|
||||
|
||||
* **sqliteInt.h** - this header file defines many of the data objects
|
||||
used internally by SQLite.
|
||||
used internally by SQLite. In addition to "sqliteInt.h", some
|
||||
subsystems have their own header files.
|
||||
|
||||
* **parse.y** - This file describes the LALR(1) grammar that SQLite uses
|
||||
to parse SQL statements, and the actions that are taken at each step
|
||||
@ -249,29 +250,44 @@ Key files:
|
||||
which defines internal data objects. The rest of SQLite interacts
|
||||
with the VDBE through an interface defined by vdbe.h.
|
||||
|
||||
* **where.c** - This file analyzes the WHERE clause and generates
|
||||
* **where.c** - This file (together with its helper files named
|
||||
by "where*.c") analyzes the WHERE clause and generates
|
||||
virtual machine code to run queries efficiently. This file is
|
||||
sometimes called the "query optimizer". It has its own private
|
||||
header file, whereInt.h, that defines data objects used internally.
|
||||
|
||||
* **btree.c** - This file contains the implementation of the B-Tree
|
||||
storage engine used by SQLite.
|
||||
storage engine used by SQLite. The interface to the rest of the system
|
||||
is defined by "btree.h". The "btreeInt.h" header defines objects
|
||||
used internally by btree.c and not published to the rest of the system.
|
||||
|
||||
* **pager.c** - This file contains the "pager" implementation, the
|
||||
module that implements transactions.
|
||||
module that implements transactions. The "pager.h" header file
|
||||
defines the interface between pager.c and the rest of the system.
|
||||
|
||||
* **os_unix.c** and **os_win.c** - These two files implement the interface
|
||||
between SQLite and the underlying operating system using the run-time
|
||||
pluggable VFS interface.
|
||||
|
||||
* **shell.c** - This file is not part of the core SQLite library. This
|
||||
* **shell.c.in** - This file is not part of the core SQLite library. This
|
||||
is the file that, when linked against sqlite3.a, generates the
|
||||
"sqlite3.exe" command-line shell.
|
||||
"sqlite3.exe" command-line shell. The "shell.c.in" file is transformed
|
||||
into "shell.c" as part of the build process.
|
||||
|
||||
* **tclsqlite.c** - This file implements the Tcl bindings for SQLite. It
|
||||
is not part of the core SQLite library. But as most of the tests in this
|
||||
repository are written in Tcl, the Tcl language bindings are important.
|
||||
|
||||
* **test*.c** - Files in the src/ folder that begin with "test" go into
|
||||
building the "testfixture.exe" program. The testfixture.exe program is
|
||||
an enhanced TCL shell. The testfixture.exe program runs scripts in the
|
||||
test/ folder to validate the core SQLite code. The testfixture program
|
||||
(and some other test programs too) is build and run when you type
|
||||
"make test".
|
||||
|
||||
* **ext/misc/json1.c** - This file implements the various JSON functions
|
||||
that are build into SQLite.
|
||||
|
||||
There are many other source files. Each has a succinct header comment that
|
||||
describes its purpose and role within the larger system.
|
||||
|
||||
|
@ -808,7 +808,7 @@ LTLINK = $(TCC) -Fe$@
|
||||
# If requested, link to the RPCRT4 library.
|
||||
#
|
||||
!IF $(USE_RPCRT4_LIB)!=0
|
||||
LTLINK = $(LTLINK) rpcrt4.lib
|
||||
LTLIBS = $(LTLIBS) rpcrt4.lib
|
||||
!ENDIF
|
||||
|
||||
# If a platform was set, force the linker to target that.
|
||||
|
103
configure
vendored
103
configure
vendored
@ -772,6 +772,7 @@ LIBOBJS
|
||||
BUILD_CFLAGS
|
||||
USE_GCOV
|
||||
OPT_FEATURE_FLAGS
|
||||
HAVE_ZLIB
|
||||
USE_AMALGAMATION
|
||||
TARGET_DEBUG
|
||||
TARGET_HAVE_EDITLINE
|
||||
@ -3931,13 +3932,13 @@ if ${lt_cv_nm_interface+:} false; then :
|
||||
else
|
||||
lt_cv_nm_interface="BSD nm"
|
||||
echo "int some_variable = 0;" > conftest.$ac_ext
|
||||
(eval echo "\"\$as_me:3934: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3935: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3937: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:3938: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3940: output\"" >&5)
|
||||
(eval echo "\"\$as_me:3941: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
@ -5143,7 +5144,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 5146 "configure"' > conftest.$ac_ext
|
||||
echo '#line 5147 "configure"' > conftest.$ac_ext
|
||||
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@ -6668,11 +6669,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:6671: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6672: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6675: \$? = $ac_status" >&5
|
||||
echo "$as_me:6676: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@ -7007,11 +7008,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7010: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7011: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7014: \$? = $ac_status" >&5
|
||||
echo "$as_me:7015: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@ -7112,11 +7113,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7115: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7116: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7119: \$? = $ac_status" >&5
|
||||
echo "$as_me:7120: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@ -7167,11 +7168,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7170: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7171: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7174: \$? = $ac_status" >&5
|
||||
echo "$as_me:7175: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@ -9547,7 +9548,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9550 "configure"
|
||||
#line 9551 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -9643,7 +9644,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9646 "configure"
|
||||
#line 9647 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -11274,6 +11275,80 @@ if test "${use_amalgamation}" != "yes" ; then
|
||||
fi
|
||||
|
||||
|
||||
#########
|
||||
# Look for zlib. Only needed by extensions and by the sqlite3.exe shell
|
||||
for ac_header in zlib.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_zlib_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_ZLIB_H 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing deflate" >&5
|
||||
$as_echo_n "checking for library containing deflate... " >&6; }
|
||||
if ${ac_cv_search_deflate+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char deflate ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return deflate ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_lib in '' z; do
|
||||
if test -z "$ac_lib"; then
|
||||
ac_res="none required"
|
||||
else
|
||||
ac_res=-l$ac_lib
|
||||
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||
fi
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_search_deflate=$ac_res
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext
|
||||
if ${ac_cv_search_deflate+:} false; then :
|
||||
break
|
||||
fi
|
||||
done
|
||||
if ${ac_cv_search_deflate+:} false; then :
|
||||
|
||||
else
|
||||
ac_cv_search_deflate=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_deflate" >&5
|
||||
$as_echo "$ac_cv_search_deflate" >&6; }
|
||||
ac_res=$ac_cv_search_deflate
|
||||
if test "$ac_res" != no; then :
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
HAVE_ZLIB="-DSQLITE_HAVE_ZLIB=1"
|
||||
else
|
||||
HAVE_ZLIB=""
|
||||
fi
|
||||
|
||||
|
||||
|
||||
#########
|
||||
# See whether we should allow loadable extensions
|
||||
# Check whether --enable-load-extension was given.
|
||||
|
@ -576,6 +576,12 @@ if test "${use_amalgamation}" != "yes" ; then
|
||||
fi
|
||||
AC_SUBST(USE_AMALGAMATION)
|
||||
|
||||
#########
|
||||
# Look for zlib. Only needed by extensions and by the sqlite3.exe shell
|
||||
AC_CHECK_HEADERS(zlib.h)
|
||||
AC_SEARCH_LIBS(deflate, z, [HAVE_ZLIB="-DSQLITE_HAVE_ZLIB=1"], [HAVE_ZLIB=""])
|
||||
AC_SUBST(HAVE_ZLIB)
|
||||
|
||||
#########
|
||||
# See whether we should allow loadable extensions
|
||||
AC_ARG_ENABLE(load-extension, AC_HELP_STRING([--disable-load-extension],
|
||||
|
@ -722,6 +722,8 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
int bPrefix
|
||||
);
|
||||
|
||||
void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase*);
|
||||
|
||||
Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
||||
Fts5Parse*,
|
||||
Fts5ExprNearset*,
|
||||
|
@ -87,7 +87,8 @@ struct Fts5ExprNode {
|
||||
** or term prefix.
|
||||
*/
|
||||
struct Fts5ExprTerm {
|
||||
int bPrefix; /* True for a prefix term */
|
||||
u8 bPrefix; /* True for a prefix term */
|
||||
u8 bFirst; /* True if token must be first in column */
|
||||
char *zTerm; /* nul-terminated term */
|
||||
Fts5IndexIter *pIter; /* Iterator for this term */
|
||||
Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
|
||||
@ -168,6 +169,7 @@ static int fts5ExprGetToken(
|
||||
case '+': tok = FTS5_PLUS; break;
|
||||
case '*': tok = FTS5_STAR; break;
|
||||
case '-': tok = FTS5_MINUS; break;
|
||||
case '^': tok = FTS5_CARET; break;
|
||||
case '\0': tok = FTS5_EOF; break;
|
||||
|
||||
case '"': {
|
||||
@ -427,6 +429,7 @@ static int fts5ExprPhraseIsMatch(
|
||||
Fts5PoslistReader *aIter = aStatic;
|
||||
int i;
|
||||
int rc = SQLITE_OK;
|
||||
int bFirst = pPhrase->aTerm[0].bFirst;
|
||||
|
||||
fts5BufferZero(&pPhrase->poslist);
|
||||
|
||||
@ -481,8 +484,10 @@ static int fts5ExprPhraseIsMatch(
|
||||
}while( bMatch==0 );
|
||||
|
||||
/* Append position iPos to the output */
|
||||
rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
|
||||
if( rc!=SQLITE_OK ) goto ismatch_out;
|
||||
if( bFirst==0 || FTS5_POS2OFFSET(iPos)==0 ){
|
||||
rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
|
||||
if( rc!=SQLITE_OK ) goto ismatch_out;
|
||||
}
|
||||
|
||||
for(i=0; i<pPhrase->nTerm; i++){
|
||||
if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
|
||||
@ -736,7 +741,9 @@ static int fts5ExprNearTest(
|
||||
** phrase is not a match, break out of the loop early. */
|
||||
for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
|
||||
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
|
||||
if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
|
||||
if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym
|
||||
|| pNear->pColset || pPhrase->aTerm[0].bFirst
|
||||
){
|
||||
int bMatch = 0;
|
||||
rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch);
|
||||
if( bMatch==0 ) break;
|
||||
@ -917,6 +924,7 @@ static int fts5ExprNodeTest_STRING(
|
||||
assert( pNear->nPhrase>1
|
||||
|| pNear->apPhrase[0]->nTerm>1
|
||||
|| pNear->apPhrase[0]->aTerm[0].pSynonym
|
||||
|| pNear->apPhrase[0]->aTerm[0].bFirst
|
||||
);
|
||||
|
||||
/* Initialize iLast, the "lastest" rowid any iterator points to. If the
|
||||
@ -1441,6 +1449,16 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the "bFirst" flag on the first token of the phrase passed as the
|
||||
** only argument.
|
||||
*/
|
||||
void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase *pPhrase){
|
||||
if( pPhrase && pPhrase->nTerm ){
|
||||
pPhrase->aTerm[0].bFirst = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated
|
||||
** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is
|
||||
@ -1719,6 +1737,7 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
|
||||
sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@ -1737,7 +1756,10 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
pNew->pRoot->pNear->nPhrase = 1;
|
||||
sCtx.pPhrase->pNode = pNew->pRoot;
|
||||
|
||||
if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){
|
||||
if( pOrig->nTerm==1
|
||||
&& pOrig->aTerm[0].pSynonym==0
|
||||
&& pOrig->aTerm[0].bFirst==0
|
||||
){
|
||||
pNew->pRoot->eType = FTS5_TERM;
|
||||
pNew->pRoot->xNext = fts5ExprNodeNext_TERM;
|
||||
}else{
|
||||
@ -2011,6 +2033,7 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
|
||||
Fts5ExprNearset *pNear = pNode->pNear;
|
||||
if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1
|
||||
&& pNear->apPhrase[0]->aTerm[0].pSynonym==0
|
||||
&& pNear->apPhrase[0]->aTerm[0].bFirst==0
|
||||
){
|
||||
pNode->eType = FTS5_TERM;
|
||||
pNode->xNext = fts5ExprNodeNext_TERM;
|
||||
@ -2097,20 +2120,23 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
|
||||
}
|
||||
}
|
||||
|
||||
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL
|
||||
&& (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1)
|
||||
){
|
||||
assert( pParse->rc==SQLITE_OK );
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
assert( pParse->zErr==0 );
|
||||
pParse->zErr = sqlite3_mprintf(
|
||||
"fts5: %s queries are not supported (detail!=full)",
|
||||
pNear->nPhrase==1 ? "phrase": "NEAR"
|
||||
);
|
||||
sqlite3_free(pRet);
|
||||
pRet = 0;
|
||||
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
|
||||
Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
|
||||
if( pNear->nPhrase!=1
|
||||
|| pPhrase->nTerm>1
|
||||
|| (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
|
||||
){
|
||||
assert( pParse->rc==SQLITE_OK );
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
assert( pParse->zErr==0 );
|
||||
pParse->zErr = sqlite3_mprintf(
|
||||
"fts5: %s queries are not supported (detail!=full)",
|
||||
pNear->nPhrase==1 ? "phrase": "NEAR"
|
||||
);
|
||||
sqlite3_free(pRet);
|
||||
pRet = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
fts5ExprAddChildren(pRet, pLeft);
|
||||
fts5ExprAddChildren(pRet, pRight);
|
||||
|
@ -4909,7 +4909,13 @@ static void fts5MergePrefixLists(
|
||||
Fts5Buffer out = {0, 0, 0};
|
||||
Fts5Buffer tmp = {0, 0, 0};
|
||||
|
||||
if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return;
|
||||
/* The maximum size of the output is equal to the sum of the two
|
||||
** input sizes + 1 varint (9 bytes). The extra varint is because if the
|
||||
** first rowid in one input is a large negative number, and the first in
|
||||
** the other a non-negative number, the delta for the non-negative
|
||||
** number will be larger on disk than the literal integer value
|
||||
** was. */
|
||||
if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9) ) return;
|
||||
fts5DoclistIterInit(p1, &i1);
|
||||
fts5DoclistIterInit(p2, &i2);
|
||||
|
||||
@ -5003,6 +5009,7 @@ static void fts5MergePrefixLists(
|
||||
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
|
||||
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
|
||||
}
|
||||
assert( out.n<=(p1->n+p2->n+9) );
|
||||
|
||||
fts5BufferSet(&p->rc, p1, out.n, out.p);
|
||||
fts5BufferFree(&tmp);
|
||||
|
@ -148,7 +148,11 @@ cnearset(A) ::= colset(X) COLON nearset(Y). {
|
||||
%destructor nearset { sqlite3Fts5ParseNearsetFree($$); }
|
||||
%destructor nearphrases { sqlite3Fts5ParseNearsetFree($$); }
|
||||
|
||||
nearset(A) ::= phrase(X). { A = sqlite3Fts5ParseNearset(pParse, 0, X); }
|
||||
nearset(A) ::= phrase(Y). { A = sqlite3Fts5ParseNearset(pParse, 0, Y); }
|
||||
nearset(A) ::= CARET phrase(Y). {
|
||||
sqlite3Fts5ParseSetCaret(Y);
|
||||
A = sqlite3Fts5ParseNearset(pParse, 0, Y);
|
||||
}
|
||||
nearset(A) ::= STRING(X) LP nearphrases(Y) neardist_opt(Z) RP. {
|
||||
sqlite3Fts5ParseNear(pParse, &X);
|
||||
sqlite3Fts5ParseSetDistance(pParse, Y, &Z);
|
||||
@ -189,6 +193,5 @@ phrase(A) ::= STRING(Y) star_opt(Z). {
|
||||
** Optional "*" character.
|
||||
*/
|
||||
%type star_opt {int}
|
||||
|
||||
star_opt(A) ::= STAR. { A = 1; }
|
||||
star_opt(A) ::= . { A = 0; }
|
||||
|
@ -130,5 +130,22 @@ do_faultsim_test 4.2 -faults oom* -body {
|
||||
faultsim_test_result {0 {2 3}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test OOM injection while parsing a CARET expression
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
INSERT INTO t1 VALUES('a b c d'); -- 1
|
||||
INSERT INTO t1 VALUES('d a b c'); -- 2
|
||||
INSERT INTO t1 VALUES('c d a b'); -- 3
|
||||
INSERT INTO t1 VALUES('b c d a'); -- 4
|
||||
}
|
||||
do_faultsim_test 5.1 -faults oom* -body {
|
||||
execsql { SELECT rowid FROM t1('^a OR ^b') }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 4}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
96
ext/fts5/test/fts5first.test
Normal file
96
ext/fts5/test/fts5first.test
Normal file
@ -0,0 +1,96 @@
|
||||
# 2017 November 25
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5first
|
||||
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(a, b);
|
||||
}
|
||||
|
||||
foreach {tn expr ok} {
|
||||
1 {^abc} 1
|
||||
2 {^abc + def} 1
|
||||
3 {^ "abc def"} 1
|
||||
4 {^"abc def"} 1
|
||||
5 {abc ^def} 1
|
||||
6 {abc + ^def} 0
|
||||
7 {abc ^+ def} 0
|
||||
8 {"^abc"} 1
|
||||
9 {NEAR(^abc def)} 0
|
||||
} {
|
||||
set res(0) {/1 {fts5: syntax error near .*}/}
|
||||
set res(1) {0 {}}
|
||||
|
||||
do_catchsql_test 1.$tn { SELECT * FROM x1($expr) } $res($ok)
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
INSERT INTO x1 VALUES('a b c', 'b c a');
|
||||
}
|
||||
|
||||
foreach {tn expr match} {
|
||||
1 {^a} 1
|
||||
2 {^b} 1
|
||||
3 {^c} 0
|
||||
4 {^a + b} 1
|
||||
5 {^b + c} 1
|
||||
6 {^c + a} 0
|
||||
7 {^"c a"} 0
|
||||
8 {a:^a} 1
|
||||
9 {a:^b} 0
|
||||
10 {a:^"a b"} 1
|
||||
} {
|
||||
do_execsql_test 2.$tn { SELECT EXISTS (SELECT rowid FROM x1($expr)) } $match
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.0 {
|
||||
DELETE FROM x1;
|
||||
INSERT INTO x1 VALUES('b a', 'c a');
|
||||
INSERT INTO x1 VALUES('a a', 'c c');
|
||||
INSERT INTO x1 VALUES('a b', 'a a');
|
||||
}
|
||||
fts5_aux_test_functions db
|
||||
|
||||
foreach {tn expr expect} {
|
||||
1 {^a} {{2 1}}
|
||||
2 {^c AND ^b} {{0 2} {1 0}}
|
||||
} {
|
||||
do_execsql_test 3.$tn {
|
||||
SELECT fts5_test_queryphrase(x1) FROM x1($expr) LIMIT 1
|
||||
} [list $expect]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.1 {
|
||||
CREATE VIRTUAL TABLE x2 USING fts5(a, b, c, detail=column);
|
||||
}
|
||||
|
||||
do_catchsql_test 3.2 {
|
||||
SELECT * FROM x2('a + b');
|
||||
} {1 {fts5: phrase queries are not supported (detail!=full)}}
|
||||
|
||||
do_catchsql_test 3.3 {
|
||||
SELECT * FROM x2('^a');
|
||||
} {1 {fts5: phrase queries are not supported (detail!=full)}}
|
||||
finish_test
|
||||
|
@ -64,7 +64,7 @@ for {set tn 1 ; set pgsz 64} {$tn<32} {incr tn; incr pgsz 16} {
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.$tn.2 {
|
||||
do_execsql_test 2.$tn.2 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
@ -77,5 +77,15 @@ for {set tn 1 ; set pgsz 64} {$tn<32} {incr tn; incr pgsz 16} {
|
||||
}
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(a);
|
||||
INSERT INTO x1(rowid, a) VALUES(-1000000000000, 'toyota');
|
||||
INSERT INTO x1(rowid, a) VALUES(1, 'tarago');
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
SELECT rowid FROM x1('t*');
|
||||
} {-1000000000000 1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -28,7 +28,9 @@
|
||||
** provide case-independent matching.
|
||||
*/
|
||||
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
|
||||
#if !defined(SQLITE_CORE) \
|
||||
|| defined(SQLITE_ENABLE_ICU) \
|
||||
|| defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
||||
|
||||
/* Include ICU headers */
|
||||
#include <unicode/utypes.h>
|
||||
@ -45,6 +47,26 @@
|
||||
#include "sqlite3.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function is called when an ICU function called from within
|
||||
** the implementation of an SQL scalar function returns an error.
|
||||
**
|
||||
** The scalar function context passed as the first argument is
|
||||
** loaded with an error message based on the following two args.
|
||||
*/
|
||||
static void icuFunctionError(
|
||||
sqlite3_context *pCtx, /* SQLite scalar function context */
|
||||
const char *zName, /* Name of ICU function that failed */
|
||||
UErrorCode e /* Error code returned by ICU function */
|
||||
){
|
||||
char zBuf[128];
|
||||
sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
|
||||
zBuf[127] = '\0';
|
||||
sqlite3_result_error(pCtx, zBuf, -1);
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
|
||||
|
||||
/*
|
||||
** Maximum length (in bytes) of the pattern in a LIKE or GLOB
|
||||
** operator.
|
||||
@ -224,24 +246,6 @@ static void icuLikeFunc(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called when an ICU function called from within
|
||||
** the implementation of an SQL scalar function returns an error.
|
||||
**
|
||||
** The scalar function context passed as the first argument is
|
||||
** loaded with an error message based on the following two args.
|
||||
*/
|
||||
static void icuFunctionError(
|
||||
sqlite3_context *pCtx, /* SQLite scalar function context */
|
||||
const char *zName, /* Name of ICU function that failed */
|
||||
UErrorCode e /* Error code returned by ICU function */
|
||||
){
|
||||
char zBuf[128];
|
||||
sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
|
||||
zBuf[127] = '\0';
|
||||
sqlite3_result_error(pCtx, zBuf, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Function to delete compiled regexp objects. Registered as
|
||||
** a destructor function with sqlite3_set_auxdata().
|
||||
@ -407,6 +411,8 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
||||
assert( 0 ); /* Unreachable */
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
|
||||
|
||||
/*
|
||||
** Collation sequence destructor function. The pCtx argument points to
|
||||
** a UCollator structure previously allocated using ucol_open().
|
||||
@ -501,6 +507,7 @@ int sqlite3IcuInit(sqlite3 *db){
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} scalars[] = {
|
||||
{"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation},
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
|
||||
{"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
|
||||
{"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
@ -512,10 +519,10 @@ int sqlite3IcuInit(sqlite3 *db){
|
||||
{"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
{"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
|
||||
};
|
||||
int rc = SQLITE_OK;
|
||||
int i;
|
||||
|
||||
|
||||
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
|
||||
const struct IcuScalar *p = &scalars[i];
|
||||
|
@ -110,7 +110,7 @@ typedef unsigned long long int u64;
|
||||
#endif
|
||||
|
||||
/* A page number is a 64-bit integer. */
|
||||
typedef i64 Pgno;
|
||||
typedef i64 LsmPgno;
|
||||
|
||||
#ifdef LSM_DEBUG
|
||||
int lsmErrorBkpt(int);
|
||||
@ -402,9 +402,9 @@ struct lsm_db {
|
||||
};
|
||||
|
||||
struct Segment {
|
||||
Pgno iFirst; /* First page of this run */
|
||||
Pgno iLastPg; /* Last page of this run */
|
||||
Pgno iRoot; /* Root page number (if any) */
|
||||
LsmPgno iFirst; /* First page of this run */
|
||||
LsmPgno iLastPg; /* Last page of this run */
|
||||
LsmPgno iRoot; /* Root page number (if any) */
|
||||
int nSize; /* Size of this run in pages */
|
||||
|
||||
Redirect *pRedirect; /* Block redirects (or NULL) */
|
||||
@ -456,7 +456,7 @@ struct Level {
|
||||
** output segment.
|
||||
*/
|
||||
struct MergeInput {
|
||||
Pgno iPg; /* Page on which next input is stored */
|
||||
LsmPgno iPg; /* Page on which next input is stored */
|
||||
int iCell; /* Cell containing next input to merge */
|
||||
};
|
||||
struct Merge {
|
||||
@ -465,7 +465,7 @@ struct Merge {
|
||||
MergeInput splitkey; /* Location in file of current splitkey */
|
||||
int nSkip; /* Number of separators entries to skip */
|
||||
int iOutputOff; /* Write offset on output page */
|
||||
Pgno iCurrentPtr; /* Current pointer value */
|
||||
LsmPgno iCurrentPtr; /* Current pointer value */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -579,10 +579,10 @@ struct Snapshot {
|
||||
Redirect redirect; /* Block redirection array */
|
||||
|
||||
/* Used by worker snapshots only */
|
||||
int nBlock; /* Number of blocks in database file */
|
||||
Pgno aiAppend[LSM_APPLIST_SZ]; /* Append point list */
|
||||
Freelist freelist; /* Free block list */
|
||||
u32 nWrite; /* Total number of pages written to disk */
|
||||
int nBlock; /* Number of blocks in database file */
|
||||
LsmPgno aiAppend[LSM_APPLIST_SZ]; /* Append point list */
|
||||
Freelist freelist; /* Free block list */
|
||||
u32 nWrite; /* Total number of pages written to disk */
|
||||
};
|
||||
#define LSM_INITIAL_SNAPSHOT_ID 11
|
||||
|
||||
@ -710,7 +710,7 @@ void lsmFsSetPageSize(FileSystem *, int);
|
||||
int lsmFsFileid(lsm_db *pDb, void **ppId, int *pnId);
|
||||
|
||||
/* Creating, populating, gobbling and deleting sorted runs. */
|
||||
void lsmFsGobble(lsm_db *, Segment *, Pgno *, int);
|
||||
void lsmFsGobble(lsm_db *, Segment *, LsmPgno *, int);
|
||||
int lsmFsSortedDelete(FileSystem *, Snapshot *, int, Segment *);
|
||||
int lsmFsSortedFinish(FileSystem *, Segment *);
|
||||
int lsmFsSortedAppend(FileSystem *, Snapshot *, Level *, int, Page **);
|
||||
@ -727,14 +727,14 @@ void lsmSortedSplitkey(lsm_db *, Level *, int *);
|
||||
|
||||
/* Reading sorted run content. */
|
||||
int lsmFsDbPageLast(FileSystem *pFS, Segment *pSeg, Page **ppPg);
|
||||
int lsmFsDbPageGet(FileSystem *, Segment *, Pgno, Page **);
|
||||
int lsmFsDbPageGet(FileSystem *, Segment *, LsmPgno, Page **);
|
||||
int lsmFsDbPageNext(Segment *, Page *, int eDir, Page **);
|
||||
|
||||
u8 *lsmFsPageData(Page *, int *);
|
||||
int lsmFsPageRelease(Page *);
|
||||
int lsmFsPagePersist(Page *);
|
||||
void lsmFsPageRef(Page *);
|
||||
Pgno lsmFsPageNumber(Page *);
|
||||
LsmPgno lsmFsPageNumber(Page *);
|
||||
|
||||
int lsmFsNRead(FileSystem *);
|
||||
int lsmFsNWrite(FileSystem *);
|
||||
@ -748,7 +748,7 @@ int lsmFsDbPageIsLast(Segment *pSeg, Page *pPg);
|
||||
int lsmFsIntegrityCheck(lsm_db *);
|
||||
#endif
|
||||
|
||||
Pgno lsmFsRedirectPage(FileSystem *, Redirect *, Pgno);
|
||||
LsmPgno lsmFsRedirectPage(FileSystem *, Redirect *, LsmPgno);
|
||||
|
||||
int lsmFsPageWritable(Page *);
|
||||
|
||||
@ -768,8 +768,8 @@ int lsmFsSyncDb(FileSystem *, int);
|
||||
void lsmFsFlushWaiting(FileSystem *, int *);
|
||||
|
||||
/* Used by lsm_info(ARRAY_STRUCTURE) and lsm_config(MMAP) */
|
||||
int lsmInfoArrayStructure(lsm_db *pDb, int bBlock, Pgno iFirst, char **pzOut);
|
||||
int lsmInfoArrayPages(lsm_db *pDb, Pgno iFirst, char **pzOut);
|
||||
int lsmInfoArrayStructure(lsm_db *pDb, int bBlock, LsmPgno iFirst, char **pz);
|
||||
int lsmInfoArrayPages(lsm_db *pDb, LsmPgno iFirst, char **pzOut);
|
||||
int lsmConfigMmap(lsm_db *pDb, int *piParam);
|
||||
|
||||
int lsmEnvOpen(lsm_env *, const char *, int, lsm_file **);
|
||||
@ -785,7 +785,7 @@ void lsmEnvSleep(lsm_env *, int);
|
||||
|
||||
int lsmFsReadSyncedId(lsm_db *db, int, i64 *piVal);
|
||||
|
||||
int lsmFsSegmentContainsPg(FileSystem *pFS, Segment *, Pgno, int *);
|
||||
int lsmFsSegmentContainsPg(FileSystem *pFS, Segment *, LsmPgno, int *);
|
||||
|
||||
void lsmFsPurgeCache(FileSystem *);
|
||||
|
||||
@ -796,7 +796,7 @@ void lsmFsPurgeCache(FileSystem *);
|
||||
/*
|
||||
** Functions from file "lsm_sorted.c".
|
||||
*/
|
||||
int lsmInfoPageDump(lsm_db *, Pgno, int, char **);
|
||||
int lsmInfoPageDump(lsm_db *, LsmPgno, int, char **);
|
||||
void lsmSortedCleanup(lsm_db *);
|
||||
int lsmSortedAutoWork(lsm_db *, int nUnit);
|
||||
|
||||
|
@ -389,7 +389,7 @@ static void ckptExportAppendlist(
|
||||
int *pRc /* IN/OUT: Error code */
|
||||
){
|
||||
int i;
|
||||
Pgno *aiAppend = db->pWorker->aiAppend;
|
||||
LsmPgno *aiAppend = db->pWorker->aiAppend;
|
||||
|
||||
for(i=0; i<LSM_APPLIST_SZ; i++){
|
||||
ckptAppend64(p, piOut, aiAppend[i], pRc);
|
||||
|
@ -269,7 +269,7 @@ struct FileSystem {
|
||||
struct Page {
|
||||
u8 *aData; /* Buffer containing page data */
|
||||
int nData; /* Bytes of usable data at aData[] */
|
||||
Pgno iPg; /* Page number */
|
||||
LsmPgno iPg; /* Page number */
|
||||
int nRef; /* Number of outstanding references */
|
||||
int flags; /* Combination of PAGE_XXX flags */
|
||||
Page *pHashNext; /* Next page in hash table slot */
|
||||
@ -332,7 +332,7 @@ static int IOERR_WRAPPER(int rc){
|
||||
#ifdef NDEBUG
|
||||
# define assert_lists_are_ok(x)
|
||||
#else
|
||||
static Page *fsPageFindInHash(FileSystem *pFS, Pgno iPg, int *piHash);
|
||||
static Page *fsPageFindInHash(FileSystem *pFS, LsmPgno iPg, int *piHash);
|
||||
|
||||
static void assert_lists_are_ok(FileSystem *pFS){
|
||||
#if 0
|
||||
@ -532,7 +532,7 @@ int lsmFsCloseAndDeleteLog(FileSystem *pFS){
|
||||
** Return true if page iReal of the database should be accessed using mmap.
|
||||
** False otherwise.
|
||||
*/
|
||||
static int fsMmapPage(FileSystem *pFS, Pgno iReal){
|
||||
static int fsMmapPage(FileSystem *pFS, LsmPgno iReal){
|
||||
return ((i64)iReal*pFS->nPagesize <= pFS->nMapLimit);
|
||||
}
|
||||
|
||||
@ -540,7 +540,7 @@ static int fsMmapPage(FileSystem *pFS, Pgno iReal){
|
||||
** Given that there are currently nHash slots in the hash table, return
|
||||
** the hash key for file iFile, page iPg.
|
||||
*/
|
||||
static int fsHashKey(int nHash, Pgno iPg){
|
||||
static int fsHashKey(int nHash, LsmPgno iPg){
|
||||
return (iPg % nHash);
|
||||
}
|
||||
|
||||
@ -880,13 +880,13 @@ void lsmFsSetBlockSize(FileSystem *pFS, int nBlocksize){
|
||||
** page on each block is the byte offset immediately following the 4-byte
|
||||
** "previous block" pointer at the start of each block.
|
||||
*/
|
||||
static Pgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
|
||||
Pgno iPg;
|
||||
static LsmPgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
|
||||
LsmPgno iPg;
|
||||
if( pFS->pCompress ){
|
||||
if( iBlock==1 ){
|
||||
iPg = pFS->nMetasize * 2 + 4;
|
||||
}else{
|
||||
iPg = pFS->nBlocksize * (Pgno)(iBlock-1) + 4;
|
||||
iPg = pFS->nBlocksize * (LsmPgno)(iBlock-1) + 4;
|
||||
}
|
||||
}else{
|
||||
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
|
||||
@ -907,9 +907,9 @@ static Pgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
|
||||
** page on each block is the byte offset of the byte immediately before
|
||||
** the 4-byte "next block" pointer at the end of each block.
|
||||
*/
|
||||
static Pgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
|
||||
static LsmPgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
|
||||
if( pFS->pCompress ){
|
||||
return pFS->nBlocksize * (Pgno)iBlock - 1 - 4;
|
||||
return pFS->nBlocksize * (LsmPgno)iBlock - 1 - 4;
|
||||
}else{
|
||||
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
|
||||
return iBlock * nPagePerBlock;
|
||||
@ -920,7 +920,7 @@ static Pgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
|
||||
** Return the block number of the block that page iPg is located on.
|
||||
** Blocks are numbered starting from 1.
|
||||
*/
|
||||
static int fsPageToBlock(FileSystem *pFS, Pgno iPg){
|
||||
static int fsPageToBlock(FileSystem *pFS, LsmPgno iPg){
|
||||
if( pFS->pCompress ){
|
||||
return (int)((iPg / pFS->nBlocksize) + 1);
|
||||
}else{
|
||||
@ -933,7 +933,7 @@ static int fsPageToBlock(FileSystem *pFS, Pgno iPg){
|
||||
**
|
||||
** This function is only called in non-compressed database mode.
|
||||
*/
|
||||
static int fsIsLast(FileSystem *pFS, Pgno iPg){
|
||||
static int fsIsLast(FileSystem *pFS, LsmPgno iPg){
|
||||
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
|
||||
assert( !pFS->pCompress );
|
||||
return ( iPg && (iPg % nPagePerBlock)==0 );
|
||||
@ -944,7 +944,7 @@ static int fsIsLast(FileSystem *pFS, Pgno iPg){
|
||||
**
|
||||
** This function is only called in non-compressed database mode.
|
||||
*/
|
||||
static int fsIsFirst(FileSystem *pFS, Pgno iPg){
|
||||
static int fsIsFirst(FileSystem *pFS, LsmPgno iPg){
|
||||
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
|
||||
assert( !pFS->pCompress );
|
||||
return ( (iPg % nPagePerBlock)==1
|
||||
@ -967,7 +967,7 @@ u8 *lsmFsPageData(Page *pPage, int *pnData){
|
||||
/*
|
||||
** Return the page number of a page.
|
||||
*/
|
||||
Pgno lsmFsPageNumber(Page *pPage){
|
||||
LsmPgno lsmFsPageNumber(Page *pPage){
|
||||
/* assert( (pPage->flags & PAGE_DIRTY)==0 ); */
|
||||
return pPage ? pPage->iPg : 0;
|
||||
}
|
||||
@ -1058,7 +1058,7 @@ void lsmFsPurgeCache(FileSystem *pFS){
|
||||
** Either way, if argument piHash is not NULL set *piHash to the hash slot
|
||||
** number that page iPg would be stored in before returning.
|
||||
*/
|
||||
static Page *fsPageFindInHash(FileSystem *pFS, Pgno iPg, int *piHash){
|
||||
static Page *fsPageFindInHash(FileSystem *pFS, LsmPgno iPg, int *piHash){
|
||||
Page *p; /* Return value */
|
||||
int iHash = fsHashKey(pFS->nHash, iPg);
|
||||
|
||||
@ -1189,8 +1189,8 @@ static int fsRedirectBlock(Redirect *p, int iBlk){
|
||||
** object passed as the second argument, return the destination page to
|
||||
** which it is redirected. Otherwise, return a copy of iPg.
|
||||
*/
|
||||
Pgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
|
||||
Pgno iReal = iPg;
|
||||
LsmPgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, LsmPgno iPg){
|
||||
LsmPgno iReal = iPg;
|
||||
|
||||
if( pRedir ){
|
||||
const int nPagePerBlock = (
|
||||
@ -1203,7 +1203,7 @@ Pgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
|
||||
if( iFrom>iBlk ) break;
|
||||
if( iFrom==iBlk ){
|
||||
int iTo = pRedir->a[i].iTo;
|
||||
iReal = iPg - (Pgno)(iFrom - iTo) * nPagePerBlock;
|
||||
iReal = iPg - (LsmPgno)(iFrom - iTo) * nPagePerBlock;
|
||||
if( iTo==1 ){
|
||||
iReal += (fsFirstPageOnBlock(pFS, 1)-1);
|
||||
}
|
||||
@ -1217,7 +1217,7 @@ Pgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
|
||||
}
|
||||
|
||||
/* Required by the circular fsBlockNext<->fsPageGet dependency. */
|
||||
static int fsPageGet(FileSystem *, Segment *, Pgno, int, Page **, int *);
|
||||
static int fsPageGet(FileSystem *, Segment *, LsmPgno, int, Page **, int *);
|
||||
|
||||
/*
|
||||
** Parameter iBlock is a database file block. This function reads the value
|
||||
@ -1269,7 +1269,7 @@ static int fsBlockNext(
|
||||
/*
|
||||
** Return the page number of the last page on the same block as page iPg.
|
||||
*/
|
||||
Pgno fsLastPageOnPagesBlock(FileSystem *pFS, Pgno iPg){
|
||||
LsmPgno fsLastPageOnPagesBlock(FileSystem *pFS, LsmPgno iPg){
|
||||
return fsLastPageOnBlock(pFS, fsPageToBlock(pFS, iPg));
|
||||
}
|
||||
|
||||
@ -1537,7 +1537,7 @@ static int fsReadPagedata(
|
||||
static int fsPageGet(
|
||||
FileSystem *pFS, /* File-system handle */
|
||||
Segment *pSeg, /* Block redirection to use (or NULL) */
|
||||
Pgno iPg, /* Page id */
|
||||
LsmPgno iPg, /* Page id */
|
||||
int noContent, /* True to not load content from disk */
|
||||
Page **ppPg, /* OUT: New page handle */
|
||||
int *pnSpace /* OUT: Bytes of free space */
|
||||
@ -1549,7 +1549,7 @@ static int fsPageGet(
|
||||
/* In most cases iReal is the same as iPg. Except, if pSeg->pRedirect is
|
||||
** not NULL, and the block containing iPg has been redirected, then iReal
|
||||
** is the page number after redirection. */
|
||||
Pgno iReal = lsmFsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
|
||||
LsmPgno iReal = lsmFsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
|
||||
|
||||
assert_lists_are_ok(pFS);
|
||||
assert( iPg>=fsFirstPageOnBlock(pFS, 1) );
|
||||
@ -1689,8 +1689,8 @@ int lsmFsReadSyncedId(lsm_db *db, int iMeta, i64 *piVal){
|
||||
static int fsRunEndsBetween(
|
||||
Segment *pRun,
|
||||
Segment *pIgnore,
|
||||
Pgno iFirst,
|
||||
Pgno iLast
|
||||
LsmPgno iFirst,
|
||||
LsmPgno iLast
|
||||
){
|
||||
return (pRun!=pIgnore && (
|
||||
(pRun->iFirst>=iFirst && pRun->iFirst<=iLast)
|
||||
@ -1705,8 +1705,8 @@ static int fsRunEndsBetween(
|
||||
static int fsLevelEndsBetween(
|
||||
Level *pLevel,
|
||||
Segment *pIgnore,
|
||||
Pgno iFirst,
|
||||
Pgno iLast
|
||||
LsmPgno iFirst,
|
||||
LsmPgno iLast
|
||||
){
|
||||
int i;
|
||||
|
||||
@ -1733,13 +1733,13 @@ static int fsFreeBlock(
|
||||
int iBlk /* Block number of block to free */
|
||||
){
|
||||
int rc = LSM_OK; /* Return code */
|
||||
Pgno iFirst; /* First page on block iBlk */
|
||||
Pgno iLast; /* Last page on block iBlk */
|
||||
LsmPgno iFirst; /* First page on block iBlk */
|
||||
LsmPgno iLast; /* Last page on block iBlk */
|
||||
Level *pLevel; /* Used to iterate through levels */
|
||||
|
||||
int iIn; /* Used to iterate through append points */
|
||||
int iOut = 0; /* Used to output append points */
|
||||
Pgno *aApp = pSnapshot->aiAppend;
|
||||
LsmPgno *aApp = pSnapshot->aiAppend;
|
||||
|
||||
iFirst = fsFirstPageOnBlock(pFS, iBlk);
|
||||
iLast = fsLastPageOnBlock(pFS, iBlk);
|
||||
@ -1811,11 +1811,16 @@ int lsmFsSortedDelete(
|
||||
** number from the array that falls on block iBlk. Or, if none of the pages
|
||||
** in aPgno[] fall on block iBlk, return 0.
|
||||
*/
|
||||
static Pgno firstOnBlock(FileSystem *pFS, int iBlk, Pgno *aPgno, int nPgno){
|
||||
Pgno iRet = 0;
|
||||
static LsmPgno firstOnBlock(
|
||||
FileSystem *pFS,
|
||||
int iBlk,
|
||||
LsmPgno *aPgno,
|
||||
int nPgno
|
||||
){
|
||||
LsmPgno iRet = 0;
|
||||
int i;
|
||||
for(i=0; i<nPgno; i++){
|
||||
Pgno iPg = aPgno[i];
|
||||
LsmPgno iPg = aPgno[i];
|
||||
if( fsPageToBlock(pFS, iPg)==iBlk && (iRet==0 || iPg<iRet) ){
|
||||
iRet = iPg;
|
||||
}
|
||||
@ -1828,7 +1833,7 @@ static Pgno firstOnBlock(FileSystem *pFS, int iBlk, Pgno *aPgno, int nPgno){
|
||||
** Return true if page iPg, which is a part of segment p, lies on
|
||||
** a redirected block.
|
||||
*/
|
||||
static int fsPageRedirects(FileSystem *pFS, Segment *p, Pgno iPg){
|
||||
static int fsPageRedirects(FileSystem *pFS, Segment *p, LsmPgno iPg){
|
||||
return (iPg!=0 && iPg!=lsmFsRedirectPage(pFS, p->pRedirect, iPg));
|
||||
}
|
||||
|
||||
@ -1854,7 +1859,7 @@ static int fsSegmentRedirects(FileSystem *pFS, Segment *p){
|
||||
void lsmFsGobble(
|
||||
lsm_db *pDb,
|
||||
Segment *pRun,
|
||||
Pgno *aPgno,
|
||||
LsmPgno *aPgno,
|
||||
int nPgno
|
||||
){
|
||||
int rc = LSM_OK;
|
||||
@ -1871,7 +1876,7 @@ void lsmFsGobble(
|
||||
|
||||
while( rc==LSM_OK ){
|
||||
int iNext = 0;
|
||||
Pgno iFirst = firstOnBlock(pFS, iBlk, aPgno, nPgno);
|
||||
LsmPgno iFirst = firstOnBlock(pFS, iBlk, aPgno, nPgno);
|
||||
if( iFirst ){
|
||||
pRun->iFirst = iFirst;
|
||||
break;
|
||||
@ -1905,11 +1910,11 @@ void lsmFsGobble(
|
||||
static int fsNextPageOffset(
|
||||
FileSystem *pFS, /* File system object */
|
||||
Segment *pSeg, /* Segment to move within */
|
||||
Pgno iPg, /* Offset of current page */
|
||||
LsmPgno iPg, /* Offset of current page */
|
||||
int nByte, /* Size of current page including headers */
|
||||
Pgno *piNext /* OUT: Offset of next page. Or zero (EOF) */
|
||||
LsmPgno *piNext /* OUT: Offset of next page. Or zero (EOF) */
|
||||
){
|
||||
Pgno iNext;
|
||||
LsmPgno iNext;
|
||||
int rc;
|
||||
|
||||
assert( pFS->pCompress );
|
||||
@ -1939,8 +1944,8 @@ static int fsNextPageOffset(
|
||||
static int fsGetPageBefore(
|
||||
FileSystem *pFS,
|
||||
Segment *pSeg,
|
||||
Pgno iPg,
|
||||
Pgno *piPrev
|
||||
LsmPgno iPg,
|
||||
LsmPgno *piPrev
|
||||
){
|
||||
u8 aSz[3];
|
||||
int rc;
|
||||
@ -1990,7 +1995,7 @@ static int fsGetPageBefore(
|
||||
int lsmFsDbPageNext(Segment *pRun, Page *pPg, int eDir, Page **ppNext){
|
||||
int rc = LSM_OK;
|
||||
FileSystem *pFS = pPg->pFS;
|
||||
Pgno iPg = pPg->iPg;
|
||||
LsmPgno iPg = pPg->iPg;
|
||||
|
||||
assert( 0==fsSegmentRedirects(pFS, pRun) );
|
||||
if( pFS->pCompress ){
|
||||
@ -2062,10 +2067,10 @@ int lsmFsDbPageNext(Segment *pRun, Page *pPg, int eDir, Page **ppNext){
|
||||
** start the new segment immediately following any segment that is part
|
||||
** of the right-hand-side of pLvl.
|
||||
*/
|
||||
static Pgno findAppendPoint(FileSystem *pFS, Level *pLvl){
|
||||
static LsmPgno findAppendPoint(FileSystem *pFS, Level *pLvl){
|
||||
int i;
|
||||
Pgno *aiAppend = pFS->pDb->pWorker->aiAppend;
|
||||
Pgno iRet = 0;
|
||||
LsmPgno *aiAppend = pFS->pDb->pWorker->aiAppend;
|
||||
LsmPgno iRet = 0;
|
||||
|
||||
for(i=LSM_APPLIST_SZ-1; iRet==0 && i>=0; i--){
|
||||
if( (iRet = aiAppend[i]) ){
|
||||
@ -2098,10 +2103,10 @@ int lsmFsSortedAppend(
|
||||
){
|
||||
int rc = LSM_OK;
|
||||
Page *pPg = 0;
|
||||
Pgno iApp = 0;
|
||||
Pgno iNext = 0;
|
||||
LsmPgno iApp = 0;
|
||||
LsmPgno iNext = 0;
|
||||
Segment *p = &pLvl->lhs;
|
||||
Pgno iPrev = p->iLastPg;
|
||||
LsmPgno iPrev = p->iLastPg;
|
||||
|
||||
*ppOut = 0;
|
||||
assert( p->pRedirect==0 );
|
||||
@ -2195,7 +2200,7 @@ int lsmFsSortedFinish(FileSystem *pFS, Segment *p){
|
||||
*/
|
||||
if( fsLastPageOnPagesBlock(pFS, p->iLastPg)!=p->iLastPg ){
|
||||
int i;
|
||||
Pgno *aiAppend = pFS->pDb->pWorker->aiAppend;
|
||||
LsmPgno *aiAppend = pFS->pDb->pWorker->aiAppend;
|
||||
for(i=0; i<LSM_APPLIST_SZ; i++){
|
||||
if( aiAppend[i]==0 ){
|
||||
aiAppend[i] = p->iLastPg+1;
|
||||
@ -2226,7 +2231,7 @@ int lsmFsSortedFinish(FileSystem *pFS, Segment *p){
|
||||
**
|
||||
** Return LSM_OK if successful, or an lsm error code if an error occurs.
|
||||
*/
|
||||
int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, Pgno iPg, Page **ppPg){
|
||||
int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, LsmPgno iPg, Page **ppPg){
|
||||
return fsPageGet(pFS, pSeg, iPg, 0, ppPg, 0);
|
||||
}
|
||||
|
||||
@ -2238,7 +2243,7 @@ int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, Pgno iPg, Page **ppPg){
|
||||
*/
|
||||
int lsmFsDbPageLast(FileSystem *pFS, Segment *pSeg, Page **ppPg){
|
||||
int rc;
|
||||
Pgno iPg = pSeg->iLastPg;
|
||||
LsmPgno iPg = pSeg->iLastPg;
|
||||
if( pFS->pCompress ){
|
||||
int nSpace;
|
||||
iPg++;
|
||||
@ -2366,14 +2371,14 @@ static void fsMovePage(
|
||||
FileSystem *pFS, /* File system object */
|
||||
int iTo, /* Destination block */
|
||||
int iFrom, /* Source block */
|
||||
Pgno *piPg /* IN/OUT: Page number */
|
||||
LsmPgno *piPg /* IN/OUT: Page number */
|
||||
){
|
||||
Pgno iPg = *piPg;
|
||||
LsmPgno iPg = *piPg;
|
||||
if( iFrom==fsPageToBlock(pFS, iPg) ){
|
||||
const int nPagePerBlock = (
|
||||
pFS->pCompress ? pFS ->nBlocksize : (pFS->nBlocksize / pFS->nPagesize)
|
||||
);
|
||||
*piPg = iPg - (Pgno)(iFrom - iTo) * nPagePerBlock;
|
||||
*piPg = iPg - (LsmPgno)(iFrom - iTo) * nPagePerBlock;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2457,21 +2462,21 @@ int lsmFsMoveBlock(FileSystem *pFS, Segment *pSeg, int iTo, int iFrom){
|
||||
**
|
||||
** This function is only used in compressed database mode.
|
||||
*/
|
||||
static Pgno fsAppendData(
|
||||
static LsmPgno fsAppendData(
|
||||
FileSystem *pFS, /* File-system handle */
|
||||
Segment *pSeg, /* Segment to append to */
|
||||
const u8 *aData, /* Buffer containing data to write */
|
||||
int nData, /* Size of buffer aData[] in bytes */
|
||||
int *pRc /* IN/OUT: Error code */
|
||||
){
|
||||
Pgno iRet = 0;
|
||||
LsmPgno iRet = 0;
|
||||
int rc = *pRc;
|
||||
assert( pFS->pCompress );
|
||||
if( rc==LSM_OK ){
|
||||
int nRem = 0;
|
||||
int nWrite = 0;
|
||||
Pgno iLastOnBlock;
|
||||
Pgno iApp = pSeg->iLastPg+1;
|
||||
LsmPgno iLastOnBlock;
|
||||
LsmPgno iApp = pSeg->iLastPg+1;
|
||||
|
||||
/* If this is the first data written into the segment, find an append-point
|
||||
** or allocate a new block. */
|
||||
@ -2519,7 +2524,7 @@ static Pgno fsAppendData(
|
||||
|
||||
/* Set the "prev" pointer on the new block */
|
||||
if( rc==LSM_OK ){
|
||||
Pgno iWrite;
|
||||
LsmPgno iWrite;
|
||||
lsmPutU32(aPtr, fsPageToBlock(pFS, iApp));
|
||||
iWrite = fsFirstPageOnBlock(pFS, iBlk);
|
||||
rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iWrite-4, aPtr, sizeof(aPtr));
|
||||
@ -2588,11 +2593,11 @@ static int fsCompressIntoBuffer(FileSystem *pFS, Page *pPg){
|
||||
static int fsAppendPage(
|
||||
FileSystem *pFS,
|
||||
Segment *pSeg,
|
||||
Pgno *piNew,
|
||||
LsmPgno *piNew,
|
||||
int *piPrev,
|
||||
int *piNext
|
||||
){
|
||||
Pgno iPrev = pSeg->iLastPg;
|
||||
LsmPgno iPrev = pSeg->iLastPg;
|
||||
int rc;
|
||||
assert( iPrev!=0 );
|
||||
|
||||
@ -2650,7 +2655,7 @@ void lsmFsFlushWaiting(FileSystem *pFS, int *pRc){
|
||||
/*
|
||||
** If there exists a hash-table entry associated with page iPg, remove it.
|
||||
*/
|
||||
static void fsRemoveHashEntry(FileSystem *pFS, Pgno iPg){
|
||||
static void fsRemoveHashEntry(FileSystem *pFS, LsmPgno iPg){
|
||||
Page *p;
|
||||
int iHash = fsHashKey(pFS->nHash, iPg);
|
||||
|
||||
@ -2804,8 +2809,8 @@ int lsmFsSortedPadding(
|
||||
){
|
||||
int rc = LSM_OK;
|
||||
if( pFS->pCompress && pSeg->iFirst ){
|
||||
Pgno iLast2;
|
||||
Pgno iLast = pSeg->iLastPg; /* Current last page of segment */
|
||||
LsmPgno iLast2;
|
||||
LsmPgno iLast = pSeg->iLastPg; /* Current last page of segment */
|
||||
int nPad; /* Bytes of padding required */
|
||||
u8 aSz[3];
|
||||
|
||||
@ -2935,7 +2940,7 @@ int lsmFsSectorSize(FileSystem *pFS){
|
||||
/*
|
||||
** Helper function for lsmInfoArrayStructure().
|
||||
*/
|
||||
static Segment *startsWith(Segment *pRun, Pgno iFirst){
|
||||
static Segment *startsWith(Segment *pRun, LsmPgno iFirst){
|
||||
return (iFirst==pRun->iFirst) ? pRun : 0;
|
||||
}
|
||||
|
||||
@ -2943,7 +2948,7 @@ static Segment *startsWith(Segment *pRun, Pgno iFirst){
|
||||
** Return the segment that starts with page iFirst, if any. If no such segment
|
||||
** can be found, return NULL.
|
||||
*/
|
||||
static Segment *findSegment(Snapshot *pWorker, Pgno iFirst){
|
||||
static Segment *findSegment(Snapshot *pWorker, LsmPgno iFirst){
|
||||
Level *pLvl; /* Used to iterate through db levels */
|
||||
Segment *pSeg = 0; /* Pointer to segment to return */
|
||||
|
||||
@ -2970,7 +2975,7 @@ static Segment *findSegment(Snapshot *pWorker, Pgno iFirst){
|
||||
int lsmInfoArrayStructure(
|
||||
lsm_db *pDb,
|
||||
int bBlock, /* True for block numbers only */
|
||||
Pgno iFirst,
|
||||
LsmPgno iFirst,
|
||||
char **pzOut
|
||||
){
|
||||
int rc = LSM_OK;
|
||||
@ -3035,7 +3040,7 @@ int lsmInfoArrayStructure(
|
||||
int lsmFsSegmentContainsPg(
|
||||
FileSystem *pFS,
|
||||
Segment *pSeg,
|
||||
Pgno iPg,
|
||||
LsmPgno iPg,
|
||||
int *pbRes
|
||||
){
|
||||
Redirect *pRedir = pSeg->pRedirect;
|
||||
@ -3064,7 +3069,7 @@ int lsmFsSegmentContainsPg(
|
||||
**
|
||||
** If an error occurs, *pzOut is set to NULL and an LSM error code returned.
|
||||
*/
|
||||
int lsmInfoArrayPages(lsm_db *pDb, Pgno iFirst, char **pzOut){
|
||||
int lsmInfoArrayPages(lsm_db *pDb, LsmPgno iFirst, char **pzOut){
|
||||
int rc = LSM_OK;
|
||||
Snapshot *pWorker; /* Worker snapshot */
|
||||
Segment *pSeg = 0; /* Array to report on */
|
||||
@ -3297,7 +3302,7 @@ int lsmFsIntegrityCheck(lsm_db *pDb){
|
||||
*/
|
||||
int lsmFsDbPageIsLast(Segment *pSeg, Page *pPg){
|
||||
if( pPg->pFS->pCompress ){
|
||||
Pgno iNext = 0;
|
||||
LsmPgno iNext = 0;
|
||||
int rc;
|
||||
rc = fsNextPageOffset(pPg->pFS, pSeg, pPg->iPg, pPg->nCompress+6, &iNext);
|
||||
return (rc!=LSM_OK || iNext==0);
|
||||
|
@ -583,14 +583,14 @@ int lsm_info(lsm_db *pDb, int eParam, ...){
|
||||
}
|
||||
|
||||
case LSM_INFO_ARRAY_STRUCTURE: {
|
||||
Pgno pgno = va_arg(ap, Pgno);
|
||||
LsmPgno pgno = va_arg(ap, LsmPgno);
|
||||
char **pzVal = va_arg(ap, char **);
|
||||
rc = lsmInfoArrayStructure(pDb, 0, pgno, pzVal);
|
||||
break;
|
||||
}
|
||||
|
||||
case LSM_INFO_ARRAY_PAGES: {
|
||||
Pgno pgno = va_arg(ap, Pgno);
|
||||
LsmPgno pgno = va_arg(ap, LsmPgno);
|
||||
char **pzVal = va_arg(ap, char **);
|
||||
rc = lsmInfoArrayPages(pDb, pgno, pzVal);
|
||||
break;
|
||||
@ -598,7 +598,7 @@ int lsm_info(lsm_db *pDb, int eParam, ...){
|
||||
|
||||
case LSM_INFO_PAGE_HEX_DUMP:
|
||||
case LSM_INFO_PAGE_ASCII_DUMP: {
|
||||
Pgno pgno = va_arg(ap, Pgno);
|
||||
LsmPgno pgno = va_arg(ap, LsmPgno);
|
||||
char **pzVal = va_arg(ap, char **);
|
||||
int bUnlock = 0;
|
||||
rc = infoGetWorker(pDb, 0, &bUnlock);
|
||||
|
@ -92,7 +92,7 @@
|
||||
#define SEGMENT_POINTER_OFFSET(pgsz) ((pgsz) - 2 - 2 - 8)
|
||||
#define SEGMENT_CELLPTR_OFFSET(pgsz, iCell) ((pgsz) - 2 - 2 - 8 - 2 - (iCell)*2)
|
||||
|
||||
#define SEGMENT_EOF(pgsz, nEntry) SEGMENT_CELLPTR_OFFSET(pgsz, nEntry)
|
||||
#define SEGMENT_EOF(pgsz, nEntry) SEGMENT_CELLPTR_OFFSET(pgsz, nEntry-1)
|
||||
|
||||
#define SEGMENT_BTREE_FLAG 0x0001
|
||||
#define PGFTR_SKIP_NEXT_FLAG 0x0002
|
||||
@ -104,9 +104,9 @@
|
||||
#endif
|
||||
|
||||
typedef struct SegmentPtr SegmentPtr;
|
||||
typedef struct Blob Blob;
|
||||
typedef struct LsmBlob LsmBlob;
|
||||
|
||||
struct Blob {
|
||||
struct LsmBlob {
|
||||
lsm_env *pEnv;
|
||||
void *pData;
|
||||
int nData;
|
||||
@ -129,18 +129,18 @@ struct SegmentPtr {
|
||||
Page *pPg; /* Current page */
|
||||
u16 flags; /* Copy of page flags field */
|
||||
int nCell; /* Number of cells on pPg */
|
||||
Pgno iPtr; /* Base cascade pointer */
|
||||
LsmPgno iPtr; /* Base cascade pointer */
|
||||
|
||||
/* Current cell. See segmentPtrLoadCell() */
|
||||
int iCell; /* Current record within page pPg */
|
||||
int eType; /* Type of current record */
|
||||
Pgno iPgPtr; /* Cascade pointer offset */
|
||||
LsmPgno iPgPtr; /* Cascade pointer offset */
|
||||
void *pKey; int nKey; /* Key associated with current record */
|
||||
void *pVal; int nVal; /* Current record value (eType==WRITE only) */
|
||||
|
||||
/* Blobs used to allocate buffers for pKey and pVal as required */
|
||||
Blob blob1;
|
||||
Blob blob2;
|
||||
LsmBlob blob1;
|
||||
LsmBlob blob2;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -171,10 +171,10 @@ struct BtreeCursor {
|
||||
void *pKey;
|
||||
int nKey;
|
||||
int eType;
|
||||
Pgno iPtr;
|
||||
LsmPgno iPtr;
|
||||
|
||||
/* Storage for key, if not local */
|
||||
Blob blob;
|
||||
LsmBlob blob;
|
||||
};
|
||||
|
||||
|
||||
@ -203,8 +203,8 @@ struct MultiCursor {
|
||||
int flags; /* Mask of CURSOR_XXX flags */
|
||||
|
||||
int eType; /* Cache of current key type */
|
||||
Blob key; /* Cache of current key (or NULL) */
|
||||
Blob val; /* Cache of current value */
|
||||
LsmBlob key; /* Cache of current key (or NULL) */
|
||||
LsmBlob val; /* Cache of current value */
|
||||
|
||||
/* All the component cursors: */
|
||||
TreeCursor *apTreeCsr[2]; /* Up to two tree cursors */
|
||||
@ -221,7 +221,7 @@ struct MultiCursor {
|
||||
void *pSystemVal; /* Pointer to buffer to free */
|
||||
|
||||
/* Used by worker cursors only */
|
||||
Pgno *pPrevMergePtr;
|
||||
LsmPgno *pPrevMergePtr;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -295,11 +295,11 @@ struct MergeWorker {
|
||||
Hierarchy hier; /* B-tree hierarchy under construction */
|
||||
Page *pPage; /* Current output page */
|
||||
int nWork; /* Number of calls to mergeWorkerNextPage() */
|
||||
Pgno *aGobble; /* Gobble point for each input segment */
|
||||
LsmPgno *aGobble; /* Gobble point for each input segment */
|
||||
|
||||
Pgno iIndirect;
|
||||
LsmPgno iIndirect;
|
||||
struct SavedPgno {
|
||||
Pgno iPgno;
|
||||
LsmPgno iPgno;
|
||||
int bStore;
|
||||
} aSave[2];
|
||||
};
|
||||
@ -371,7 +371,7 @@ void lsmPutU64(u8 *aOut, u64 nVal){
|
||||
aOut[7] = (u8)((nVal ) & 0xFF);
|
||||
}
|
||||
|
||||
static int sortedBlobGrow(lsm_env *pEnv, Blob *pBlob, int nData){
|
||||
static int sortedBlobGrow(lsm_env *pEnv, LsmBlob *pBlob, int nData){
|
||||
assert( pBlob->pEnv==pEnv || (pBlob->pEnv==0 && pBlob->pData==0) );
|
||||
if( pBlob->nAlloc<nData ){
|
||||
pBlob->pData = lsmReallocOrFree(pEnv, pBlob->pData, nData);
|
||||
@ -382,7 +382,7 @@ static int sortedBlobGrow(lsm_env *pEnv, Blob *pBlob, int nData){
|
||||
return LSM_OK;
|
||||
}
|
||||
|
||||
static int sortedBlobSet(lsm_env *pEnv, Blob *pBlob, void *pData, int nData){
|
||||
static int sortedBlobSet(lsm_env *pEnv, LsmBlob *pBlob, void *pData, int nData){
|
||||
if( sortedBlobGrow(pEnv, pBlob, nData) ) return LSM_NOMEM;
|
||||
memcpy(pBlob->pData, pData, nData);
|
||||
pBlob->nData = nData;
|
||||
@ -390,15 +390,15 @@ static int sortedBlobSet(lsm_env *pEnv, Blob *pBlob, void *pData, int nData){
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int sortedBlobCopy(Blob *pDest, Blob *pSrc){
|
||||
static int sortedBlobCopy(LsmBlob *pDest, LsmBlob *pSrc){
|
||||
return sortedBlobSet(pDest, pSrc->pData, pSrc->nData);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void sortedBlobFree(Blob *pBlob){
|
||||
static void sortedBlobFree(LsmBlob *pBlob){
|
||||
assert( pBlob->pEnv || pBlob->pData==0 );
|
||||
if( pBlob->pData ) lsmFree(pBlob->pEnv, pBlob->pData);
|
||||
memset(pBlob, 0, sizeof(Blob));
|
||||
memset(pBlob, 0, sizeof(LsmBlob));
|
||||
}
|
||||
|
||||
static int sortedReadData(
|
||||
@ -407,7 +407,7 @@ static int sortedReadData(
|
||||
int iOff,
|
||||
int nByte,
|
||||
void **ppData,
|
||||
Blob *pBlob
|
||||
LsmBlob *pBlob
|
||||
){
|
||||
int rc = LSM_OK;
|
||||
int iEnd;
|
||||
@ -481,8 +481,8 @@ static int pageGetNRec(u8 *aData, int nData){
|
||||
return (int)lsmGetU16(&aData[SEGMENT_NRECORD_OFFSET(nData)]);
|
||||
}
|
||||
|
||||
static Pgno pageGetPtr(u8 *aData, int nData){
|
||||
return (Pgno)lsmGetU64(&aData[SEGMENT_POINTER_OFFSET(nData)]);
|
||||
static LsmPgno pageGetPtr(u8 *aData, int nData){
|
||||
return (LsmPgno)lsmGetU64(&aData[SEGMENT_POINTER_OFFSET(nData)]);
|
||||
}
|
||||
|
||||
static int pageGetFlags(u8 *aData, int nData){
|
||||
@ -506,8 +506,8 @@ static int pageObjGetNRec(Page *pPg){
|
||||
** Return the decoded (possibly relative) pointer value stored in cell
|
||||
** iCell from page aData/nData.
|
||||
*/
|
||||
static Pgno pageGetRecordPtr(u8 *aData, int nData, int iCell){
|
||||
Pgno iRet; /* Return value */
|
||||
static LsmPgno pageGetRecordPtr(u8 *aData, int nData, int iCell){
|
||||
LsmPgno iRet; /* Return value */
|
||||
u8 *aCell; /* Pointer to cell iCell */
|
||||
|
||||
assert( iCell<pageGetNRec(aData, nData) && iCell>=0 );
|
||||
@ -522,7 +522,7 @@ static u8 *pageGetKey(
|
||||
int iCell, /* Index of cell on page to read */
|
||||
int *piTopic, /* OUT: Topic associated with this key */
|
||||
int *pnKey, /* OUT: Size of key in bytes */
|
||||
Blob *pBlob /* If required, use this for dynamic memory */
|
||||
LsmBlob *pBlob /* If required, use this for dynamic memory */
|
||||
){
|
||||
u8 *pKey;
|
||||
int nDummy;
|
||||
@ -554,7 +554,7 @@ static int pageGetKeyCopy(
|
||||
Page *pPg, /* Page to read from */
|
||||
int iCell, /* Index of cell on page to read */
|
||||
int *piTopic, /* OUT: Topic associated with this key */
|
||||
Blob *pBlob /* If required, use this for dynamic memory */
|
||||
LsmBlob *pBlob /* If required, use this for dynamic memory */
|
||||
){
|
||||
int rc = LSM_OK;
|
||||
int nKey;
|
||||
@ -569,8 +569,8 @@ static int pageGetKeyCopy(
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Pgno pageGetBtreeRef(Page *pPg, int iKey){
|
||||
Pgno iRef;
|
||||
static LsmPgno pageGetBtreeRef(Page *pPg, int iKey){
|
||||
LsmPgno iRef;
|
||||
u8 *aData;
|
||||
int nData;
|
||||
u8 *aCell;
|
||||
@ -592,11 +592,11 @@ static int pageGetBtreeKey(
|
||||
Segment *pSeg, /* Segment page pPg belongs to */
|
||||
Page *pPg,
|
||||
int iKey,
|
||||
Pgno *piPtr,
|
||||
LsmPgno *piPtr,
|
||||
int *piTopic,
|
||||
void **ppKey,
|
||||
int *pnKey,
|
||||
Blob *pBlob
|
||||
LsmBlob *pBlob
|
||||
){
|
||||
u8 *aData;
|
||||
int nData;
|
||||
@ -613,7 +613,7 @@ static int pageGetBtreeKey(
|
||||
|
||||
if( eType==0 ){
|
||||
int rc;
|
||||
Pgno iRef; /* Page number of referenced page */
|
||||
LsmPgno iRef; /* Page number of referenced page */
|
||||
Page *pRef;
|
||||
aCell += GETVARINT64(aCell, iRef);
|
||||
rc = lsmFsDbPageGet(lsmPageFS(pPg), pSeg, iRef, &pRef);
|
||||
@ -638,7 +638,7 @@ static int btreeCursorLoadKey(BtreeCursor *pCsr){
|
||||
pCsr->nKey = 0;
|
||||
pCsr->eType = 0;
|
||||
}else{
|
||||
Pgno dummy;
|
||||
LsmPgno dummy;
|
||||
int iPg = pCsr->iPg;
|
||||
int iCell = pCsr->aPg[iPg].iCell;
|
||||
while( iCell<0 && (--iPg)>=0 ){
|
||||
@ -683,7 +683,7 @@ static int btreeCursorNext(BtreeCursor *pCsr){
|
||||
assert( pPg->iCell<=nCell );
|
||||
pPg->iCell++;
|
||||
if( pPg->iCell==nCell ){
|
||||
Pgno iLoad;
|
||||
LsmPgno iLoad;
|
||||
|
||||
/* Up to parent. */
|
||||
lsmFsPageRelease(pPg->pPage);
|
||||
@ -842,7 +842,7 @@ static int btreeCursorRestore(
|
||||
if( p->iPg ){
|
||||
lsm_env *pEnv = lsmFsEnv(pCsr->pFS);
|
||||
int iCell; /* Current cell number on leaf page */
|
||||
Pgno iLeaf; /* Page number of current leaf page */
|
||||
LsmPgno iLeaf; /* Page number of current leaf page */
|
||||
int nDepth; /* Depth of b-tree structure */
|
||||
Segment *pSeg = pCsr->pSeg;
|
||||
|
||||
@ -866,7 +866,7 @@ static int btreeCursorRestore(
|
||||
|
||||
/* Populate any other aPg[] array entries */
|
||||
if( rc==LSM_OK && nDepth>1 ){
|
||||
Blob blob = {0,0,0};
|
||||
LsmBlob blob = {0,0,0};
|
||||
void *pSeek;
|
||||
int nSeek;
|
||||
int iTopicSeek;
|
||||
@ -883,7 +883,7 @@ static int btreeCursorRestore(
|
||||
pSeek = 0;
|
||||
nSeek = 0;
|
||||
}else{
|
||||
Pgno dummy;
|
||||
LsmPgno dummy;
|
||||
rc = pageGetBtreeKey(pSeg, pPg,
|
||||
0, &dummy, &iTopicSeek, &pSeek, &nSeek, &pCsr->blob
|
||||
);
|
||||
@ -912,7 +912,7 @@ static int btreeCursorRestore(
|
||||
int iTry = (iMin+iMax)/2;
|
||||
void *pKey; int nKey; /* Key for cell iTry */
|
||||
int iTopic; /* Topic for key pKeyT/nKeyT */
|
||||
Pgno iPtr; /* Pointer for cell iTry */
|
||||
LsmPgno iPtr; /* Pointer for cell iTry */
|
||||
int res; /* (pSeek - pKeyT) */
|
||||
|
||||
rc = pageGetBtreeKey(
|
||||
@ -955,7 +955,7 @@ static int btreeCursorRestore(
|
||||
aData = fsPageData(pBtreePg->pPage, &nData);
|
||||
pCsr->iPtr = btreeCursorPtr(aData, nData, pBtreePg->iCell+1);
|
||||
if( pBtreePg->iCell<0 ){
|
||||
Pgno dummy;
|
||||
LsmPgno dummy;
|
||||
int i;
|
||||
for(i=pCsr->iPg-1; i>=0; i--){
|
||||
if( pCsr->aPg[i].iCell>0 ) break;
|
||||
@ -1030,7 +1030,7 @@ static int segmentPtrReadData(
|
||||
int iOff,
|
||||
int nByte,
|
||||
void **ppData,
|
||||
Blob *pBlob
|
||||
LsmBlob *pBlob
|
||||
){
|
||||
return sortedReadData(pPtr->pSeg, pPtr->pPg, iOff, nByte, ppData, pBlob);
|
||||
}
|
||||
@ -1123,7 +1123,7 @@ static void sortedSplitkey(lsm_db *pDb, Level *pLevel, int *pRc){
|
||||
}
|
||||
if( rc==LSM_OK ){
|
||||
int iTopic;
|
||||
Blob blob = {0, 0, 0, 0};
|
||||
LsmBlob blob = {0, 0, 0, 0};
|
||||
u8 *aData;
|
||||
int nData;
|
||||
|
||||
@ -1131,7 +1131,7 @@ static void sortedSplitkey(lsm_db *pDb, Level *pLevel, int *pRc){
|
||||
if( pageGetFlags(aData, nData) & SEGMENT_BTREE_FLAG ){
|
||||
void *pKey;
|
||||
int nKey;
|
||||
Pgno dummy;
|
||||
LsmPgno dummy;
|
||||
rc = pageGetBtreeKey(pSeg,
|
||||
pPg, pMerge->splitkey.iCell, &dummy, &iTopic, &pKey, &nKey, &blob
|
||||
);
|
||||
@ -1342,7 +1342,7 @@ static int assertKeyLocation(
|
||||
void *pKey, int nKey
|
||||
){
|
||||
lsm_env *pEnv = lsmFsEnv(pCsr->pDb->pFS);
|
||||
Blob blob = {0, 0, 0};
|
||||
LsmBlob blob = {0, 0, 0};
|
||||
int eDir;
|
||||
int iTopic = 0; /* TODO: Fix me */
|
||||
|
||||
@ -1488,7 +1488,7 @@ static int ptrFwdPointer(
|
||||
Page *pPage,
|
||||
int iCell,
|
||||
Segment *pSeg,
|
||||
Pgno *piPtr,
|
||||
LsmPgno *piPtr,
|
||||
int *pbFound
|
||||
){
|
||||
Page *pPg = pPage;
|
||||
@ -1573,14 +1573,14 @@ static int sortedRhsFirst(MultiCursor *pCsr, Level *pLvl, SegmentPtr *pPtr){
|
||||
static int segmentPtrFwdPointer(
|
||||
MultiCursor *pCsr, /* Multi-cursor pPtr belongs to */
|
||||
SegmentPtr *pPtr, /* Segment-pointer to extract FC ptr from */
|
||||
Pgno *piPtr /* OUT: FC pointer value */
|
||||
LsmPgno *piPtr /* OUT: FC pointer value */
|
||||
){
|
||||
Level *pLvl = pPtr->pLevel;
|
||||
Level *pNext = pLvl->pNext;
|
||||
Page *pPg = pPtr->pPg;
|
||||
int rc;
|
||||
int bFound;
|
||||
Pgno iOut = 0;
|
||||
LsmPgno iOut = 0;
|
||||
|
||||
if( pPtr->pSeg==&pLvl->lhs || pPtr->pSeg==&pLvl->aRhs[pLvl->nRight-1] ){
|
||||
if( pNext==0
|
||||
@ -1641,7 +1641,7 @@ static int segmentPtrSeek(
|
||||
int rc = LSM_OK;
|
||||
int iMin;
|
||||
int iMax;
|
||||
Pgno iPtrOut = 0;
|
||||
LsmPgno iPtrOut = 0;
|
||||
|
||||
/* If the current page contains an oversized entry, then there are no
|
||||
** pointers to one or more of the subsequent pages in the sorted run.
|
||||
@ -1768,18 +1768,18 @@ static int seekInBtree(
|
||||
Segment *pSeg, /* Seek within this segment */
|
||||
int iTopic,
|
||||
void *pKey, int nKey, /* Key to seek to */
|
||||
Pgno *aPg, /* OUT: Page numbers */
|
||||
LsmPgno *aPg, /* OUT: Page numbers */
|
||||
Page **ppPg /* OUT: Leaf (sorted-run) page reference */
|
||||
){
|
||||
int i = 0;
|
||||
int rc;
|
||||
int iPg;
|
||||
Page *pPg = 0;
|
||||
Blob blob = {0, 0, 0};
|
||||
LsmBlob blob = {0, 0, 0};
|
||||
|
||||
iPg = (int)pSeg->iRoot;
|
||||
do {
|
||||
Pgno *piFirst = 0;
|
||||
LsmPgno *piFirst = 0;
|
||||
if( aPg ){
|
||||
aPg[i++] = iPg;
|
||||
piFirst = &aPg[i];
|
||||
@ -1808,7 +1808,7 @@ static int seekInBtree(
|
||||
int iTry = (iMin+iMax)/2;
|
||||
void *pKeyT; int nKeyT; /* Key for cell iTry */
|
||||
int iTopicT; /* Topic for key pKeyT/nKeyT */
|
||||
Pgno iPtr; /* Pointer associated with cell iTry */
|
||||
LsmPgno iPtr; /* Pointer associated with cell iTry */
|
||||
int res; /* (pKey - pKeyT) */
|
||||
|
||||
rc = pageGetBtreeKey(
|
||||
@ -1899,7 +1899,7 @@ static int seekInLevel(
|
||||
int eSeek, /* Search bias - see above */
|
||||
int iTopic, /* Key topic to search for */
|
||||
void *pKey, int nKey, /* Key to search for */
|
||||
Pgno *piPgno, /* IN/OUT: fraction cascade pointer (or 0) */
|
||||
LsmPgno *piPgno, /* IN/OUT: fraction cascade pointer (or 0) */
|
||||
int *pbStop /* OUT: See above */
|
||||
){
|
||||
Level *pLvl = aPtr[0].pLevel; /* Level to seek within */
|
||||
@ -3055,7 +3055,7 @@ int lsmMCursorSeek(
|
||||
int bStop = 0; /* Set to true to halt search operation */
|
||||
int rc = LSM_OK; /* Return code */
|
||||
int iPtr = 0; /* Used to iterate through pCsr->aPtr[] */
|
||||
Pgno iPgno = 0; /* FC pointer value */
|
||||
LsmPgno iPgno = 0; /* FC pointer value */
|
||||
|
||||
assert( pCsr->apTreeCsr[0]==0 || iTopic==0 );
|
||||
assert( pCsr->apTreeCsr[1]==0 || iTopic==0 );
|
||||
@ -3537,7 +3537,7 @@ static int mergeWorkerLoadHierarchy(MergeWorker *pMW){
|
||||
** + Type byte (always SORTED_SEPARATOR or SORTED_SYSTEM_SEPARATOR),
|
||||
** + Absolute pointer value (varint),
|
||||
** + Number of bytes in key (varint),
|
||||
** + Blob containing key data.
|
||||
** + LsmBlob containing key data.
|
||||
**
|
||||
** 2. All pointer values are stored as absolute values (not offsets
|
||||
** relative to the footer pointer value).
|
||||
@ -3571,8 +3571,8 @@ static int mergeWorkerLoadHierarchy(MergeWorker *pMW){
|
||||
static int mergeWorkerBtreeWrite(
|
||||
MergeWorker *pMW,
|
||||
u8 eType,
|
||||
Pgno iPtr,
|
||||
Pgno iKeyPg,
|
||||
LsmPgno iPtr,
|
||||
LsmPgno iKeyPg,
|
||||
void *pKey,
|
||||
int nKey
|
||||
){
|
||||
@ -3682,7 +3682,7 @@ static int mergeWorkerBtreeWrite(
|
||||
static int mergeWorkerBtreeIndirect(MergeWorker *pMW){
|
||||
int rc = LSM_OK;
|
||||
if( pMW->iIndirect ){
|
||||
Pgno iKeyPg = pMW->aSave[1].iPgno;
|
||||
LsmPgno iKeyPg = pMW->aSave[1].iPgno;
|
||||
rc = mergeWorkerBtreeWrite(pMW, 0, pMW->iIndirect, iKeyPg, 0, 0);
|
||||
pMW->iIndirect = 0;
|
||||
}
|
||||
@ -3703,7 +3703,7 @@ static int mergeWorkerPushHierarchy(
|
||||
int nKey /* Size of pKey buffer in bytes */
|
||||
){
|
||||
int rc = LSM_OK; /* Return Code */
|
||||
Pgno iPtr; /* Pointer value to accompany pKey/nKey */
|
||||
LsmPgno iPtr; /* Pointer value to accompany pKey/nKey */
|
||||
|
||||
assert( pMW->aSave[0].bStore==0 );
|
||||
assert( pMW->aSave[1].bStore==0 );
|
||||
@ -3734,7 +3734,7 @@ static int mergeWorkerFinishHierarchy(
|
||||
){
|
||||
int i; /* Used to loop through apHier[] */
|
||||
int rc = LSM_OK; /* Return code */
|
||||
Pgno iPtr; /* New right-hand-child pointer value */
|
||||
LsmPgno iPtr; /* New right-hand-child pointer value */
|
||||
|
||||
iPtr = pMW->aSave[0].iPgno;
|
||||
for(i=0; i<pMW->hier.nHier && rc==LSM_OK; i++){
|
||||
@ -3830,7 +3830,7 @@ static int mergeWorkerPersistAndRelease(MergeWorker *pMW){
|
||||
*/
|
||||
static int mergeWorkerNextPage(
|
||||
MergeWorker *pMW, /* Merge worker object to append page to */
|
||||
Pgno iFPtr /* Pointer value for footer of new page */
|
||||
LsmPgno iFPtr /* Pointer value for footer of new page */
|
||||
){
|
||||
int rc = LSM_OK; /* Return code */
|
||||
Page *pNext = 0; /* New page appended to run */
|
||||
@ -3999,6 +3999,11 @@ static int mergeWorkerWrite(
|
||||
** marked read-only, advance to the next page of the output run. */
|
||||
iOff = pMerge->iOutputOff;
|
||||
if( iOff<0 || pPg==0 || iOff+nHdr > SEGMENT_EOF(nData, nRec+1) ){
|
||||
if( iOff>=0 && pPg ){
|
||||
/* Zero any free space on the page */
|
||||
assert( aData );
|
||||
memset(&aData[iOff], 0, SEGMENT_EOF(nData, nRec)-iOff);
|
||||
}
|
||||
iFPtr = (int)*pMW->pCsr->pPrevMergePtr;
|
||||
iRPtr = iPtr - iFPtr;
|
||||
iOff = 0;
|
||||
@ -4069,36 +4074,49 @@ static void mergeWorkerShutdown(MergeWorker *pMW, int *pRc){
|
||||
/* Unless the merge has finished, save the cursor position in the
|
||||
** Merge.aInput[] array. See function mergeWorkerInit() for the
|
||||
** code to restore a cursor position based on aInput[]. */
|
||||
if( rc==LSM_OK && pCsr && lsmMCursorValid(pCsr) ){
|
||||
if( rc==LSM_OK && pCsr ){
|
||||
Merge *pMerge = pMW->pLevel->pMerge;
|
||||
int bBtree = (pCsr->pBtCsr!=0);
|
||||
int iPtr;
|
||||
if( lsmMCursorValid(pCsr) ){
|
||||
int bBtree = (pCsr->pBtCsr!=0);
|
||||
int iPtr;
|
||||
|
||||
/* pMerge->nInput==0 indicates that this is a FlushTree() operation. */
|
||||
assert( pMerge->nInput==0 || pMW->pLevel->nRight>0 );
|
||||
assert( pMerge->nInput==0 || pMerge->nInput==(pCsr->nPtr+bBtree) );
|
||||
/* pMerge->nInput==0 indicates that this is a FlushTree() operation. */
|
||||
assert( pMerge->nInput==0 || pMW->pLevel->nRight>0 );
|
||||
assert( pMerge->nInput==0 || pMerge->nInput==(pCsr->nPtr+bBtree) );
|
||||
|
||||
for(i=0; i<(pMerge->nInput-bBtree); i++){
|
||||
SegmentPtr *pPtr = &pCsr->aPtr[i];
|
||||
if( pPtr->pPg ){
|
||||
pMerge->aInput[i].iPg = lsmFsPageNumber(pPtr->pPg);
|
||||
pMerge->aInput[i].iCell = pPtr->iCell;
|
||||
for(i=0; i<(pMerge->nInput-bBtree); i++){
|
||||
SegmentPtr *pPtr = &pCsr->aPtr[i];
|
||||
if( pPtr->pPg ){
|
||||
pMerge->aInput[i].iPg = lsmFsPageNumber(pPtr->pPg);
|
||||
pMerge->aInput[i].iCell = pPtr->iCell;
|
||||
}else{
|
||||
pMerge->aInput[i].iPg = 0;
|
||||
pMerge->aInput[i].iCell = 0;
|
||||
}
|
||||
}
|
||||
if( bBtree && pMerge->nInput ){
|
||||
assert( i==pCsr->nPtr );
|
||||
btreeCursorPosition(pCsr->pBtCsr, &pMerge->aInput[i]);
|
||||
}
|
||||
|
||||
/* Store the location of the split-key */
|
||||
iPtr = pCsr->aTree[1] - CURSOR_DATA_SEGMENT;
|
||||
if( iPtr<pCsr->nPtr ){
|
||||
pMerge->splitkey = pMerge->aInput[iPtr];
|
||||
}else{
|
||||
pMerge->aInput[i].iPg = 0;
|
||||
pMerge->aInput[i].iCell = 0;
|
||||
btreeCursorSplitkey(pCsr->pBtCsr, &pMerge->splitkey);
|
||||
}
|
||||
}
|
||||
if( bBtree && pMerge->nInput ){
|
||||
assert( i==pCsr->nPtr );
|
||||
btreeCursorPosition(pCsr->pBtCsr, &pMerge->aInput[i]);
|
||||
}
|
||||
|
||||
/* Store the location of the split-key */
|
||||
iPtr = pCsr->aTree[1] - CURSOR_DATA_SEGMENT;
|
||||
if( iPtr<pCsr->nPtr ){
|
||||
pMerge->splitkey = pMerge->aInput[iPtr];
|
||||
}else{
|
||||
btreeCursorSplitkey(pCsr->pBtCsr, &pMerge->splitkey);
|
||||
/* Zero any free space left on the final page. This helps with
|
||||
** compression if using a compression hook. And prevents valgrind
|
||||
** from complaining about uninitialized byte passed to write(). */
|
||||
if( pMW->pPage ){
|
||||
int nData;
|
||||
u8 *aData = fsPageData(pMW->pPage, &nData);
|
||||
int iOff = pMerge->iOutputOff;
|
||||
int iEof = SEGMENT_EOF(nData, pageGetNRec(aData, nData));
|
||||
memset(&aData[iOff], 0, iEof - iOff);
|
||||
}
|
||||
|
||||
pMerge->iOutputOff = -1;
|
||||
@ -4200,7 +4218,7 @@ static int mergeWorkerStep(MergeWorker *pMW){
|
||||
int rc = LSM_OK; /* Return code */
|
||||
int eType; /* SORTED_SEPARATOR, WRITE or DELETE */
|
||||
void *pKey; int nKey; /* Key */
|
||||
Pgno iPtr;
|
||||
LsmPgno iPtr;
|
||||
int iVal;
|
||||
|
||||
pCsr = pMW->pCsr;
|
||||
@ -4353,7 +4371,7 @@ static int sortedNewToplevel(
|
||||
if( rc!=LSM_OK ){
|
||||
lsmMCursorClose(pCsr, 0);
|
||||
}else{
|
||||
Pgno iLeftPtr = 0;
|
||||
LsmPgno iLeftPtr = 0;
|
||||
Merge merge; /* Merge object used to create new level */
|
||||
MergeWorker mergeworker; /* MergeWorker object for the same purpose */
|
||||
|
||||
@ -4530,7 +4548,7 @@ static int mergeWorkerInit(
|
||||
memset(pMW, 0, sizeof(MergeWorker));
|
||||
pMW->pDb = pDb;
|
||||
pMW->pLevel = pLevel;
|
||||
pMW->aGobble = lsmMallocZeroRc(pDb->pEnv, sizeof(Pgno) * pLevel->nRight, &rc);
|
||||
pMW->aGobble = lsmMallocZeroRc(pDb->pEnv, sizeof(LsmPgno)*pLevel->nRight,&rc);
|
||||
|
||||
/* Create a multi-cursor to read the data to write to the new
|
||||
** segment. The new segment contains:
|
||||
@ -4612,7 +4630,7 @@ static int sortedBtreeGobble(
|
||||
int rc = LSM_OK;
|
||||
if( rtTopic(pCsr->eType)==0 ){
|
||||
Segment *pSeg = pCsr->aPtr[iGobble].pSeg;
|
||||
Pgno *aPg;
|
||||
LsmPgno *aPg;
|
||||
int nPg;
|
||||
|
||||
/* Seek from the root of the b-tree to the segment leaf that may contain
|
||||
@ -4621,7 +4639,7 @@ static int sortedBtreeGobble(
|
||||
** gobbled up to (but not including) the first of these page numbers.
|
||||
*/
|
||||
assert( pSeg->iRoot>0 );
|
||||
aPg = lsmMallocZeroRc(pDb->pEnv, sizeof(Pgno)*32, &rc);
|
||||
aPg = lsmMallocZeroRc(pDb->pEnv, sizeof(LsmPgno)*32, &rc);
|
||||
if( rc==LSM_OK ){
|
||||
rc = seekInBtree(pCsr, pSeg,
|
||||
rtTopic(pCsr->eType), pCsr->key.pData, pCsr->key.nData, aPg, 0
|
||||
@ -5448,9 +5466,9 @@ int lsmFlushTreeToDisk(lsm_db *pDb){
|
||||
*/
|
||||
static char *segToString(lsm_env *pEnv, Segment *pSeg, int nMin){
|
||||
int nSize = pSeg->nSize;
|
||||
Pgno iRoot = pSeg->iRoot;
|
||||
Pgno iFirst = pSeg->iFirst;
|
||||
Pgno iLast = pSeg->iLastPg;
|
||||
LsmPgno iRoot = pSeg->iRoot;
|
||||
LsmPgno iFirst = pSeg->iFirst;
|
||||
LsmPgno iLast = pSeg->iLastPg;
|
||||
char *z;
|
||||
|
||||
char *z1;
|
||||
@ -5509,7 +5527,7 @@ static int fileToString(
|
||||
}
|
||||
|
||||
void sortedDumpPage(lsm_db *pDb, Segment *pRun, Page *pPg, int bVals){
|
||||
Blob blob = {0, 0, 0}; /* Blob used for keys */
|
||||
LsmBlob blob = {0, 0, 0}; /* LsmBlob used for keys */
|
||||
LsmString s;
|
||||
int i;
|
||||
|
||||
@ -5545,7 +5563,7 @@ void sortedDumpPage(lsm_db *pDb, Segment *pRun, Page *pPg, int bVals){
|
||||
aCell += lsmVarintGet32(aCell, &iPgPtr);
|
||||
|
||||
if( eType==0 ){
|
||||
Pgno iRef; /* Page number of referenced page */
|
||||
LsmPgno iRef; /* Page number of referenced page */
|
||||
aCell += lsmVarintGet64(aCell, &iRef);
|
||||
lsmFsDbPageGet(pDb->pFS, pRun, iRef, &pRef);
|
||||
aKey = pageGetKey(pRun, pRef, 0, &iTopic, &nKey, &blob);
|
||||
@ -5589,7 +5607,7 @@ static void infoCellDump(
|
||||
int *piPgPtr,
|
||||
u8 **paKey, int *pnKey,
|
||||
u8 **paVal, int *pnVal,
|
||||
Blob *pBlob
|
||||
LsmBlob *pBlob
|
||||
){
|
||||
u8 *aData; int nData; /* Page data */
|
||||
u8 *aKey; int nKey = 0; /* Key */
|
||||
@ -5607,7 +5625,7 @@ static void infoCellDump(
|
||||
|
||||
if( eType==0 ){
|
||||
int dummy;
|
||||
Pgno iRef; /* Page number of referenced page */
|
||||
LsmPgno iRef; /* Page number of referenced page */
|
||||
aCell += lsmVarintGet64(aCell, &iRef);
|
||||
if( bIndirect ){
|
||||
lsmFsDbPageGet(pDb->pFS, pSeg, iRef, &pRef);
|
||||
@ -5653,7 +5671,7 @@ static int infoAppendBlob(LsmString *pStr, int bHex, u8 *z, int n){
|
||||
|
||||
static int infoPageDump(
|
||||
lsm_db *pDb, /* Database handle */
|
||||
Pgno iPg, /* Page number of page to dump */
|
||||
LsmPgno iPg, /* Page number of page to dump */
|
||||
int flags,
|
||||
char **pzOut /* OUT: lsmMalloc'd string */
|
||||
){
|
||||
@ -5694,7 +5712,7 @@ static int infoPageDump(
|
||||
}
|
||||
|
||||
if( rc==LSM_OK ){
|
||||
Blob blob = {0, 0, 0, 0};
|
||||
LsmBlob blob = {0, 0, 0, 0};
|
||||
int nKeyWidth = 0;
|
||||
LsmString str;
|
||||
int nRec;
|
||||
@ -5729,7 +5747,7 @@ static int infoPageDump(
|
||||
u8 *aVal; int nVal = 0; /* Value */
|
||||
int iPgPtr;
|
||||
int eType;
|
||||
Pgno iAbsPtr;
|
||||
LsmPgno iAbsPtr;
|
||||
char zFlags[8];
|
||||
|
||||
infoCellDump(pDb, pSeg, bIndirect, pPg, iCell, &eType, &iPgPtr,
|
||||
@ -5795,7 +5813,7 @@ static int infoPageDump(
|
||||
|
||||
int lsmInfoPageDump(
|
||||
lsm_db *pDb, /* Database handle */
|
||||
Pgno iPg, /* Page number of page to dump */
|
||||
LsmPgno iPg, /* Page number of page to dump */
|
||||
int bHex, /* True to output key/value in hex form */
|
||||
char **pzOut /* OUT: lsmMalloc'd string */
|
||||
){
|
||||
@ -5971,8 +5989,8 @@ void lsmSortedExpandBtreePage(Page *pPg, int nOrig){
|
||||
#ifdef LSM_DEBUG_EXPENSIVE
|
||||
static void assertRunInOrder(lsm_db *pDb, Segment *pSeg){
|
||||
Page *pPg = 0;
|
||||
Blob blob1 = {0, 0, 0, 0};
|
||||
Blob blob2 = {0, 0, 0, 0};
|
||||
LsmBlob blob1 = {0, 0, 0, 0};
|
||||
LsmBlob blob2 = {0, 0, 0, 0};
|
||||
|
||||
lsmFsDbPageGet(pDb->pFS, pSeg, pSeg->iFirst, &pPg);
|
||||
while( pPg ){
|
||||
@ -6034,7 +6052,7 @@ static int assertPointersOk(
|
||||
int rc = LSM_OK; /* Error code */
|
||||
SegmentPtr ptr1; /* Iterates through pOne */
|
||||
SegmentPtr ptr2; /* Iterates through pTwo */
|
||||
Pgno iPrev;
|
||||
LsmPgno iPrev;
|
||||
|
||||
assert( pOne && pTwo );
|
||||
|
||||
@ -6057,7 +6075,7 @@ static int assertPointersOk(
|
||||
}
|
||||
|
||||
while( rc==LSM_OK && ptr2.pPg ){
|
||||
Pgno iThis;
|
||||
LsmPgno iThis;
|
||||
|
||||
/* Advance to the next page of segment pTwo that contains at least
|
||||
** one cell. Break out of the loop if the iterator reaches EOF. */
|
||||
@ -6119,7 +6137,7 @@ static int assertBtreeOk(
|
||||
){
|
||||
int rc = LSM_OK; /* Return code */
|
||||
if( pSeg->iRoot ){
|
||||
Blob blob = {0, 0, 0}; /* Buffer used to cache overflow keys */
|
||||
LsmBlob blob = {0, 0, 0}; /* Buffer used to cache overflow keys */
|
||||
FileSystem *pFS = pDb->pFS; /* File system to read from */
|
||||
Page *pPg = 0; /* Main run page */
|
||||
BtreeCursor *pCsr = 0; /* Btree cursor */
|
||||
|
88
ext/lsm1/tool/mklsm1c.tcl
Normal file
88
ext/lsm1/tool/mklsm1c.tcl
Normal file
@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
# restart with tclsh \
|
||||
exec tclsh "$0" "$@"
|
||||
|
||||
set srcdir [file dirname [file dirname [info script]]]
|
||||
set G(src) [string map [list %dir% $srcdir] {
|
||||
%dir%/lsm.h
|
||||
%dir%/lsmInt.h
|
||||
%dir%/lsm_vtab.c
|
||||
%dir%/lsm_ckpt.c
|
||||
%dir%/lsm_file.c
|
||||
%dir%/lsm_log.c
|
||||
%dir%/lsm_main.c
|
||||
%dir%/lsm_mem.c
|
||||
%dir%/lsm_mutex.c
|
||||
%dir%/lsm_shared.c
|
||||
%dir%/lsm_sorted.c
|
||||
%dir%/lsm_str.c
|
||||
%dir%/lsm_tree.c
|
||||
%dir%/lsm_unix.c
|
||||
%dir%/lsm_varint.c
|
||||
%dir%/lsm_win32.c
|
||||
}]
|
||||
|
||||
set G(hdr) {
|
||||
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_LSM1)
|
||||
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
||||
# define NDEBUG 1
|
||||
#endif
|
||||
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
|
||||
# undef NDEBUG
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
set G(footer) {
|
||||
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_LSM1) */
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Read and return the entire contents of text file $zFile from disk.
|
||||
#
|
||||
proc readfile {zFile} {
|
||||
set fd [open $zFile]
|
||||
set data [read $fd]
|
||||
close $fd
|
||||
return $data
|
||||
}
|
||||
|
||||
proc lsm1c_init {zOut} {
|
||||
global G
|
||||
set G(fd) stdout
|
||||
set G(fd) [open $zOut w]
|
||||
|
||||
puts -nonewline $G(fd) $G(hdr)
|
||||
}
|
||||
|
||||
proc lsm1c_printfile {zIn} {
|
||||
global G
|
||||
set data [readfile $zIn]
|
||||
set zTail [file tail $zIn]
|
||||
puts $G(fd) "#line 1 \"$zTail\""
|
||||
|
||||
foreach line [split $data "\n"] {
|
||||
if {[regexp {^# *include.*lsm} $line]} {
|
||||
set line "/* $line */"
|
||||
} elseif { [regexp {^(const )?[a-zA-Z][a-zA-Z0-9]* [*]?lsm[^_]} $line] } {
|
||||
set line "static $line"
|
||||
}
|
||||
puts $G(fd) $line
|
||||
}
|
||||
}
|
||||
|
||||
proc lsm1c_close {} {
|
||||
global G
|
||||
puts -nonewline $G(fd) $G(footer)
|
||||
if {$G(fd)!="stdout"} {
|
||||
close $G(fd)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lsm1c_init lsm1.c
|
||||
foreach f $G(src) { lsm1c_printfile $f }
|
||||
lsm1c_close
|
@ -47,9 +47,9 @@ static void rot13func(
|
||||
const unsigned char *zIn;
|
||||
int nIn;
|
||||
unsigned char *zOut;
|
||||
char *zToFree = 0;
|
||||
unsigned char *zToFree = 0;
|
||||
int i;
|
||||
char zTemp[100];
|
||||
unsigned char zTemp[100];
|
||||
assert( argc==1 );
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
zIn = (const unsigned char*)sqlite3_value_text(argv[0]);
|
||||
@ -57,7 +57,7 @@ static void rot13func(
|
||||
if( nIn<sizeof(zTemp)-1 ){
|
||||
zOut = zTemp;
|
||||
}else{
|
||||
zOut = zToFree = sqlite3_malloc( nIn+1 );
|
||||
zOut = zToFree = (unsigned char*)sqlite3_malloc64( nIn+1 );
|
||||
if( zOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
|
23
main.mk
23
main.mk
@ -263,6 +263,24 @@ FTS5_SRC = \
|
||||
$(TOP)/ext/fts5/fts5_varint.c \
|
||||
$(TOP)/ext/fts5/fts5_vocab.c \
|
||||
|
||||
LSM1_SRC = \
|
||||
$(TOP)/ext/lsm1/lsm.h \
|
||||
$(TOP)/ext/lsm1/lsmInt.h \
|
||||
$(TOP)/ext/lsm1/lsm_ckpt.c \
|
||||
$(TOP)/ext/lsm1/lsm_file.c \
|
||||
$(TOP)/ext/lsm1/lsm_log.c \
|
||||
$(TOP)/ext/lsm1/lsm_main.c \
|
||||
$(TOP)/ext/lsm1/lsm_mem.c \
|
||||
$(TOP)/ext/lsm1/lsm_mutex.c \
|
||||
$(TOP)/ext/lsm1/lsm_shared.c \
|
||||
$(TOP)/ext/lsm1/lsm_sorted.c \
|
||||
$(TOP)/ext/lsm1/lsm_str.c \
|
||||
$(TOP)/ext/lsm1/lsm_tree.c \
|
||||
$(TOP)/ext/lsm1/lsm_unix.c \
|
||||
$(TOP)/ext/lsm1/lsm_varint.c \
|
||||
$(TOP)/ext/lsm1/lsm_vtab.c \
|
||||
$(TOP)/ext/lsm1/lsm_win32.c
|
||||
|
||||
|
||||
# Generated source code files
|
||||
#
|
||||
@ -766,6 +784,10 @@ fts5.c: $(FTS5_SRC) $(FTS5_HDR)
|
||||
tclsh $(TOP)/ext/fts5/tool/mkfts5c.tcl
|
||||
cp $(TOP)/ext/fts5/fts5.h .
|
||||
|
||||
lsm1.c: $(LSM1_SRC)
|
||||
tclsh $(TOP)/ext/lsm1/tool/mklsm1c.tcl
|
||||
cp $(TOP)/ext/lsm1/lsm.h .
|
||||
|
||||
userauth.o: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
|
||||
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c
|
||||
|
||||
@ -1019,3 +1041,4 @@ clean:
|
||||
rm -f fuzzcheck fuzzcheck.exe
|
||||
rm -f sqldiff sqldiff.exe
|
||||
rm -f fts5.* fts5parse.*
|
||||
rm -f lsm.h lsm1.c
|
||||
|
131
manifest
131
manifest
@ -1,9 +1,9 @@
|
||||
C Merge\sall\sthe\slatest\schanges\sfrom\strunk.
|
||||
D 2017-11-15T16:29:02.752
|
||||
F Makefile.in b142eb20482922153ebc77b261cdfd0a560ed05a81e9f6d9a2b0e8192922a1d2
|
||||
C Bring\sin\sthe\slatest\strunk\schanges.
|
||||
D 2017-12-14T14:50:49.020
|
||||
F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc a55372a22454e742ba7c8f6edf05b83213ec01125166ad7dcee0567e2f7fc81b
|
||||
F README.md f5c87359573c4d255425e588a56554b50fdcc2afba4e017a2e02a43701456afd
|
||||
F Makefile.msc a2492b29176edc3c754aa7a2f7daa20cd3fa20a56e3ee64e376092836177c42a
|
||||
F README.md eeae1e552f93ef72ef7c5b8f6647b368a001c28820ad1df179d3dae602bef681
|
||||
F VERSION 0c10cdfed866fdd2d80434f64f042c3330f1daaed12e54287beb104f04b3faaf
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@ -11,7 +11,7 @@ F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 66c0befa511f0d95ba229e180067cf0357a9ebf8b3201b06d683c5ba6220fb39
|
||||
F autoconf/Makefile.msc 6143fe5b571cfeb0159702931d3ade664a00edc0c03814c7f6d825ae73eeffac
|
||||
F autoconf/Makefile.msc b88a70dee8453cc353e5d6df172d60a11a0af905710a24b1e6be80f8fea6e96b
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 8dd08ca564279fff091c9bfdd2599d8f992c9f1f70c5396de2126ad2bd1b3bed
|
||||
@ -30,8 +30,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure bdc49e9f0b0ced903ebdb2850362dd3391eeb88585e0429d12b94928d2873b6b x
|
||||
F configure.ac 369ebae6c04d9d2de5064e21d300f2f42f2fbf13235cabff9d1a54f2b2c4d05d
|
||||
F configure 9af547be0e0e1a8fca8553b82599b5a3be1528a3d78deb68cb49d3b611215cb7 x
|
||||
F configure.ac d4529ebb26ae046269334f1dac65f2b1d6927c2efe22b2ec24dce24dfe4f83dd
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 278113807f49d12d04179a93fab92b5b917a08771152ca7949d34e928efa3941
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
@ -99,13 +99,13 @@ F ext/fts3/unicode/mkunicode.tcl ab0543a3b2399092ea2dd75df1bef333405b0d7f6b8c495
|
||||
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7
|
||||
F ext/fts5/fts5Int.h 15e7514b46a845937d7c62e5c69e935091f0dbb72eb61aa4c8bcfbd39fdea158
|
||||
F ext/fts5/fts5Int.h eda28e3a0a5d87c412e8355fe35da875b04cb389908c8eb0d867ad662adbc491
|
||||
F ext/fts5/fts5_aux.c 67acf8d51723cf28ffc3828210ba662df4b8d267
|
||||
F ext/fts5/fts5_buffer.c 1dd1ec0446b3acfc2d7d407eb894762a461613e2695273f48e449bfd13e973ff
|
||||
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c f2825f714d91bbe62ab5820aee9ad12e0c94205b2a01725eaa9072415ae9ff1c
|
||||
F ext/fts5/fts5_expr.c 01048018d21524e2c302b063ff5c3cdcf546e03297215e577205d85b47499deb
|
||||
F ext/fts5/fts5_hash.c 32be400cf761868c9db33efe81a06eb19a17c5402ad477ee9efb51301546dd55
|
||||
F ext/fts5/fts5_index.c 2ce9d50ec5508b8205615aad69e1c9b2c77f017f21d4479e1fb2079c01fdd017
|
||||
F ext/fts5/fts5_index.c 5fe14375a29e8a7aa8f3e863babe180a19269206c254c8f47b216821d4ac1e15
|
||||
F ext/fts5/fts5_main.c 24868f88ab2a865defbba7a92eebeb726cc991eb092b71b5f5508f180c72605b
|
||||
F ext/fts5/fts5_storage.c fb5ef3c27073f67ade2e1bea08405f9e43f68f5f3676ed0ab7013bce5ba10be6
|
||||
F ext/fts5/fts5_tcl.c a7df39442ae674dde877cf06fe02ebb7658e69c179a4d223241c90df4f14b54e
|
||||
@ -115,7 +115,7 @@ F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
|
||||
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
|
||||
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
|
||||
F ext/fts5/fts5_vocab.c 1cd79854cb21543e66507b25b0578bc1b20aa6a1349b7feceb8e8fed0e7a77a6
|
||||
F ext/fts5/fts5parse.y a070b538e08ae9e2177d15c337ed2a3464408f0f886e746307098f746efd94ca
|
||||
F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841
|
||||
F ext/fts5/test/fts5aa.test cba3fae6466446980caf1b9f5f26df77f95a999d35db7d932d6e82ae7ba0ede9
|
||||
@ -162,8 +162,9 @@ F ext/fts5/test/fts5fault7.test 0acbec416edb24b8881f154e99c31e9ccf73f539cfcd1640
|
||||
F ext/fts5/test/fts5fault8.test 318238659d35f82ad215ecb57ca4c87486ea85d45dbeedaee42f148ff5105ee2
|
||||
F ext/fts5/test/fts5fault9.test 0111b229388bdf251b91cfead68580227801dd30960a19aa8fe9021a1e73cb6d
|
||||
F ext/fts5/test/fts5faultA.test be4487576bff8c22cee6597d1893b312f306504a8c6ccd3c53ca85af12290c8c
|
||||
F ext/fts5/test/fts5faultB.test 28810d93d37b59ebd5cf9502897f4dc9e6adb8ea6a5f64e125d3088597199d0d
|
||||
F ext/fts5/test/fts5faultB.test e6d04f9ea7b21be1d89abb8df2cb4baf65b0453b744d5a805fcd3ef45ff86a7e
|
||||
F ext/fts5/test/fts5faultD.test cc5d1225556e356615e719c612e845d41bff7d5a
|
||||
F ext/fts5/test/fts5first.test 707a591b1b7d893fcfcb2366cbfe56aefab5d9c7cfa58bef35eba73a1dbf3b29
|
||||
F ext/fts5/test/fts5full.test 49b565da02918c06e58f51f0b953b0302b96f155aa68baba24782b81570685e2
|
||||
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
|
||||
F ext/fts5/test/fts5hash.test a4cf51acad99bfc43c16fb74f9d22495dc221ae0701fc5e908ca963a9b26a02b
|
||||
@ -182,7 +183,7 @@ F ext/fts5/test/fts5plan.test e30e8378441114ef6977a3dc24ecd203caa670d782124dfc9a
|
||||
F ext/fts5/test/fts5porter.test 8d08010c28527db66bc3feebd2b8767504aaeb9b101a986342fa7833d49d0d15
|
||||
F ext/fts5/test/fts5porter2.test 0d251a673f02fa13ca7f011654873b3add20745f7402f108600a23e52d8c7457
|
||||
F ext/fts5/test/fts5prefix.test a0fa67b06650f2deaa7bf27745899d94e0fb547ad9ecbd08bfad98c04912c056
|
||||
F ext/fts5/test/fts5query.test bdb6fd9e73268cfc07f789f1448cd71ea78acb02e481c619f286289ea18ca518
|
||||
F ext/fts5/test/fts5query.test ac363b17a442620bb0780e93c24f16a5f963dfe2f23dc85647b869efcfada728
|
||||
F ext/fts5/test/fts5rank.test 6e149da77a269923a8439aaa52366e49b85be4721902662da39a5ded16ed85d9
|
||||
F ext/fts5/test/fts5rebuild.test 6d09fd54b1170a1e54fe17b808bbf17fba3154956cc2f065dd94bf1e3d254f63
|
||||
F ext/fts5/test/fts5restart.test 835ecc8f449e3919f72509ab58056d0cedca40d1fe04108ccf8ac4c2ba41f415
|
||||
@ -209,7 +210,7 @@ F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
|
||||
F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
|
||||
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
||||
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c 635775226d07c743c770888a9dd5175afc6e67d3e28a4032b7fedc3bcaa92e65
|
||||
F ext/icu/icu.c c2c7592574c08cd1270d909b8fb8797f6ea1f49e931e71dbcc25506b9b224580
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/lsm1/Makefile 98b0a24b45e248283d6bea4b6cb3e58d7b394edd8e96a0ac28c5fa5104813bad
|
||||
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
|
||||
@ -238,15 +239,15 @@ F ext/lsm1/lsm-test/lsmtest_tdb4.c 47e8bb5eba266472d690fb8264f1855ebdba0ae5a0e54
|
||||
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
|
||||
F ext/lsm1/lsm-test/lsmtest_win32.c 0e0a224674c4d3170631c41b026b56c7e1672b151f5261e1b4cc19068641da2d
|
||||
F ext/lsm1/lsm.h 0f6f64ff071471cb87bf98beb8386566f30ea001
|
||||
F ext/lsm1/lsmInt.h e9e5c5f08e35a104086102b3def94ee69cbc0d39002f6596f5c80a640439628e
|
||||
F ext/lsm1/lsm_ckpt.c ac6fb4581983291c2e0be6fbb68f12b26f0c08d606835c05417be1323d0fdd03
|
||||
F ext/lsm1/lsm_file.c 4b3fb56336fbc9d941e1b2042e809d986feebdc41e73dc7fc4fdc0dd1bd4274d
|
||||
F ext/lsm1/lsmInt.h 5983690e05e83653cc01ba9d8fbf8455e534ddf8349ed9adedbf46a7549760b0
|
||||
F ext/lsm1/lsm_ckpt.c 0eabfaf812ddb4ea43add38f05e430694cd054eb622c3e35af4c43118a2d5321
|
||||
F ext/lsm1/lsm_file.c 3c51841d5b3e7da162693cbac9a9f47eeedf6bcbbe2969a4d25e30c428c9fe36
|
||||
F ext/lsm1/lsm_log.c a8bf334532109bba05b09a504ee45fc393828b0d034ca61ab45e3940709d9a7c
|
||||
F ext/lsm1/lsm_main.c 15e73ccdafdd44ddeefc29e332079d88ba8f00c12c797b3c2b63d3171b5afce8
|
||||
F ext/lsm1/lsm_main.c 801295038b548ae2e5fae93f08c3f945154f40848a03ff26b16eab5d04ba573a
|
||||
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
|
||||
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
|
||||
F ext/lsm1/lsm_shared.c 76adfc1ed9ffebaf92746dde4b370ccc48143ca8b05b563816eadd2aadf1c525
|
||||
F ext/lsm1/lsm_sorted.c a04518dfbfff0171fafb152a46e9fe9f45e1edbf3570e4533dd58ddb6567f0c9
|
||||
F ext/lsm1/lsm_sorted.c d07ff7c28758542b8b4da4b5a1fb67b22a4d33e50e7f684cffe1f6c45cf5182c
|
||||
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
|
||||
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
|
||||
F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
|
||||
@ -255,6 +256,7 @@ F ext/lsm1/lsm_vtab.c 529255dc704289001b225d97e57e0cfa14b29c3f281c7349cfa8fdb655
|
||||
F ext/lsm1/lsm_win32.c 0a4acbd7e8d136dd3a5753f0a9e7a9802263a9d96cef3278cf120bcaa724db7c
|
||||
F ext/lsm1/test/lsm1_common.tcl 5ed4bab07c93be2e4f300ebe46007ecf4b3e20bc5fbe1dedaf04a8774a6d8d82
|
||||
F ext/lsm1/test/lsm1_simple.test ca949efefa102f4644231dcd9291d8cda7699a4ce1006b26e0e3fcb72233f422
|
||||
F ext/lsm1/tool/mklsm1c.tcl f31561bbee5349f0a554d1ad7236ac1991fc09176626f529f6078e07335398b0
|
||||
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
|
||||
F ext/misc/amatch.c 6db4607cb17c54b853a2d7c7c36046d004853f65b9b733e6f019d543d5dfae87
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
@ -277,7 +279,7 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
|
||||
F ext/misc/regexp.c a68d25c659bd2d893cd1215667bbf75ecb9dc7d4
|
||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/rot13.c 540a169cb0d74f15522a8930b0cccdcb37a4fd071d219a5a083a319fc6e8db77
|
||||
F ext/misc/scrub.c 1c5bfb8b0cd18b602fcb55755e84abf0023ac2fb
|
||||
F ext/misc/series.c f3c0dba5c5c749ce1782b53076108f87cf0b71041eb6023f727a9c50681da564
|
||||
F ext/misc/sha1.c 0b9e9b855354910d3ca467bf39099d570e73db56
|
||||
@ -394,7 +396,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk fbe15be384ec172be0cc30efc91cda61ca16bd5d833e8b812cf653ccb0c74977
|
||||
F main.mk 6123b0b2db806ddb482c24786ad6603a289df720382a3bce8f532d76a94c84b1
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@ -413,18 +415,18 @@ F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 75229a5a47985997f861b428552acd14fe42b657f755cba5e0b1a007bd77b2ea
|
||||
F src/btree.c b83a6b03f160528020bb965f0c3a40af5286cd4923c3870fd218177f03a120a7
|
||||
F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09
|
||||
F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc
|
||||
F src/build.c 514db9d494ed29155e552f2ec2fa7c55c0241f847c683156b7c017f4b0bad9fa
|
||||
F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f308688
|
||||
F src/build.c 87b68e3b45559ec404b12f095f0ba5f06f91a6dd2d21bd8443e41d8ac2e67196
|
||||
F src/callback.c fe677cb5f5abb02f7a772a62a98c2f516426081df68856e8f2d5f950929b966a
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
||||
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
||||
F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
|
||||
F src/dbpage.c 8db4c97f630e7d83f884ea75caf1ffd0988c160e9d530194d93721c80821e0f6
|
||||
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
||||
F src/delete.c e6a70fb58f6628f0ffc6d7221a6702c0d7b342c82520385b3996b364c22e0cb3
|
||||
F src/expr.c 5257a9157f22f048ddcce5cd494d39633e89c2a4769671311b3e7875d262f746
|
||||
F src/delete.c 74667ad914ac143731a444a1bacf29ceb18f6eded8a0dd17aafae80baa07f8bb
|
||||
F src/expr.c fe11b91bb65b869143bd42023427c4429778ae42c0a0db7762f68f75b347a958
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
|
||||
F src/func.c 0fb9a2d678d3c8aba89b46468b309cd7e8fa9806a369a30aa89024660845bb13
|
||||
@ -436,7 +438,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c cb67cc56ef2ddd13e6944b2c0dd08a920bcd9503230adef8b9928d338097c722
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
|
||||
F src/main.c c1965ee8159cee5fba3f590cc4767515a690504455a03e4817b1accfe0ba95a5
|
||||
F src/main.c 4f94536a61dc77477e1cee7ecfae2896778c1a3d3de4f978db28f8b9220f6e52
|
||||
F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@ -445,7 +447,7 @@ F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
F src/memjournal.c 6f3d36a0a8f72f48f6c3c722f04301ac64f2515435fa42924293e46fc7994661
|
||||
F src/msvc.h 4942752b6a253116baaa8de75256c51a459a5e81
|
||||
F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
|
||||
F src/mutex.c b021263554c8a3995e9d53193b8194b96d1ed28e06c3b532dd7f7d29cf0c7d53
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
||||
F src/mutex_unix.c 27bb6cc49485ee46711a6580ab7b3f1402211d23
|
||||
@ -455,8 +457,8 @@ F src/os.c 22d31db3ca5a96a408fbf1ceeaaebcaf64c87024d2ff9fe1cf2ddbec3e75c104
|
||||
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c e87cef0bb894b94d96ee3af210be669549d111c580817d14818101b992640767
|
||||
F src/os_win.c 7f36120492e4a23c48d1dd685edf29ae459c6d555660c61f1323cea3e5a1191d
|
||||
F src/os_unix.c 7fc2735390a7809d5d893ed735d994ff12521224b89738226fff6f1a0aa1c932
|
||||
F src/os_win.c 0a4afa35cc8e812000df3ea2f64b476131b39e29e75d8007d0504726e4761de4
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
|
||||
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
|
||||
@ -466,17 +468,17 @@ F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||
F src/pragma.c d04725ac25387d9638919e197fb009f378e13af7bf899516979e54b3164e3602
|
||||
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/prepare.c 7cf451f903ad92a14e22de415a13e7a7d30f1bd23b3d21eeb0dc7264723244c5
|
||||
F src/prepare.c 259f4e7960c47082c9653f3d5f0c294abd68bb9c3aab86de7630700cba1c20fb
|
||||
F src/printf.c 9506b4b96e59c0467047155f09015750cb2878aeda3d39e5610c1192ddc3c41c
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 17e220191860a64a18c084141e1a8b7309e166a6f2d42c02021af27ea080d157
|
||||
F src/shell.c.in 08cbffc31900359fea85896342a46147e9772c370d8a5079b7be26e3a1f50e8a
|
||||
F src/sqlite.h.in 8fd97993d48b50b9bade38c52f12d175942c9497c960905610c7b03a3e4b5818
|
||||
F src/shell.c.in 6ffed0c589f5aff180789a8c8abf5b2d3e2eea7470c86b30e797887cb0c9d0e5
|
||||
F src/sqlite.h.in 364515dd186285f3c01f5cab42e7db7edc47c70e87b6a25de389a2e6b8c413fd
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
|
||||
F src/sqliteInt.h fb297e4b891608057e857d583e30a261d905a3f41493f351fc91bae7d22008ff
|
||||
F src/sqliteInt.h 55b8e7da85947eb61b13d4d2523ccdda7800a13e987c3fc4ca73d8518bbf02fa
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -496,7 +498,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
|
||||
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
|
||||
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c 3000f00b9b47b149d842059904c3fcab5f3871fb6aee7d7cc5756f0c64779ae3
|
||||
F src/test_config.c 3904a8682aac58b77d20ca236face2b11e50781be4116004ba1ba79f69896ec9
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
|
||||
F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
|
||||
@ -535,7 +537,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
|
||||
F src/treeview.c 08a83195de8fad3f00542e3c8b3c1eb1222c999817c9e301ffb7f332882b96dd
|
||||
F src/trigger.c fc6be2a6e103d9e38b161e07d7db0ffb1f2218bd2f27ccdc0a3d1cc89e9cea0f
|
||||
F src/trigger.c 775053eecf6b73062e243404b56f5064446254d5cce17d8704d5cdffd72a546a
|
||||
F src/update.c 961bd1265d4d1e5cd65c9a54fa5122fb7aefcb003fcf2de0c092fceb7e58972c
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c d01fa6f45bfad3b65fb2490513aa2e0676412c61b4b094340b513cf72c3704a4
|
||||
@ -544,19 +546,19 @@ F src/vdbe.c 3393b508d9ad084ffce232a7c53e375ef5ac99b50b685c5131fcdfce97a9d534
|
||||
F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
|
||||
F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9
|
||||
F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1
|
||||
F src/vdbeaux.c 9521a9364e68edad3c8d05ae63395d076724bed1c878c9b13fab61ada54e7d2a
|
||||
F src/vdbeaux.c b02a1f842c0e916285643b8475b7189f10b76f9e7edb5e2353a913c7980f90b5
|
||||
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
|
||||
F src/vdbemem.c 2ef9e66b301a1e575e32966c4c0fd4844e8eea37a2f02bae78c4f68f50a6ab30
|
||||
F src/vdbemem.c 8478f7fb1948bf8fdeec7c2cb59ea58155c31258b9cd43c56d485e03ed40bd07
|
||||
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
|
||||
F src/vdbetrace.c 48e11ebe040c6b41d146abed2602e3d00d621d7ebe4eb29b0a0f1617fd3c2f6c
|
||||
F src/vtab.c 0e4885495172e1bdf54b12cce23b395ac74ef5729031f15e1bc1e3e6b360ed1a
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c beeb71e4eab65dbf0d95f2717efc6ca3c0f5b3090ce67f3de63828f39a6ff053
|
||||
F src/wal.c 5a3f464edd64596f601683ed321d12e6fd93c5fb9afdfb3653d6ffd0fee9c48f
|
||||
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||
F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
|
||||
F src/where.c 031a80bcafe93934fd7052f3031c9e7eb36b61754c6c84d6bf0833184abad3db
|
||||
F src/where.c ee9dd4a438a07cd364c8449e834db4c4d6163a2576a69e937d7a4c37685612a2
|
||||
F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
|
||||
F src/wherecode.c 4a117dd5886616d074f7b6589c23bf742f5a9858d6ffdaf8b9d1f76ab06245d2
|
||||
F src/wherecode.c ff2f079097a3bdce6ebabfde1419fba448c9ce5feb7cb964e8bfa2a4e27274ef
|
||||
F src/whereexpr.c 427ea8e96ec24f2a7814c67b8024ad664a9c7656264c4566c34743cb23186e46
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@ -736,7 +738,7 @@ F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test a1783b960ad8c15a77cd9f207be072898db1026c
|
||||
F test/distinct2.test faef8a3f27424e2cfbe19b2a40752294de3b5d957e049e3336be53ec0476cb58
|
||||
F test/distinct2.test df0bb52b754661ea84ec9ff488d48913c97bd31d83ca17ce0bf1334645e660cf
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_blobbytes.test 439a945953b35cb6948a552edaec4dc31fd70a05
|
||||
F test/e_blobclose.test 4b3c8c60c2171164d472059c73e9f3c1844bb66d
|
||||
@ -787,7 +789,7 @@ F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a
|
||||
F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
|
||||
F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13
|
||||
F test/fkey7.test 24076d43d3449f12f25503909ca4bfb5fc5fefd5af1f930723a496343eb28454
|
||||
F test/fkey8.test e5372e32cdb4481f121ec3550703eeb7b4e0762c
|
||||
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
|
||||
F test/fordelete.test eb93a2f34137bb87bdab88fcab06c0bd92719aff
|
||||
@ -932,7 +934,7 @@ F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
|
||||
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
|
||||
F test/icu.test 73956798bace8982909c00476b216714a6d0559a
|
||||
F test/icu.test 7fb00edc09e05d51e36be12b33e0af04e3394e3b02dbdcb2eefcb901203e28c4
|
||||
F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
|
||||
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
|
||||
F test/in.test 2fa2dfba1afe30eb830f327e7131dfadaa7a701d677de0eb65f9303d99e18fe0
|
||||
@ -984,7 +986,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/join.test 442c462eea85cf065d70a663c626b780a95af6e11585d909bb63b87598afe678
|
||||
F test/join2.test a48f723c5692e2cbb23a9297ac2720cb77d51a70
|
||||
F test/join2.test 1a0c26399910b015d9f8f95b884e9a079fd2cfdccd65f7b1603846508cae0dc6
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test bc98ea4b4e5003f5b1453701ebb8cd7d1c01a550
|
||||
@ -1007,7 +1009,7 @@ F test/like.test 11cfd7d4ef8625389df9efc46735ff0b0b41d5e62047ef0f3bc24c380d28a7a
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/like3.test 3608a2042b6f922f900fbfd5d3ce4e7eca57f7c4
|
||||
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
|
||||
F test/limit2.test e35f57bd3a62d7c5dcb5ac4306e675c75f974809
|
||||
F test/limit2.test 360982809e03211636d2b18ddbc97d5da06826941370607e4b00e113f827cb5a
|
||||
F test/loadext.test d077450695ddb5c1ea3ad7d48e5f5850fe732ad9
|
||||
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
|
||||
F test/lock.test be4fe08118fb988fed741f429b7dd5d65e1c90db
|
||||
@ -1063,7 +1065,7 @@ F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2
|
||||
F test/misc8.test ba03aaa08f02d62fbb8d3b2f5595c1b33aa9bbc5
|
||||
F test/misuse.test 9e7f78402005e833af71dcab32d048003869eca5abcaccc985d4f8dc1d86bcc7
|
||||
F test/mjournal.test 68b749956f9a179e7e633a3958b48a5a905d28d30c7ec88f3f26dc6f220129db
|
||||
F test/mjournal.test 9d86e697dcbc5da2c4e8caba9b176b5765fe65e80c88c278b8c09a917e436795
|
||||
F test/mmap1.test d2cfc1635171c434dcff0ece2f1c8e0a658807ce
|
||||
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
|
||||
F test/mmap3.test b3c297e78e6a8520aafcc1a8f140535594c9086e
|
||||
@ -1173,7 +1175,7 @@ F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
|
||||
F test/schema4.test 3b26c9fa916abb6dadf894137adcf41b7796f7b9
|
||||
F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e
|
||||
F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce1f9b
|
||||
F test/securedel.test 5f997cb6bd38727b81e0985f53ec386c99db6441b2b9e6357240649d29017239
|
||||
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
|
||||
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test 460a5824df01575b18f7fa4bd8e40d09de20c542e90c1543e164bc7d3b0a0bb7
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
@ -1210,7 +1212,7 @@ F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1
|
||||
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
|
||||
F test/shell5.test 23939a4c51f0421330ea61dbd3c74f9c215f5f8d3d1a94846da6ffc777a35458
|
||||
F test/shell6.test ab1592ebe881371f651f18ee6a0df21cbfb5310f88cb832ab642d4038f679772
|
||||
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
|
||||
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@ -1223,6 +1225,7 @@ F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
|
||||
F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b
|
||||
F test/snapshot.test 85735bd997a4f6d710140c28fd860519a299649f
|
||||
F test/snapshot2.test 925e42427e923262db63c9d7155183f889e3e99feaedec4075f659e51608344f
|
||||
F test/snapshot3.test 9719443594a04778861bd20d12596c5f880af177d6cd62f111da3198cafc6096
|
||||
F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
|
||||
@ -1250,7 +1253,7 @@ F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
|
||||
F test/stat.test f8f1279ffffabe6df825723af18cc6e0ae70a893
|
||||
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
|
||||
F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f
|
||||
F test/stmtvtab1.test acc3c40f484f2c4922e270724383d715abb9d69676da907a9c64f31c54f2ef9f
|
||||
F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b359468e2d5
|
||||
F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49
|
||||
F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
|
||||
F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f
|
||||
@ -1293,7 +1296,7 @@ F test/threadtest3.c 38a612ea62854349ed66372f330a40d73c5cf956
|
||||
F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925
|
||||
F test/time-wordcount.sh 8e0b0f8109367827ad5d58f5cc849705731e4b90
|
||||
F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c
|
||||
F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660
|
||||
F test/tkt-26ff0c2d1e.test c15bec890c4d226c0da2f35ff30f9e84c169cfef90e73a8cb5cec11d723dfa96
|
||||
F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2
|
||||
F test/tkt-2d1a5c67d.test be1326f3061caec85085f4c9ee4490561ca037c0
|
||||
F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
|
||||
@ -1315,7 +1318,7 @@ F test/tkt-5ee23731f.test 9db6e1d7209dc0794948b260d6f82b2b1de83a9f
|
||||
F test/tkt-6bfb98dfc0.test 24780633627b5cfc0635a5500c2389ebfb563336
|
||||
F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf
|
||||
F test/tkt-78e04e52ea.test 1b2e6bf4f1d9887b216b6da774e5f25915ec8118
|
||||
F test/tkt-7a31705a7e6.test e75a2bba4eec801b92c8040eb22096ac6d35e844
|
||||
F test/tkt-7a31705a7e6.test 9e9c057b6a9497c8f7ba7b16871029414ccf6550e7345d9085d6d71c9a56bb6f
|
||||
F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18
|
||||
F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8
|
||||
F test/tkt-80e031a00f.test 9ee36348b761bf7c14261e002b75a4c0d5a04d4c
|
||||
@ -1328,7 +1331,7 @@ F test/tkt-9a8b09f8e6.test b2ef151d0984b2ebf237760dbeaa50724e5a0667
|
||||
F test/tkt-9d68c883.test 16f7cb96781ba579bc2e19bb14b4ad609d9774b6
|
||||
F test/tkt-9f2eb3abac.test cb6123ac695a08b4454c3792fbe85108f67fabf8
|
||||
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
|
||||
F test/tkt-a8a0d2996a.test eb597379dbcefa24765763d7f682c00cb5924fa9
|
||||
F test/tkt-a8a0d2996a.test 76662ff0622c90e7ce7bbcb4d9e1129acddf877d17c3489f2da7f17ddfaad1f4
|
||||
F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550
|
||||
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
|
||||
F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
|
||||
@ -1392,7 +1395,7 @@ F test/tkt3121.test 536df66a02838c26a12fe98639354ca1290ca68b
|
||||
F test/tkt3201.test f1500ccecc0d578dc4cde7d3242008297c4d59b3
|
||||
F test/tkt3292.test 962465a0984a3b8c757efe59c2c59144871ee1dd
|
||||
F test/tkt3298.test 20fd8773b825cb602e033aa04f8602e1ebdcd93c
|
||||
F test/tkt3334.test ea13a53cb176e90571a76c86605b14a09efe366d
|
||||
F test/tkt3334.test 9756631e3c4aa3c416362c279e3c0953a83b7ca8274cb81a13264bb56296d8b0
|
||||
F test/tkt3346.test 6f67c3ed7db94dfc5df4f5f0b63809a1f611e01a
|
||||
F test/tkt3357.test 77c37c6482b526fe89941ce951c22d011f5922ed
|
||||
F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b
|
||||
@ -1456,7 +1459,7 @@ F test/triggerC.test 302d8995f5ffe63bbc15053abb3ef7a39cf5a092
|
||||
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
|
||||
F test/triggerE.test 15fa63f1097db1f83dd62d121616006978063d1f
|
||||
F test/triggerF.test 6a8c22bd058cf467f0c7d112afe87f7a8c579c0c4681b914b8f19020f48528a4
|
||||
F test/triggerG.test 175cafdc6399d85231a09e82e051b0e45a2fd1f23dd08ae715bc359716149ab6
|
||||
F test/triggerG.test d5caeef6144ede2426dd13211fd72248241ff2ebc68e12a4c0bf30f5faa21499
|
||||
F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1
|
||||
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
|
||||
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
|
||||
@ -1480,10 +1483,10 @@ F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
|
||||
F test/vacuum2.test aa048abee196c16c9ba308465494009057b79f9b
|
||||
F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
|
||||
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7c010
|
||||
F test/vacuum5.test c87234e8ca4107f349da4edbeda3e4ea5adc93f3
|
||||
F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test 765802c7a66d37fabd5ac8e2f2dbe572b43eb9ab
|
||||
F test/vtab1.test 8f91b9538d1404c3932293a588c4344218a0c94792d4289bb55e41020e7b3fff
|
||||
@ -1532,9 +1535,9 @@ F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c
|
||||
F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
|
||||
F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03
|
||||
F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6
|
||||
F test/walprotocol.test 0b92feb132ccebd855494d917d3f6c2d717ace20
|
||||
F test/walprotocol.test a112aba0b79e3adeaa485fed09484b32c654e97df58e454aa8489ac2cd57bf84
|
||||
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
|
||||
F test/walro2.test 8812e514c968bf4ee317571fafedac43443360ae23edd7d0f4ef1eae0c13e8e8
|
||||
F test/walro2.test 5cd57d192ee334c3894330303b5f8cb6789fef49b2c83ad1b50b9b132d0f7ae1
|
||||
F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
|
||||
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
|
||||
@ -1678,7 +1681,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 063a03a3779e8c032dd006712facaaa6d60964425701ea10c753ff981a8f2bd9 3925facd942c9df663f9b29b1e6f94f6be14af8c2b99eb691bfc836b4c220826
|
||||
R c7a14dabad9b6d1a92ae6a806b590590
|
||||
P 1a1a73b821eb1a22ca335f582a0aea31c71ca9f5b09d54f26409691c90e38c4a 3765aaf712998af5ffb6bc680a0c1419f2b5deb47ecbc1835ba5879127c4dbe3
|
||||
R 29a07f33957881a5b837419ff7f21683
|
||||
U drh
|
||||
Z afc7a4b7b3683c496a44306e363185c7
|
||||
Z d18bd4436a6dfca865f7b12ca3ce5865
|
||||
|
@ -1 +1 @@
|
||||
1a1a73b821eb1a22ca335f582a0aea31c71ca9f5b09d54f26409691c90e38c4a
|
||||
75d8517703f7efa33437079108e2c4ef0de1a118bbe1f4a86afdc34da09d3008
|
91
src/btree.c
91
src/btree.c
@ -112,6 +112,31 @@ int sqlite3_enable_shared_cache(int enable){
|
||||
#define hasReadConflicts(a, b) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single
|
||||
** (MemPage*) as an argument. The (MemPage*) must not be NULL.
|
||||
**
|
||||
** If SQLITE_DEBUG is not defined, then this macro is equivalent to
|
||||
** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message
|
||||
** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented
|
||||
** with the page number and filename associated with the (MemPage*).
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int corruptPageError(int lineno, MemPage *p){
|
||||
char *zMsg = sqlite3_mprintf("database corruption page %d of %s",
|
||||
(int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
|
||||
);
|
||||
if( zMsg ){
|
||||
sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
|
||||
}
|
||||
sqlite3_free(zMsg);
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)
|
||||
#else
|
||||
# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@ -1400,7 +1425,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
int sz = get2byte(&data[iFree+2]);
|
||||
int top = get2byte(&data[hdr+5]);
|
||||
if( top>=iFree ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
if( iFree2 ){
|
||||
assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
|
||||
@ -1434,13 +1459,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
** if PRAGMA cell_size_check=ON.
|
||||
*/
|
||||
if( pc<iCellFirst || pc>iCellLast ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( pc>=iCellFirst && pc<=iCellLast );
|
||||
size = pPage->xCellSize(pPage, &src[pc]);
|
||||
cbrk -= size;
|
||||
if( cbrk<iCellFirst || pc+size>usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
|
||||
testcase( cbrk+size==usableSize );
|
||||
@ -1460,7 +1485,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
|
||||
defragment_out:
|
||||
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( cbrk>=iCellFirst );
|
||||
put2byte(&data[hdr+5], cbrk);
|
||||
@ -1504,7 +1529,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
||||
testcase( x==4 );
|
||||
testcase( x==3 );
|
||||
if( size+pc > usableSize ){
|
||||
*pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
|
||||
*pRc = SQLITE_CORRUPT_PAGE(pPg);
|
||||
return 0;
|
||||
}else if( x<4 ){
|
||||
/* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
|
||||
@ -1527,7 +1552,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
||||
if( pc<iAddr+size ) break;
|
||||
}
|
||||
if( pc ){
|
||||
*pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
|
||||
*pRc = SQLITE_CORRUPT_PAGE(pPg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1575,7 +1600,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
if( top==0 && pPage->pBt->usableSize==65536 ){
|
||||
top = 65536;
|
||||
}else{
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1665,12 +1690,12 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
|
||||
if( iFreeBlk<iPtr+4 ){
|
||||
if( iFreeBlk==0 ) break;
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
iPtr = iFreeBlk;
|
||||
}
|
||||
if( iFreeBlk>pPage->pBt->usableSize-4 ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( iFreeBlk>iPtr || iFreeBlk==0 );
|
||||
|
||||
@ -1682,10 +1707,10 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
*/
|
||||
if( iFreeBlk && iEnd+3>=iFreeBlk ){
|
||||
nFrag = iFreeBlk - iEnd;
|
||||
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
|
||||
if( iEnd > pPage->pBt->usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
iSize = iEnd - iStart;
|
||||
iFreeBlk = get2byte(&data[iFreeBlk]);
|
||||
@ -1698,13 +1723,13 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
if( iPtr>hdr+1 ){
|
||||
int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
|
||||
if( iPtrEnd+3>=iStart ){
|
||||
if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
nFrag += iStart - iPtrEnd;
|
||||
iSize = iEnd - iPtr;
|
||||
iStart = iPtr;
|
||||
}
|
||||
}
|
||||
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
data[hdr+7] -= nFrag;
|
||||
}
|
||||
x = get2byte(&data[hdr+5]);
|
||||
@ -1712,7 +1737,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
/* The new freeblock is at the beginning of the cell content area,
|
||||
** so just extend the cell content area rather than create another
|
||||
** freelist entry */
|
||||
if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
put2byte(&data[hdr+1], iFreeBlk);
|
||||
put2byte(&data[hdr+5], iEnd);
|
||||
}else{
|
||||
@ -1785,7 +1810,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
}else{
|
||||
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
|
||||
** an error. */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
pPage->max1bytePayload = pBt->max1bytePayload;
|
||||
return SQLITE_OK;
|
||||
@ -1826,7 +1851,7 @@ static int btreeInitPage(MemPage *pPage){
|
||||
/* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
|
||||
** the b-tree page type. */
|
||||
if( decodeFlags(pPage, data[hdr]) ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
|
||||
pPage->maskPage = (u16)(pBt->pageSize - 1);
|
||||
@ -1845,7 +1870,7 @@ static int btreeInitPage(MemPage *pPage){
|
||||
pPage->nCell = get2byte(&data[hdr+3]);
|
||||
if( pPage->nCell>MX_CELL(pBt) ){
|
||||
/* To many cells for a single page. The page must be corrupt */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
testcase( pPage->nCell==MX_CELL(pBt) );
|
||||
/* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
|
||||
@ -1873,12 +1898,12 @@ static int btreeInitPage(MemPage *pPage){
|
||||
testcase( pc==iCellFirst );
|
||||
testcase( pc==iCellLast );
|
||||
if( pc<iCellFirst || pc>iCellLast ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
sz = pPage->xCellSize(pPage, &data[pc]);
|
||||
testcase( pc+sz==usableSize );
|
||||
if( pc+sz>usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
if( !pPage->leaf ) iCellLast++;
|
||||
@ -1896,12 +1921,12 @@ static int btreeInitPage(MemPage *pPage){
|
||||
/* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
|
||||
** always be at least one cell before the first freeblock.
|
||||
*/
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
while( 1 ){
|
||||
if( pc>iCellLast ){
|
||||
/* Freeblock off the end of the page */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
next = get2byte(&data[pc]);
|
||||
size = get2byte(&data[pc+2]);
|
||||
@ -1911,11 +1936,11 @@ static int btreeInitPage(MemPage *pPage){
|
||||
}
|
||||
if( next>0 ){
|
||||
/* Freeblock not in ascending order */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
if( pc+size>(unsigned int)usableSize ){
|
||||
/* Last freeblock extends past page end */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1927,7 +1952,7 @@ static int btreeInitPage(MemPage *pPage){
|
||||
** area, according to the page header, lies within the page.
|
||||
*/
|
||||
if( nFree>usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
pPage->nFree = (u16)(nFree - iCellFirst);
|
||||
pPage->isInit = 1;
|
||||
@ -3458,7 +3483,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||
if( eType==PTRMAP_OVERFLOW2 ){
|
||||
/* The pointer is always the first 4 bytes of the page in this case. */
|
||||
if( get4byte(pPage->aData)!=iFrom ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
put4byte(pPage->aData, iTo);
|
||||
}else{
|
||||
@ -3477,7 +3502,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
if( info.nLocal<info.nPayload ){
|
||||
if( pCell+info.nSize > pPage->aData+pPage->pBt->usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
if( iFrom==get4byte(pCell+info.nSize-4) ){
|
||||
put4byte(pCell+info.nSize-4, iTo);
|
||||
@ -3495,7 +3520,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||
if( i==nCell ){
|
||||
if( eType!=PTRMAP_BTREE ||
|
||||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
|
||||
}
|
||||
@ -4593,7 +4618,7 @@ static int accessPayload(
|
||||
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
|
||||
** but is recast into its current form to avoid integer overflow problems
|
||||
*/
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
|
||||
/* Check if data must be read/written to/from the btree page itself. */
|
||||
@ -4741,7 +4766,7 @@ static int accessPayload(
|
||||
|
||||
if( rc==SQLITE_OK && amt>0 ){
|
||||
/* Overflow chain ends prematurely */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -5019,7 +5044,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
** (or the freelist). */
|
||||
assert( pRoot->intKey==1 || pRoot->intKey==0 );
|
||||
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
|
||||
return SQLITE_CORRUPT_PGNO(pCur->pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pCur->pPage);
|
||||
}
|
||||
|
||||
skip_init:
|
||||
@ -5292,7 +5317,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( pPage->intKeyLeaf ){
|
||||
while( 0x80 <= *(pCell++) ){
|
||||
if( pCell>=pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5366,7 +5391,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
|
||||
testcase( nCell==2 ); /* Minimum legal index key size */
|
||||
if( nCell<2 ){
|
||||
rc = SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
rc = SQLITE_CORRUPT_PAGE(pPage);
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCellKey = sqlite3Malloc( nCell+18 );
|
||||
@ -6169,7 +6194,7 @@ static int clearCell(
|
||||
}
|
||||
if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){
|
||||
/* Cell extends past end of page */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
ovflPgno = get4byte(pCell + pInfo->nSize - 4);
|
||||
pBt = pPage->pBt;
|
||||
|
12
src/build.c
12
src/build.c
@ -4364,6 +4364,18 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
|
||||
pKey->aSortOrder[i] = pIdx->aSortOrder[i];
|
||||
}
|
||||
if( pParse->nErr ){
|
||||
assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ );
|
||||
if( pIdx->bNoQuery==0 ){
|
||||
/* Deactivate the index because it contains an unknown collating
|
||||
** sequence. The only way to reactive the index is to reload the
|
||||
** schema. Adding the missing collating sequence later does not
|
||||
** reactive the index. The application had the chance to register
|
||||
** the missing index using the collation-needed callback. For
|
||||
** simplicity, SQLite will not give the application a second chance.
|
||||
*/
|
||||
pIdx->bNoQuery = 1;
|
||||
pParse->rc = SQLITE_ERROR_RETRY;
|
||||
}
|
||||
sqlite3KeyInfoUnref(pKey);
|
||||
pKey = 0;
|
||||
}
|
||||
|
@ -105,6 +105,7 @@ CollSeq *sqlite3GetCollSeq(
|
||||
assert( !p || p->xCmp );
|
||||
if( p==0 ){
|
||||
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
|
||||
pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@
|
||||
**
|
||||
** Jean Meeus
|
||||
** Astronomical Algorithms, 2nd Edition, 1998
|
||||
** ISBM 0-943396-61-1
|
||||
** ISBN 0-943396-61-1
|
||||
** Willmann-Bell, Inc
|
||||
** Richmond, Virginia (USA)
|
||||
*/
|
||||
|
@ -283,11 +283,11 @@ void sqlite3DeleteFrom(
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
||||
isView = pTab->pSelect!=0;
|
||||
bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
|
||||
#else
|
||||
# define pTrigger 0
|
||||
# define isView 0
|
||||
#endif
|
||||
bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
|
||||
#ifdef SQLITE_OMIT_VIEW
|
||||
# undef isView
|
||||
# define isView 0
|
||||
|
13
src/expr.c
13
src/expr.c
@ -2186,16 +2186,15 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
** pX->iTable made to point to the ephemeral table instead of an
|
||||
** existing table.
|
||||
**
|
||||
** The inFlags parameter must contain exactly one of the bits
|
||||
** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains
|
||||
** IN_INDEX_MEMBERSHIP, then the generated table will be used for a
|
||||
** fast membership test. When the IN_INDEX_LOOP bit is set, the
|
||||
** IN index will be used to loop over all values of the RHS of the
|
||||
** IN operator.
|
||||
** The inFlags parameter must contain, at a minimum, one of the bits
|
||||
** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both. If inFlags contains
|
||||
** IN_INDEX_MEMBERSHIP, then the generated table will be used for a fast
|
||||
** membership test. When the IN_INDEX_LOOP bit is set, the IN index will
|
||||
** be used to loop over all values of the RHS of the IN operator.
|
||||
**
|
||||
** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
|
||||
** through the set members) then the b-tree must not contain duplicates.
|
||||
** An epheremal table must be used unless the selected columns are guaranteed
|
||||
** An epheremal table will be created unless the selected columns are guaranteed
|
||||
** to be unique - either because it is an INTEGER PRIMARY KEY or due to
|
||||
** a UNIQUE constraint or index.
|
||||
**
|
||||
|
28
src/main.c
28
src/main.c
@ -22,7 +22,7 @@
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
# include "rtree.h"
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_ICU
|
||||
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
||||
# include "sqliteicu.h"
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_JSON1
|
||||
@ -2822,6 +2822,7 @@ static int openDatabase(
|
||||
}else{
|
||||
isThreadsafe = sqlite3GlobalConfig.bFullMutex;
|
||||
}
|
||||
|
||||
if( flags & SQLITE_OPEN_PRIVATECACHE ){
|
||||
flags &= ~SQLITE_OPEN_SHAREDCACHE;
|
||||
}else if( sqlite3GlobalConfig.sharedCacheEnabled ){
|
||||
@ -2854,13 +2855,20 @@ static int openDatabase(
|
||||
/* Allocate the sqlite data structure */
|
||||
db = sqlite3MallocZero( sizeof(sqlite3) );
|
||||
if( db==0 ) goto opendb_out;
|
||||
if( isThreadsafe ){
|
||||
if( isThreadsafe
|
||||
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|
||||
|| sqlite3GlobalConfig.bCoreMutex
|
||||
#endif
|
||||
){
|
||||
db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
|
||||
if( db->mutex==0 ){
|
||||
sqlite3_free(db);
|
||||
db = 0;
|
||||
goto opendb_out;
|
||||
}
|
||||
if( isThreadsafe==0 ){
|
||||
sqlite3MutexWarnOnContention(db->mutex);
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->errMask = 0xff;
|
||||
@ -3042,7 +3050,7 @@ static int openDatabase(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ICU
|
||||
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
||||
if( !db->mallocFailed && rc==SQLITE_OK ){
|
||||
rc = sqlite3IcuInit(db);
|
||||
}
|
||||
@ -3344,37 +3352,37 @@ int sqlite3_get_autocommit(sqlite3 *db){
|
||||
** 2. Invoke sqlite3_log() to provide the source code location where
|
||||
** a low-level error is first detected.
|
||||
*/
|
||||
static int reportError(int iErr, int lineno, const char *zType){
|
||||
int sqlite3ReportError(int iErr, int lineno, const char *zType){
|
||||
sqlite3_log(iErr, "%s at line %d of [%.10s]",
|
||||
zType, lineno, 20+sqlite3_sourceid());
|
||||
return iErr;
|
||||
}
|
||||
int sqlite3CorruptError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return reportError(SQLITE_CORRUPT, lineno, "database corruption");
|
||||
return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption");
|
||||
}
|
||||
int sqlite3MisuseError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return reportError(SQLITE_MISUSE, lineno, "misuse");
|
||||
return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse");
|
||||
}
|
||||
int sqlite3CantopenError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return reportError(SQLITE_CANTOPEN, lineno, "cannot open file");
|
||||
return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
|
||||
char zMsg[100];
|
||||
sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return reportError(SQLITE_CORRUPT, lineno, zMsg);
|
||||
return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
|
||||
}
|
||||
int sqlite3NomemError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return reportError(SQLITE_NOMEM, lineno, "OOM");
|
||||
return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
|
||||
}
|
||||
int sqlite3IoerrnomemError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
|
||||
return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
192
src/mutex.c
192
src/mutex.c
@ -26,6 +26,193 @@ static SQLITE_WSD int mutexIsInit = 0;
|
||||
|
||||
|
||||
#ifndef SQLITE_MUTEX_OMIT
|
||||
|
||||
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|
||||
/*
|
||||
** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains
|
||||
** the implementation of a wrapper around the system default mutex
|
||||
** implementation (sqlite3DefaultMutex()).
|
||||
**
|
||||
** Most calls are passed directly through to the underlying default
|
||||
** mutex implementation. Except, if a mutex is configured by calling
|
||||
** sqlite3MutexWarnOnContention() on it, then if contention is ever
|
||||
** encountered within xMutexEnter() a warning is emitted via sqlite3_log().
|
||||
**
|
||||
** This type of mutex is used as the database handle mutex when testing
|
||||
** apps that usually use SQLITE_CONFIG_MULTITHREAD mode.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS
|
||||
** is defined. Variable CheckMutex.mutex is a pointer to the real mutex
|
||||
** allocated by the system mutex implementation. Variable iType is usually set
|
||||
** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST
|
||||
** or one of the static mutex identifiers. Or, if this is a recursive mutex
|
||||
** that has been configured using sqlite3MutexWarnOnContention(), it is
|
||||
** set to SQLITE_MUTEX_WARNONCONTENTION.
|
||||
*/
|
||||
typedef struct CheckMutex CheckMutex;
|
||||
struct CheckMutex {
|
||||
int iType;
|
||||
sqlite3_mutex *mutex;
|
||||
};
|
||||
|
||||
#define SQLITE_MUTEX_WARNONCONTENTION (-1)
|
||||
|
||||
/*
|
||||
** Pointer to real mutex methods object used by the CheckMutex
|
||||
** implementation. Set by checkMutexInit().
|
||||
*/
|
||||
static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int checkMutexHeld(sqlite3_mutex *p){
|
||||
return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex);
|
||||
}
|
||||
static int checkMutexNotheld(sqlite3_mutex *p){
|
||||
return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
static int checkMutexInit(void){
|
||||
pGlobalMutexMethods = sqlite3DefaultMutex();
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static int checkMutexEnd(void){
|
||||
pGlobalMutexMethods = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate a mutex.
|
||||
*/
|
||||
static sqlite3_mutex *checkMutexAlloc(int iType){
|
||||
static CheckMutex staticMutexes[] = {
|
||||
{2, 0}, {3, 0}, {4, 0}, {5, 0},
|
||||
{6, 0}, {7, 0}, {8, 0}, {9, 0},
|
||||
{10, 0}, {11, 0}, {12, 0}, {13, 0}
|
||||
};
|
||||
CheckMutex *p = 0;
|
||||
|
||||
assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 );
|
||||
if( iType<2 ){
|
||||
p = sqlite3MallocZero(sizeof(CheckMutex));
|
||||
if( p==0 ) return 0;
|
||||
p->iType = iType;
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( iType-2>=ArraySize(staticMutexes) ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
p = &staticMutexes[iType-2];
|
||||
}
|
||||
|
||||
if( p->mutex==0 ){
|
||||
p->mutex = pGlobalMutexMethods->xMutexAlloc(iType);
|
||||
if( p->mutex==0 ){
|
||||
if( iType<2 ){
|
||||
sqlite3_free(p);
|
||||
}
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (sqlite3_mutex*)p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a mutex.
|
||||
*/
|
||||
static void checkMutexFree(sqlite3_mutex *p){
|
||||
assert( SQLITE_MUTEX_RECURSIVE<2 );
|
||||
assert( SQLITE_MUTEX_FAST<2 );
|
||||
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
|
||||
|
||||
#if SQLITE_ENABLE_API_ARMOR
|
||||
if( ((CheckMutex*)p)->iType<2 )
|
||||
#endif
|
||||
{
|
||||
CheckMutex *pCheck = (CheckMutex*)p;
|
||||
pGlobalMutexMethods->xMutexFree(pCheck->mutex);
|
||||
sqlite3_free(pCheck);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
else{
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Enter the mutex.
|
||||
*/
|
||||
static void checkMutexEnter(sqlite3_mutex *p){
|
||||
CheckMutex *pCheck = (CheckMutex*)p;
|
||||
if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){
|
||||
if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){
|
||||
return;
|
||||
}
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
"illegal multi-threaded access to database connection"
|
||||
);
|
||||
}
|
||||
pGlobalMutexMethods->xMutexEnter(pCheck->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Enter the mutex (do not block).
|
||||
*/
|
||||
static int checkMutexTry(sqlite3_mutex *p){
|
||||
CheckMutex *pCheck = (CheckMutex*)p;
|
||||
return pGlobalMutexMethods->xMutexTry(pCheck->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Leave the mutex.
|
||||
*/
|
||||
static void checkMutexLeave(sqlite3_mutex *p){
|
||||
CheckMutex *pCheck = (CheckMutex*)p;
|
||||
pGlobalMutexMethods->xMutexLeave(pCheck->mutex);
|
||||
}
|
||||
|
||||
sqlite3_mutex_methods const *multiThreadedCheckMutex(void){
|
||||
static const sqlite3_mutex_methods sMutex = {
|
||||
checkMutexInit,
|
||||
checkMutexEnd,
|
||||
checkMutexAlloc,
|
||||
checkMutexFree,
|
||||
checkMutexEnter,
|
||||
checkMutexTry,
|
||||
checkMutexLeave,
|
||||
#ifdef SQLITE_DEBUG
|
||||
checkMutexHeld,
|
||||
checkMutexNotheld
|
||||
#else
|
||||
0,
|
||||
0
|
||||
#endif
|
||||
};
|
||||
return &sMutex;
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as
|
||||
** one on which there should be no contention.
|
||||
*/
|
||||
void sqlite3MutexWarnOnContention(sqlite3_mutex *p){
|
||||
if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){
|
||||
CheckMutex *pCheck = (CheckMutex*)p;
|
||||
assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE );
|
||||
pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION;
|
||||
}
|
||||
}
|
||||
#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */
|
||||
|
||||
/*
|
||||
** Initialize the mutex system.
|
||||
*/
|
||||
@ -41,7 +228,11 @@ int sqlite3MutexInit(void){
|
||||
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
|
||||
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|
||||
pFrom = multiThreadedCheckMutex();
|
||||
#else
|
||||
pFrom = sqlite3DefaultMutex();
|
||||
#endif
|
||||
}else{
|
||||
pFrom = sqlite3NoopMutex();
|
||||
}
|
||||
@ -167,3 +358,4 @@ int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SQLITE_MUTEX_OMIT) */
|
||||
|
||||
|
@ -483,7 +483,7 @@ static struct unix_syscall {
|
||||
#else
|
||||
{ "munmap", (sqlite3_syscall_ptr)0, 0 },
|
||||
#endif
|
||||
#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
|
||||
#define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent)
|
||||
|
||||
#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
|
||||
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
|
||||
@ -4165,7 +4165,7 @@ static int unixShmSystemLock(
|
||||
|
||||
/* Access to the unixShmNode object is serialized by the caller */
|
||||
pShmNode = pFile->pInode->pShmNode;
|
||||
assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
|
||||
assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) );
|
||||
|
||||
/* Shared locks never span more than one byte */
|
||||
assert( n==1 || lockType!=F_RDLCK );
|
||||
@ -5799,7 +5799,7 @@ static int unixOpen(
|
||||
** a file-descriptor on the directory too. The first time unixSync()
|
||||
** is called the directory file descriptor will be fsync()ed and close()d.
|
||||
*/
|
||||
int syncDir = (isCreate && (
|
||||
int isNewJrnl = (isCreate && (
|
||||
eType==SQLITE_OPEN_MASTER_JOURNAL
|
||||
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|
||||
|| eType==SQLITE_OPEN_WAL
|
||||
@ -5869,7 +5869,7 @@ static int unixOpen(
|
||||
|
||||
}else if( !zName ){
|
||||
/* If zName is NULL, the upper layer is requesting a temp file. */
|
||||
assert(isDelete && !syncDir);
|
||||
assert(isDelete && !isNewJrnl);
|
||||
rc = unixGetTempname(pVfs->mxPathname, zTmpname);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
@ -5915,6 +5915,9 @@ static int unixOpen(
|
||||
}
|
||||
if( fd<0 ){
|
||||
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
|
||||
/* If unable to create a journal, change the error code to
|
||||
** indicate that the directory permissions are wrong. */
|
||||
if( isNewJrnl && osAccess(zName, F_OK) ) rc = SQLITE_READONLY_DIRECTORY;
|
||||
goto open_finished;
|
||||
}
|
||||
|
||||
@ -5974,7 +5977,7 @@ static int unixOpen(
|
||||
if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
|
||||
noLock = eType!=SQLITE_OPEN_MAIN_DB;
|
||||
if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
|
||||
if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
|
||||
if( isNewJrnl ) ctrlFlags |= UNIXFILE_DIRSYNC;
|
||||
if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
|
||||
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
|
@ -3742,7 +3742,7 @@ static int winShmSystemLock(
|
||||
int rc = 0; /* Result code form Lock/UnlockFileEx() */
|
||||
|
||||
/* Access to the winShmNode object is serialized by the caller */
|
||||
assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
|
||||
assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
|
||||
|
||||
OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
|
||||
pFile->hFile.h, lockType, ofst, nByte));
|
||||
|
@ -655,8 +655,6 @@ static int sqlite3Prepare(
|
||||
end_prepare:
|
||||
|
||||
sqlite3ParserReset(&sParse);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
assert( (rc&db->errMask)==rc );
|
||||
return rc;
|
||||
}
|
||||
static int sqlite3LockAndPrepare(
|
||||
@ -669,6 +667,7 @@ static int sqlite3LockAndPrepare(
|
||||
const char **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
int rc;
|
||||
int cnt = 0;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
|
||||
@ -679,15 +678,18 @@ static int sqlite3LockAndPrepare(
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
|
||||
if( rc==SQLITE_SCHEMA ){
|
||||
sqlite3ResetOneSchema(db, -1);
|
||||
sqlite3_finalize(*ppStmt);
|
||||
do{
|
||||
/* Make multiple attempts to compile the SQL, until it either succeeds
|
||||
** or encounters a permanent error. A schema problem after one schema
|
||||
** reset is considered a permanent error. */
|
||||
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
|
||||
}
|
||||
assert( rc==SQLITE_OK || *ppStmt==0 );
|
||||
}while( rc==SQLITE_ERROR_RETRY
|
||||
|| (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
assert( (rc&db->errMask)==rc );
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
assert( rc==SQLITE_OK || *ppStmt==0 );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
151
src/shell.c.in
151
src/shell.c.in
@ -1190,12 +1190,9 @@ static void output_csv(ShellState *p, const char *z, int bSep){
|
||||
}
|
||||
}
|
||||
if( i==0 ){
|
||||
putc('"', out);
|
||||
for(i=0; z[i]; i++){
|
||||
if( z[i]=='"' ) putc('"', out);
|
||||
putc(z[i], out);
|
||||
}
|
||||
putc('"', out);
|
||||
char *zQuoted = sqlite3_mprintf("\"%w\"", z);
|
||||
utf8_printf(out, "%s", zQuoted);
|
||||
sqlite3_free(zQuoted);
|
||||
}else{
|
||||
utf8_printf(out, "%s", z);
|
||||
}
|
||||
@ -3898,10 +3895,10 @@ static int lintFkeyIndexes(
|
||||
**
|
||||
** 0. The text of an SQL statement similar to:
|
||||
**
|
||||
** "EXPLAIN QUERY PLAN SELECT rowid FROM child_table WHERE child_key=?"
|
||||
** "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
|
||||
**
|
||||
** This is the same SELECT that the foreign keys implementation needs
|
||||
** to run internally on child tables. If there is an index that can
|
||||
** This SELECT is similar to the one that the foreign keys implementation
|
||||
** needs to run internally on child tables. If there is an index that can
|
||||
** be used to optimize this query, then it can also be used by the FK
|
||||
** implementation to optimize DELETE or UPDATE statements on the parent
|
||||
** table.
|
||||
@ -3929,7 +3926,7 @@ static int lintFkeyIndexes(
|
||||
*/
|
||||
const char *zSql =
|
||||
"SELECT "
|
||||
" 'EXPLAIN QUERY PLAN SELECT rowid FROM ' || quote(s.name) || ' WHERE '"
|
||||
" 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
|
||||
" || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
|
||||
" || fkey_collate_clause("
|
||||
" f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
|
||||
@ -5922,49 +5919,77 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
|
||||
#ifndef SQLITE_UNTESTABLE
|
||||
if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
|
||||
if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){
|
||||
static const struct {
|
||||
const char *zCtrlName; /* Name of a test-control option */
|
||||
int ctrlCode; /* Integer code for that option */
|
||||
const char *zUsage; /* Usage notes */
|
||||
} aCtrl[] = {
|
||||
{ "prng_save", SQLITE_TESTCTRL_PRNG_SAVE },
|
||||
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE },
|
||||
{ "prng_reset", SQLITE_TESTCTRL_PRNG_RESET },
|
||||
{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST },
|
||||
{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL },
|
||||
{ "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS },
|
||||
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
|
||||
{ "assert", SQLITE_TESTCTRL_ASSERT },
|
||||
{ "always", SQLITE_TESTCTRL_ALWAYS },
|
||||
{ "reserve", SQLITE_TESTCTRL_RESERVE },
|
||||
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
|
||||
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
|
||||
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
|
||||
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
|
||||
{ "imposter", SQLITE_TESTCTRL_IMPOSTER },
|
||||
{ "always", SQLITE_TESTCTRL_ALWAYS, "BOOLEAN" },
|
||||
{ "assert", SQLITE_TESTCTRL_ASSERT, "BOOLEAN" },
|
||||
/*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, "" },*/
|
||||
/*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, "" },*/
|
||||
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER, "" },
|
||||
/*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, "" }, */
|
||||
{ "imposter", SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"},
|
||||
#ifdef SQLITE_N_KEYWORD
|
||||
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD, "IDENTIFIER" },
|
||||
#endif
|
||||
{ "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" },
|
||||
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" },
|
||||
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" },
|
||||
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE, "OFFSET " },
|
||||
{ "prng_reset", SQLITE_TESTCTRL_PRNG_RESET, "" },
|
||||
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
|
||||
{ "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" },
|
||||
{ "reserve", SQLITE_TESTCTRL_RESERVE, "BYTES-OF-RESERVE" },
|
||||
};
|
||||
int testctrl = -1;
|
||||
int rc2 = 0;
|
||||
int iCtrl = -1;
|
||||
int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */
|
||||
int isOk = 0;
|
||||
int i, n2;
|
||||
const char *zCmd = 0;
|
||||
|
||||
open_db(p, 0);
|
||||
zCmd = nArg>=2 ? azArg[1] : "help";
|
||||
|
||||
/* The argument can optionally begin with "-" or "--" */
|
||||
if( zCmd[0]=='-' && zCmd[1] ){
|
||||
zCmd++;
|
||||
if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
|
||||
}
|
||||
|
||||
/* --help lists all test-controls */
|
||||
if( strcmp(zCmd,"help")==0 ){
|
||||
utf8_printf(p->out, "Available test-controls:\n");
|
||||
for(i=0; i<ArraySize(aCtrl); i++){
|
||||
utf8_printf(p->out, " .testctrl %s %s\n",
|
||||
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
|
||||
}
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
|
||||
/* convert testctrl text option to value. allow any unique prefix
|
||||
** of the option name, or a numerical value. */
|
||||
n2 = strlen30(azArg[1]);
|
||||
n2 = strlen30(zCmd);
|
||||
for(i=0; i<ArraySize(aCtrl); i++){
|
||||
if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
|
||||
if( strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
|
||||
if( testctrl<0 ){
|
||||
testctrl = aCtrl[i].ctrlCode;
|
||||
iCtrl = i;
|
||||
}else{
|
||||
utf8_printf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
|
||||
testctrl = -1;
|
||||
break;
|
||||
utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n"
|
||||
"Use \".testctrl --help\" for help\n", zCmd);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
|
||||
if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
|
||||
utf8_printf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
|
||||
if( testctrl<0 ){
|
||||
utf8_printf(stderr,"Error: unknown test-control: %s\n"
|
||||
"Use \".testctrl --help\" for help\n", zCmd);
|
||||
}else{
|
||||
switch(testctrl){
|
||||
|
||||
@ -5974,10 +5999,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( nArg==3 ){
|
||||
int opt = (int)strtol(azArg[2], 0, 0);
|
||||
rc2 = sqlite3_test_control(testctrl, p->db, opt);
|
||||
raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
|
||||
azArg[1]);
|
||||
isOk = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -5988,10 +6010,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
case SQLITE_TESTCTRL_BYTEORDER:
|
||||
if( nArg==2 ){
|
||||
rc2 = sqlite3_test_control(testctrl);
|
||||
raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
utf8_printf(stderr,"Error: testctrl %s takes no options\n",
|
||||
azArg[1]);
|
||||
isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -6000,24 +6019,27 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( nArg==3 ){
|
||||
unsigned int opt = (unsigned int)integerValue(azArg[2]);
|
||||
rc2 = sqlite3_test_control(testctrl, opt);
|
||||
raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
utf8_printf(stderr,"Error: testctrl %s takes a single unsigned"
|
||||
" int option\n", azArg[1]);
|
||||
isOk = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
/* sqlite3_test_control(int, int) */
|
||||
case SQLITE_TESTCTRL_ASSERT:
|
||||
case SQLITE_TESTCTRL_ALWAYS:
|
||||
if( nArg==3 ){
|
||||
int opt = booleanValue(azArg[2]);
|
||||
rc2 = sqlite3_test_control(testctrl, opt);
|
||||
isOk = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
/* sqlite3_test_control(int, int) */
|
||||
case SQLITE_TESTCTRL_LOCALTIME_FAULT:
|
||||
case SQLITE_TESTCTRL_NEVER_CORRUPT:
|
||||
if( nArg==3 ){
|
||||
int opt = booleanValue(azArg[2]);
|
||||
rc2 = sqlite3_test_control(testctrl, opt);
|
||||
raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
|
||||
azArg[1]);
|
||||
isOk = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -6027,11 +6049,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( nArg==3 ){
|
||||
const char *opt = azArg[2];
|
||||
rc2 = sqlite3_test_control(testctrl, opt);
|
||||
raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
utf8_printf(stderr,
|
||||
"Error: testctrl %s takes a single char * option\n",
|
||||
azArg[1]);
|
||||
isOk = 1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@ -6042,22 +6060,19 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
azArg[2],
|
||||
integerValue(azArg[3]),
|
||||
integerValue(azArg[4]));
|
||||
raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
}else{
|
||||
raw_printf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
|
||||
isOk = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQLITE_TESTCTRL_BITVEC_TEST:
|
||||
case SQLITE_TESTCTRL_FAULT_INSTALL:
|
||||
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
|
||||
default:
|
||||
utf8_printf(stderr,
|
||||
"Error: CLI support for testctrl %s not implemented\n",
|
||||
azArg[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( isOk==0 && iCtrl>=0 ){
|
||||
utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd, aCtrl[iCtrl].zUsage);
|
||||
rc = 1;
|
||||
}else if( isOk==1 ){
|
||||
raw_printf(p->out, "%d\n", rc2);
|
||||
}else if( isOk==2 ){
|
||||
raw_printf(p->out, "0x%08x\n", rc2);
|
||||
}
|
||||
}else
|
||||
#endif /* !defined(SQLITE_UNTESTABLE) */
|
||||
|
||||
|
@ -470,6 +470,8 @@ int sqlite3_exec(
|
||||
** the most recent error can be obtained using
|
||||
** [sqlite3_extended_errcode()].
|
||||
*/
|
||||
#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8))
|
||||
#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8))
|
||||
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
|
||||
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
|
||||
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
|
||||
@ -515,6 +517,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
|
||||
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
|
||||
#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
|
||||
#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8))
|
||||
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
|
||||
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
|
||||
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
|
||||
|
@ -2172,6 +2172,7 @@ struct Index {
|
||||
unsigned isCovering:1; /* True if this is a covering index */
|
||||
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
|
||||
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
|
||||
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
int nSample; /* Number of elements in aSample[] */
|
||||
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
|
||||
@ -2984,7 +2985,7 @@ struct Parse {
|
||||
int nMem; /* Number of memory cells used so far */
|
||||
int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
|
||||
int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
|
||||
int iSelfTab; /* Table for associated with an index on expr, or negative
|
||||
int iSelfTab; /* Table associated with an index on expr, or negative
|
||||
** of the base register during check-constraint eval */
|
||||
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
|
||||
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
|
||||
@ -3431,6 +3432,7 @@ struct TreeView {
|
||||
** using sqlite3_log(). The routines also provide a convenient place
|
||||
** to set a debugger breakpoint.
|
||||
*/
|
||||
int sqlite3ReportError(int iErr, int lineno, const char *zType);
|
||||
int sqlite3CorruptError(int);
|
||||
int sqlite3MisuseError(int);
|
||||
int sqlite3CantopenError(int);
|
||||
@ -3589,6 +3591,12 @@ int sqlite3LookasideUsed(sqlite3*,int*);
|
||||
sqlite3_mutex *sqlite3Pcache1Mutex(void);
|
||||
sqlite3_mutex *sqlite3MallocMutex(void);
|
||||
|
||||
#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT)
|
||||
void sqlite3MutexWarnOnContention(sqlite3_mutex*);
|
||||
#else
|
||||
# define sqlite3MutexWarnOnContention(x)
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
int sqlite3IsNaN(double);
|
||||
#else
|
||||
|
@ -429,6 +429,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "icu", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ICU_COLLATIONS
|
||||
Tcl_SetVar2(interp, "sqlite_options", "icu_collations", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "icu_collations", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_INCRBLOB
|
||||
Tcl_SetVar2(interp, "sqlite_options", "incrblob", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@ -696,6 +702,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar2(interp, "sqlite_options", "unlock_notify", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_FAST_SECURE_DELETE
|
||||
Tcl_SetVar2(interp, "sqlite_options", "fast_secure_delete", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "fast_secure_delete", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
@ -875,7 +875,7 @@ static TriggerPrg *codeRowTrigger(
|
||||
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
|
||||
|
||||
transferParseError(pParse, pSubParse);
|
||||
if( db->mallocFailed==0 ){
|
||||
if( db->mallocFailed==0 && pParse->nErr==0 ){
|
||||
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
|
||||
}
|
||||
pProgram->nMem = pSubParse->nMem;
|
||||
|
@ -2268,6 +2268,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
pPager = sqlite3BtreePager(pBt);
|
||||
if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF
|
||||
&& aMJNeeded[sqlite3PagerGetJournalMode(pPager)]
|
||||
&& sqlite3PagerIsMemdb(pPager)==0
|
||||
){
|
||||
assert( i!=1 );
|
||||
nTrans++;
|
||||
|
@ -1321,7 +1321,11 @@ static int valueFromExpr(
|
||||
|
||||
assert( pExpr!=0 );
|
||||
while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
|
||||
#if defined(SQLITE_ENABLE_STAT3_OR_STAT4)
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#else
|
||||
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
|
||||
#endif
|
||||
|
||||
/* Compressed expressions only appear when parsing the DEFAULT clause
|
||||
** on a table column definition, and hence only when pCtx==0. This
|
||||
@ -1416,7 +1420,10 @@ static int valueFromExpr(
|
||||
return rc;
|
||||
|
||||
no_mem:
|
||||
sqlite3OomFault(db);
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( pCtx==0 || pCtx->pParse->nErr==0 )
|
||||
#endif
|
||||
sqlite3OomFault(db);
|
||||
sqlite3DbFree(db, zVal);
|
||||
assert( *ppVal==0 );
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
|
@ -2494,8 +2494,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
pInfo = walCkptInfo(pWal);
|
||||
if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0
|
||||
|| 0==memcmp(&pWal->hdr, pWal->pSnapshot, sizeof(WalIndexHdr)))
|
||||
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
|
||||
#endif
|
||||
){
|
||||
/* The WAL has been completely backfilled (or it is empty).
|
||||
|
77
src/where.c
77
src/where.c
@ -2460,7 +2460,7 @@ static int whereLoopAddBtreeIndex(
|
||||
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
||||
assert( saved_nEq==pNew->u.btree.nEq );
|
||||
if( iCol==XN_ROWID
|
||||
|| (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
|
||||
|| (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
|
||||
){
|
||||
if( iCol>=0 && pProbe->uniqNotNull==0 ){
|
||||
pNew->wsFlags |= WHERE_UNQ_WANTED;
|
||||
@ -2879,6 +2879,7 @@ static int whereLoopAddBtree(
|
||||
testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */
|
||||
continue; /* Partial index inappropriate for this query */
|
||||
}
|
||||
if( pProbe->bNoQuery ) continue;
|
||||
rSize = pProbe->aiRowLogEst[0];
|
||||
pNew->u.btree.nEq = 0;
|
||||
pNew->u.btree.nBtm = 0;
|
||||
@ -4677,35 +4678,80 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Attempt to omit tables from the join that do not effect the result */
|
||||
|
||||
/* Attempt to omit tables from the join that do not affect the result.
|
||||
** For a table to not affect the result, the following must be true:
|
||||
**
|
||||
** 1) The query must not be an aggregate.
|
||||
** 2) The table must be the RHS of a LEFT JOIN.
|
||||
** 3) Either the query must be DISTINCT, or else the ON or USING clause
|
||||
** must contain a constraint that limits the scan of the table to
|
||||
** at most a single row.
|
||||
** 4) The table must not be referenced by any part of the query apart
|
||||
** from its own USING or ON clause.
|
||||
**
|
||||
** For example, given:
|
||||
**
|
||||
** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
|
||||
** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
|
||||
** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
|
||||
**
|
||||
** then table t2 can be omitted from the following:
|
||||
**
|
||||
** SELECT v1, v3 FROM t1
|
||||
** LEFT JOIN t2 USING (t1.ipk=t2.ipk)
|
||||
** LEFT JOIN t3 USING (t1.ipk=t3.ipk)
|
||||
**
|
||||
** or from:
|
||||
**
|
||||
** SELECT DISTINCT v1, v3 FROM t1
|
||||
** LEFT JOIN t2
|
||||
** LEFT JOIN t3 USING (t1.ipk=t3.ipk)
|
||||
*/
|
||||
notReady = ~(Bitmask)0;
|
||||
if( pWInfo->nLevel>=2
|
||||
&& pResultSet!=0
|
||||
&& pResultSet!=0 /* guarantees condition (1) above */
|
||||
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
|
||||
){
|
||||
int i;
|
||||
Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
|
||||
if( sWLB.pOrderBy ){
|
||||
tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
|
||||
}
|
||||
while( pWInfo->nLevel>=2 ){
|
||||
for(i=pWInfo->nLevel-1; i>=1; i--){
|
||||
WhereTerm *pTerm, *pEnd;
|
||||
pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
|
||||
if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break;
|
||||
struct SrcList_item *pItem;
|
||||
pLoop = pWInfo->a[i].pWLoop;
|
||||
pItem = &pWInfo->pTabList->a[pLoop->iTab];
|
||||
if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
|
||||
if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
|
||||
&& (pLoop->wsFlags & WHERE_ONEROW)==0
|
||||
){
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if( (tabUsed & pLoop->maskSelf)!=0 ) break;
|
||||
if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
|
||||
pEnd = sWLB.pWC->a + sWLB.pWC->nTerm;
|
||||
for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)!=0
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
){
|
||||
break;
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
|
||||
if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
|| pTerm->pExpr->iRightJoinTable!=pItem->iCursor
|
||||
){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pTerm<pEnd ) break;
|
||||
if( pTerm<pEnd ) continue;
|
||||
WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId));
|
||||
notReady &= ~pLoop->maskSelf;
|
||||
for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
}
|
||||
if( i!=pWInfo->nLevel-1 ){
|
||||
int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
|
||||
memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
|
||||
}
|
||||
pWInfo->nLevel--;
|
||||
nTabList--;
|
||||
}
|
||||
@ -4860,7 +4906,6 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** loop below generates code for a single nested loop of the VM
|
||||
** program.
|
||||
*/
|
||||
notReady = ~(Bitmask)0;
|
||||
for(ii=0; ii<nTabList; ii++){
|
||||
int addrExplain;
|
||||
int wsFlags;
|
||||
@ -4924,6 +4969,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
Index *pIdx;
|
||||
int n;
|
||||
if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
|
||||
&& i==pWInfo->nLevel-1 /* Ticket [ef9318757b152e3] 2017-10-21 */
|
||||
&& (pLoop->wsFlags & WHERE_INDEXED)!=0
|
||||
&& (pIdx = pLoop->u.btree.pIndex)->hasStat1
|
||||
&& (n = pLoop->u.btree.nIdxCol)>0
|
||||
@ -4990,7 +5036,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
|
||||
assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
|
||||
if( (ws & WHERE_IDX_ONLY)==0 ){
|
||||
sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
|
||||
assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
|
||||
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
|
||||
}
|
||||
if( (ws & WHERE_INDEXED)
|
||||
|| ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx)
|
||||
|
156
src/wherecode.c
156
src/wherecode.c
@ -377,6 +377,102 @@ static void updateRangeAffinityStr(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** pX is an expression of the form: (vector) IN (SELECT ...)
|
||||
** In other words, it is a vector IN operator with a SELECT clause on the
|
||||
** LHS. But not all terms in the vector are indexable and the terms might
|
||||
** not be in the correct order for indexing.
|
||||
**
|
||||
** This routine makes a copy of the input pX expression and then adjusts
|
||||
** the vector on the LHS with corresponding changes to the SELECT so that
|
||||
** the vector contains only index terms and those terms are in the correct
|
||||
** order. The modified IN expression is returned. The caller is responsible
|
||||
** for deleting the returned expression.
|
||||
**
|
||||
** Example:
|
||||
**
|
||||
** CREATE TABLE t1(a,b,c,d,e,f);
|
||||
** CREATE INDEX t1x1 ON t1(e,c);
|
||||
** SELECT * FROM t1 WHERE (a,b,c,d,e) IN (SELECT v,w,x,y,z FROM t2)
|
||||
** \_______________________________________/
|
||||
** The pX expression
|
||||
**
|
||||
** Since only columns e and c can be used with the index, in that order,
|
||||
** the modified IN expression that is returned will be:
|
||||
**
|
||||
** (e,c) IN (SELECT z,x FROM t2)
|
||||
**
|
||||
** The reduced pX is different from the original (obviously) and thus is
|
||||
** only used for indexing, to improve performance. The original unaltered
|
||||
** IN expression must also be run on each output row for correctness.
|
||||
*/
|
||||
static Expr *removeUnindexableInClauseTerms(
|
||||
Parse *pParse, /* The parsing context */
|
||||
int iEq, /* Look at loop terms starting here */
|
||||
WhereLoop *pLoop, /* The current loop */
|
||||
Expr *pX /* The IN expression to be reduced */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
Expr *pNew = sqlite3ExprDup(db, pX, 0);
|
||||
if( db->mallocFailed==0 ){
|
||||
ExprList *pOrigRhs = pNew->x.pSelect->pEList; /* Original unmodified RHS */
|
||||
ExprList *pOrigLhs = pNew->pLeft->x.pList; /* Original unmodified LHS */
|
||||
ExprList *pRhs = 0; /* New RHS after modifications */
|
||||
ExprList *pLhs = 0; /* New LHS after mods */
|
||||
int i; /* Loop counter */
|
||||
Select *pSelect; /* Pointer to the SELECT on the RHS */
|
||||
|
||||
for(i=iEq; i<pLoop->nLTerm; i++){
|
||||
if( pLoop->aLTerm[i]->pExpr==pX ){
|
||||
int iField = pLoop->aLTerm[i]->iField - 1;
|
||||
assert( pOrigRhs->a[iField].pExpr!=0 );
|
||||
pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
|
||||
pOrigRhs->a[iField].pExpr = 0;
|
||||
assert( pOrigLhs->a[iField].pExpr!=0 );
|
||||
pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr);
|
||||
pOrigLhs->a[iField].pExpr = 0;
|
||||
}
|
||||
}
|
||||
sqlite3ExprListDelete(db, pOrigRhs);
|
||||
sqlite3ExprListDelete(db, pOrigLhs);
|
||||
pNew->pLeft->x.pList = pLhs;
|
||||
pNew->x.pSelect->pEList = pRhs;
|
||||
if( pLhs && pLhs->nExpr==1 ){
|
||||
/* Take care here not to generate a TK_VECTOR containing only a
|
||||
** single value. Since the parser never creates such a vector, some
|
||||
** of the subroutines do not handle this case. */
|
||||
Expr *p = pLhs->a[0].pExpr;
|
||||
pLhs->a[0].pExpr = 0;
|
||||
sqlite3ExprDelete(db, pNew->pLeft);
|
||||
pNew->pLeft = p;
|
||||
}
|
||||
pSelect = pNew->x.pSelect;
|
||||
if( pSelect->pOrderBy ){
|
||||
/* If the SELECT statement has an ORDER BY clause, zero the
|
||||
** iOrderByCol variables. These are set to non-zero when an
|
||||
** ORDER BY term exactly matches one of the terms of the
|
||||
** result-set. Since the result-set of the SELECT statement may
|
||||
** have been modified or reordered, these variables are no longer
|
||||
** set correctly. Since setting them is just an optimization,
|
||||
** it's easiest just to zero them here. */
|
||||
ExprList *pOrderBy = pSelect->pOrderBy;
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
pOrderBy->a[i].u.x.iOrderByCol = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
printf("For indexing, change the IN expr:\n");
|
||||
sqlite3TreeViewExpr(0, pX, 0);
|
||||
printf("Into:\n");
|
||||
sqlite3TreeViewExpr(0, pNew, 0);
|
||||
#endif
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Generate code for a single equality term of the WHERE clause. An equality
|
||||
** term can be either X=expr or X IN (...). pTerm is the term to be
|
||||
@ -439,68 +535,23 @@ static int codeEqualityTerm(
|
||||
}
|
||||
}
|
||||
for(i=iEq;i<pLoop->nLTerm; i++){
|
||||
if( ALWAYS(pLoop->aLTerm[i]) && pLoop->aLTerm[i]->pExpr==pX ) nEq++;
|
||||
assert( pLoop->aLTerm[i]!=0 );
|
||||
if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
|
||||
}
|
||||
|
||||
if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
|
||||
}else{
|
||||
Select *pSelect = pX->x.pSelect;
|
||||
sqlite3 *db = pParse->db;
|
||||
u16 savedDbOptFlags = db->dbOptFlags;
|
||||
ExprList *pOrigRhs = pSelect->pEList;
|
||||
ExprList *pOrigLhs = pX->pLeft->x.pList;
|
||||
ExprList *pRhs = 0; /* New Select.pEList for RHS */
|
||||
ExprList *pLhs = 0; /* New pX->pLeft vector */
|
||||
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
||||
|
||||
for(i=iEq;i<pLoop->nLTerm; i++){
|
||||
if( pLoop->aLTerm[i]->pExpr==pX ){
|
||||
int iField = pLoop->aLTerm[i]->iField - 1;
|
||||
Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0);
|
||||
Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0);
|
||||
|
||||
pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs);
|
||||
pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs);
|
||||
}
|
||||
}
|
||||
if( !db->mallocFailed ){
|
||||
Expr *pLeft = pX->pLeft;
|
||||
|
||||
if( pSelect->pOrderBy ){
|
||||
/* If the SELECT statement has an ORDER BY clause, zero the
|
||||
** iOrderByCol variables. These are set to non-zero when an
|
||||
** ORDER BY term exactly matches one of the terms of the
|
||||
** result-set. Since the result-set of the SELECT statement may
|
||||
** have been modified or reordered, these variables are no longer
|
||||
** set correctly. Since setting them is just an optimization,
|
||||
** it's easiest just to zero them here. */
|
||||
ExprList *pOrderBy = pSelect->pOrderBy;
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
pOrderBy->a[i].u.x.iOrderByCol = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Take care here not to generate a TK_VECTOR containing only a
|
||||
** single value. Since the parser never creates such a vector, some
|
||||
** of the subroutines do not handle this case. */
|
||||
if( pLhs->nExpr==1 ){
|
||||
pX->pLeft = pLhs->a[0].pExpr;
|
||||
}else{
|
||||
pLeft->x.pList = pLhs;
|
||||
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq);
|
||||
testcase( aiMap==0 );
|
||||
}
|
||||
pSelect->pEList = pRhs;
|
||||
db->dbOptFlags |= SQLITE_QueryFlattener;
|
||||
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
|
||||
db->dbOptFlags = savedDbOptFlags;
|
||||
testcase( aiMap!=0 && aiMap[0]!=0 );
|
||||
pSelect->pEList = pOrigRhs;
|
||||
pLeft->x.pList = pOrigLhs;
|
||||
pX->pLeft = pLeft;
|
||||
pTerm->pExpr->iTable = pX->iTable;
|
||||
}
|
||||
sqlite3ExprListDelete(pParse->db, pLhs);
|
||||
sqlite3ExprListDelete(pParse->db, pRhs);
|
||||
sqlite3ExprDelete(db, pX);
|
||||
pX = pTerm->pExpr;
|
||||
}
|
||||
|
||||
if( eType==IN_INDEX_INDEX_DESC ){
|
||||
@ -1639,6 +1690,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}
|
||||
}else if( bStopAtNull ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
||||
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
|
||||
endEq = 0;
|
||||
nConstraint++;
|
||||
}
|
||||
|
@ -179,5 +179,55 @@ do_execsql_test 920 {
|
||||
wxYZ wxYz wxYz wxyZ wxyZ wxyz wxyz
|
||||
}
|
||||
|
||||
# Ticket https://sqlite.org/src/info/ef9318757b152e3a on 2017-11-21
|
||||
# Incorrect result due to a skip-ahead-distinct optimization on a
|
||||
# join where no rows of the inner loop appear in the result set.
|
||||
#
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
do_execsql_test 1000 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
CREATE TABLE t2(x INTEGER PRIMARY KEY, y INTEGER);
|
||||
CREATE INDEX t2y ON t2(y);
|
||||
WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<49)
|
||||
INSERT INTO t1(b) SELECT x/10 - 1 FROM c;
|
||||
WITH RECURSIVE c(x) AS (VALUES(-1) UNION ALL SELECT x+1 FROM c WHERE x<19)
|
||||
INSERT INTO t2(x,y) SELECT x, 1 FROM c;
|
||||
SELECT DISTINCT y FROM t1, t2 WHERE b=x AND b<>-1;
|
||||
ANALYZE;
|
||||
SELECT DISTINCT y FROM t1, t2 WHERE b=x AND b<>-1;
|
||||
} {1 1}
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
do_execsql_test 1010 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
CREATE TABLE t2(x INTEGER PRIMARY KEY, y INTEGER);
|
||||
CREATE INDEX t2y ON t2(y);
|
||||
WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<49)
|
||||
INSERT INTO t1(b) SELECT -(x/10 - 1) FROM c;
|
||||
WITH RECURSIVE c(x) AS (VALUES(-1) UNION ALL SELECT x+1 FROM c WHERE x<19)
|
||||
INSERT INTO t2(x,y) SELECT -x, 1 FROM c;
|
||||
SELECT DISTINCT y FROM t1, t2 WHERE b=x AND b<>1 ORDER BY y DESC;
|
||||
ANALYZE;
|
||||
SELECT DISTINCT y FROM t1, t2 WHERE b=x AND b<>1 ORDER BY y DESC;
|
||||
} {1 1}
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
do_execsql_test 1020 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX t1a ON t1(a, b);
|
||||
-- Lots of rows of (1, 'no'), followed by a single (1, 'yes').
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
|
||||
INSERT INTO t1(a, b) SELECT 1, 'no' FROM c;
|
||||
INSERT INTO t1(a, b) VALUES(1, 'yes');
|
||||
CREATE TABLE t2(x PRIMARY KEY);
|
||||
INSERT INTO t2 VALUES('yes');
|
||||
SELECT DISTINCT a FROM t1, t2 WHERE x=b;
|
||||
ANALYZE;
|
||||
SELECT DISTINCT a FROM t1, t2 WHERE x=b;
|
||||
} {1 1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -68,4 +68,18 @@ ifcapable incrblob {
|
||||
} {SQLITE_CONSTRAINT}
|
||||
}
|
||||
|
||||
ifcapable stat4 {
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE p4 (id INTEGER NOT NULL PRIMARY KEY);
|
||||
INSERT INTO p4 VALUES(1), (2), (3);
|
||||
|
||||
CREATE TABLE c4(x INTEGER REFERENCES p4(id) DEFERRABLE INITIALLY DEFERRED);
|
||||
CREATE INDEX c4_x ON c4(x);
|
||||
INSERT INTO c4 VALUES(1), (2), (3);
|
||||
|
||||
ANALYZE;
|
||||
INSERT INTO p4(id) VALUES(4);
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
120
test/icu.test
120
test/icu.test
@ -15,7 +15,7 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !icu {
|
||||
ifcapable !icu&&!icu_collations {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
@ -35,54 +35,57 @@ proc test_expr {name settings expr result} {
|
||||
} $settings $expr] $result
|
||||
}
|
||||
|
||||
# Tests of the REGEXP operator.
|
||||
#
|
||||
test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1
|
||||
test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1
|
||||
test_expr icu-1.3 {i1='hello'} {i1 REGEXP '.ell'} 0
|
||||
test_expr icu-1.4 {i1='hello'} {i1 REGEXP '.ell.*'} 1
|
||||
test_expr icu-1.5 {i1=NULL} {i1 REGEXP '.ell.*'} {}
|
||||
ifcapable icu {
|
||||
|
||||
# Some non-ascii characters with defined case mappings
|
||||
#
|
||||
set ::EGRAVE "\xC8"
|
||||
set ::egrave "\xE8"
|
||||
# Tests of the REGEXP operator.
|
||||
#
|
||||
test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1
|
||||
test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1
|
||||
test_expr icu-1.3 {i1='hello'} {i1 REGEXP '.ell'} 0
|
||||
test_expr icu-1.4 {i1='hello'} {i1 REGEXP '.ell.*'} 1
|
||||
test_expr icu-1.5 {i1=NULL} {i1 REGEXP '.ell.*'} {}
|
||||
|
||||
set ::OGRAVE "\xD2"
|
||||
set ::ograve "\xF2"
|
||||
# Some non-ascii characters with defined case mappings
|
||||
#
|
||||
set ::EGRAVE "\xC8"
|
||||
set ::egrave "\xE8"
|
||||
|
||||
# That German letter that looks a bit like a B. The
|
||||
# upper-case version of which is "SS" (two characters).
|
||||
#
|
||||
set ::szlig "\xDF"
|
||||
set ::OGRAVE "\xD2"
|
||||
set ::ograve "\xF2"
|
||||
|
||||
# Tests of the upper()/lower() functions.
|
||||
#
|
||||
test_expr icu-2.1 {i1='HellO WorlD'} {upper(i1)} {HELLO WORLD}
|
||||
test_expr icu-2.2 {i1='HellO WorlD'} {lower(i1)} {hello world}
|
||||
test_expr icu-2.3 {i1=$::egrave} {lower(i1)} $::egrave
|
||||
test_expr icu-2.4 {i1=$::egrave} {upper(i1)} $::EGRAVE
|
||||
test_expr icu-2.5 {i1=$::ograve} {lower(i1)} $::ograve
|
||||
test_expr icu-2.6 {i1=$::ograve} {upper(i1)} $::OGRAVE
|
||||
test_expr icu-2.3 {i1=$::EGRAVE} {lower(i1)} $::egrave
|
||||
test_expr icu-2.4 {i1=$::EGRAVE} {upper(i1)} $::EGRAVE
|
||||
test_expr icu-2.5 {i1=$::OGRAVE} {lower(i1)} $::ograve
|
||||
test_expr icu-2.6 {i1=$::OGRAVE} {upper(i1)} $::OGRAVE
|
||||
# That German letter that looks a bit like a B. The
|
||||
# upper-case version of which is "SS" (two characters).
|
||||
#
|
||||
set ::szlig "\xDF"
|
||||
|
||||
test_expr icu-2.7 {i1=$::szlig} {upper(i1)} "SS"
|
||||
test_expr icu-2.8 {i1='SS'} {lower(i1)} "ss"
|
||||
# Tests of the upper()/lower() functions.
|
||||
#
|
||||
test_expr icu-2.1 {i1='HellO WorlD'} {upper(i1)} {HELLO WORLD}
|
||||
test_expr icu-2.2 {i1='HellO WorlD'} {lower(i1)} {hello world}
|
||||
test_expr icu-2.3 {i1=$::egrave} {lower(i1)} $::egrave
|
||||
test_expr icu-2.4 {i1=$::egrave} {upper(i1)} $::EGRAVE
|
||||
test_expr icu-2.5 {i1=$::ograve} {lower(i1)} $::ograve
|
||||
test_expr icu-2.6 {i1=$::ograve} {upper(i1)} $::OGRAVE
|
||||
test_expr icu-2.3 {i1=$::EGRAVE} {lower(i1)} $::egrave
|
||||
test_expr icu-2.4 {i1=$::EGRAVE} {upper(i1)} $::EGRAVE
|
||||
test_expr icu-2.5 {i1=$::OGRAVE} {lower(i1)} $::ograve
|
||||
test_expr icu-2.6 {i1=$::OGRAVE} {upper(i1)} $::OGRAVE
|
||||
|
||||
do_execsql_test icu-2.9 {
|
||||
SELECT upper(char(0xfb04,0xfb04,0xfb04,0xfb04));
|
||||
} {FFLFFLFFLFFL}
|
||||
test_expr icu-2.7 {i1=$::szlig} {upper(i1)} "SS"
|
||||
test_expr icu-2.8 {i1='SS'} {lower(i1)} "ss"
|
||||
|
||||
# In turkish (locale="tr_TR"), the lower case version of I
|
||||
# is "small dotless i" (code point 0x131 (decimal 305)).
|
||||
#
|
||||
set ::small_dotless_i "\u0131"
|
||||
test_expr icu-3.1 {i1='I'} {lower(i1)} "i"
|
||||
test_expr icu-3.2 {i1='I'} {lower(i1, 'tr_tr')} $::small_dotless_i
|
||||
test_expr icu-3.3 {i1='I'} {lower(i1, 'en_AU')} "i"
|
||||
do_execsql_test icu-2.9 {
|
||||
SELECT upper(char(0xfb04,0xfb04,0xfb04,0xfb04));
|
||||
} {FFLFFLFFLFFL}
|
||||
|
||||
# In turkish (locale="tr_TR"), the lower case version of I
|
||||
# is "small dotless i" (code point 0x131 (decimal 305)).
|
||||
#
|
||||
set ::small_dotless_i "\u0131"
|
||||
test_expr icu-3.1 {i1='I'} {lower(i1)} "i"
|
||||
test_expr icu-3.2 {i1='I'} {lower(i1, 'tr_tr')} $::small_dotless_i
|
||||
test_expr icu-3.3 {i1='I'} {lower(i1, 'en_AU')} "i"
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Test the collation sequence function.
|
||||
@ -124,22 +127,23 @@ do_test icu-4.3 {
|
||||
#
|
||||
# http://src.chromium.org/viewvc/chrome/trunk/src/third_party/sqlite/icu-regexp.patch?revision=34807&view=markup
|
||||
#
|
||||
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
|
||||
do_catchsql_test icu-5.2 {
|
||||
SELECT regexp('a[abc]c.*')
|
||||
} {1 {wrong number of arguments to function regexp()}}
|
||||
do_catchsql_test icu-5.3 {
|
||||
SELECT regexp('a[abc]c.*', 'abc', 'c')
|
||||
} {1 {wrong number of arguments to function regexp()}}
|
||||
do_catchsql_test icu-5.4 {
|
||||
SELECT 'abc' REGEXP 'a[abc]c.*'
|
||||
} {0 1}
|
||||
do_catchsql_test icu-5.4 { SELECT 'abc' REGEXP } {1 {near " ": syntax error}}
|
||||
do_catchsql_test icu-5.5 { SELECT 'abc' REGEXP, 1 } {1 {near ",": syntax error}}
|
||||
|
||||
|
||||
do_malloc_test icu-6.10 -sqlbody {
|
||||
SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
|
||||
ifcapable icu {
|
||||
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
|
||||
do_catchsql_test icu-5.2 {
|
||||
SELECT regexp('a[abc]c.*')
|
||||
} {1 {wrong number of arguments to function regexp()}}
|
||||
do_catchsql_test icu-5.3 {
|
||||
SELECT regexp('a[abc]c.*', 'abc', 'c')
|
||||
} {1 {wrong number of arguments to function regexp()}}
|
||||
do_catchsql_test icu-5.4 {
|
||||
SELECT 'abc' REGEXP 'a[abc]c.*'
|
||||
} {0 1}
|
||||
do_catchsql_test icu-5.4 {SELECT 'abc' REGEXP } {1 {near " ": syntax error}}
|
||||
do_catchsql_test icu-5.5 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}}
|
||||
|
||||
do_malloc_test icu-6.10 -sqlbody {
|
||||
SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
100
test/join2.test
100
test/join2.test
@ -92,4 +92,104 @@ do_catchsql_test 2.2 {
|
||||
SELECT * FROM aa JOIN cc ON (a=b) JOIN bb ON (b=c);
|
||||
} {0 {one one one}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a problem causing where.c to overlook opportunities to
|
||||
# omit unnecessary tables from a LEFT JOIN when UNIQUE, NOT NULL column
|
||||
# that makes this possible happens to be the leftmost in its table.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t1(k1 INTEGER PRIMARY KEY, k2, k3);
|
||||
CREATE TABLE t2(k2 INTEGER PRIMARY KEY, v2);
|
||||
|
||||
-- Prior to this problem being fixed, table t3_2 would be omitted from
|
||||
-- the join queries below, but if t3_1 were used in its place it would
|
||||
-- not.
|
||||
CREATE TABLE t3_1(k3 PRIMARY KEY, v3) WITHOUT ROWID;
|
||||
CREATE TABLE t3_2(v3, k3 PRIMARY KEY) WITHOUT ROWID;
|
||||
}
|
||||
|
||||
do_eqp_test 3.1 {
|
||||
SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_1 USING (k3);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
do_eqp_test 3.2 {
|
||||
SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_2 USING (k3);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that tables other than the rightmost can be omitted from a
|
||||
# LEFT JOIN query.
|
||||
#
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE c1(k INTEGER PRIMARY KEY, v1);
|
||||
CREATE TABLE c2(k INTEGER PRIMARY KEY, v2);
|
||||
CREATE TABLE c3(k INTEGER PRIMARY KEY, v3);
|
||||
|
||||
INSERT INTO c1 VALUES(1, 2);
|
||||
INSERT INTO c2 VALUES(2, 3);
|
||||
INSERT INTO c3 VALUES(3, 'v3');
|
||||
|
||||
INSERT INTO c1 VALUES(111, 1112);
|
||||
INSERT INTO c2 VALUES(112, 1113);
|
||||
INSERT INTO c3 VALUES(113, 'v1113');
|
||||
}
|
||||
do_execsql_test 4.1.1 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2);
|
||||
} {2 v3 1112 {}}
|
||||
do_execsql_test 4.1.2 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {2 v3 1112 {}}
|
||||
|
||||
do_execsql_test 4.1.3 {
|
||||
SELECT DISTINCT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {2 v3 1112 {}}
|
||||
|
||||
do_execsql_test 4.1.4 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {2 v3 2 v3 1112 {} 1112 {}}
|
||||
|
||||
do_eqp_test 4.2.1 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE c1}
|
||||
0 1 1 {SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
0 2 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
do_eqp_test 4.2.2 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE c1}
|
||||
0 1 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
# 2017-11-23 (Thanksgiving day)
|
||||
# OSSFuzz found an assertion fault in the new LEFT JOIN eliminator code.
|
||||
#
|
||||
do_execsql_test 4.3.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t1(x PRIMARY KEY) WITHOUT ROWID;
|
||||
CREATE TABLE t2(x);
|
||||
SELECT a.x
|
||||
FROM t1 AS a
|
||||
LEFT JOIN t1 AS b ON (a.x=b.x)
|
||||
LEFT JOIN t2 AS c ON (a.x=c.x);
|
||||
} {}
|
||||
do_execsql_test 4.3.1 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10)
|
||||
INSERT INTO t1(x) SELECT x FROM c;
|
||||
INSERT INTO t2(x) SELECT x+9 FROM t1;
|
||||
SELECT a.x, c.x
|
||||
FROM t1 AS a
|
||||
LEFT JOIN t1 AS b ON (a.x=b.x)
|
||||
LEFT JOIN t2 AS c ON (a.x=c.x);
|
||||
} {1 {} 2 {} 3 {} 4 {} 5 {} 6 {} 7 {} 8 {} 9 {} 10 10}
|
||||
|
||||
finish_test
|
||||
|
@ -150,4 +150,21 @@ do_execsql_test 502 {
|
||||
SELECT j FROM t502 WHERE i IN (1,2,3,4,5) ORDER BY j LIMIT 3;
|
||||
} {1 3 4}
|
||||
|
||||
# Ticket https://www.sqlite.org/src/info/123c9ba32130a6c9 2017-12-13
|
||||
# Incorrect result when an idnex is used for an ordered join.
|
||||
#
|
||||
# This test case is in the limit2.test module because the problem was first
|
||||
# exposed by check-in https://www.sqlite.org/src/info/559733b09e which
|
||||
# implemented the ORDER BY LIMIT optimization that limit2.test strives to
|
||||
# test.
|
||||
#
|
||||
do_execsql_test 600 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1,2);
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(x, y); INSERT INTO t2 VALUES(1,3);
|
||||
CREATE INDEX t1ab ON t1(a,b);
|
||||
SELECT y FROM t1, t2 WHERE a=x AND b<=y ORDER BY b DESC;
|
||||
} {3}
|
||||
|
||||
finish_test
|
||||
|
@ -15,6 +15,11 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix mjournal
|
||||
|
||||
if {[permutation]=="inmemory_journal"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Test that nothing bad happens if a journal file contains a pointer to
|
||||
# a master journal file that does not have a "-" in the name. At one point
|
||||
# this was causing a segfault on unix.
|
||||
@ -79,5 +84,80 @@ do_execsql_test 1.6 {
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that master journals are not created if the transaction involves
|
||||
# multiple temp files.
|
||||
#
|
||||
db close
|
||||
testvfs tvfs
|
||||
tvfs filter xOpen
|
||||
tvfs script open_cb
|
||||
set ::open ""
|
||||
proc open_cb {method file arglist} {
|
||||
lappend ::open $file
|
||||
}
|
||||
|
||||
proc contains_mj {} {
|
||||
foreach f $::open {
|
||||
set t [file tail $f]
|
||||
if {[string match *mj* $t]} { return 1 }
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
# Like [do_execsql_test], except that a boolean indicating whether or
|
||||
# not a master journal file was opened ([file tail] contains "mj") or
|
||||
# not. Example:
|
||||
#
|
||||
# do_hasmj_test 1.0 { SELECT 'a', 'b' } {0 a b}
|
||||
#
|
||||
proc do_hasmj_test {tn sql expected} {
|
||||
set ::open [list]
|
||||
uplevel [list do_test $tn [subst -nocommands {
|
||||
set res [execsql "$sql"]
|
||||
concat [contains_mj] [set res]
|
||||
}] [list {*}$expected]]
|
||||
}
|
||||
|
||||
forcedelete test.db
|
||||
forcedelete test.db2
|
||||
forcedelete test.db3
|
||||
sqlite3 db test.db -vfs tvfs
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
ATTACH 'test.db2' AS dbfile;
|
||||
ATTACH '' AS dbtemp;
|
||||
ATTACH ':memory:' AS dbmem;
|
||||
|
||||
CREATE TABLE t1(x);
|
||||
CREATE TABLE dbfile.t2(x);
|
||||
CREATE TABLE dbtemp.t3(x);
|
||||
CREATE TABLE dbmem.t4(x);
|
||||
}
|
||||
|
||||
# Two real files.
|
||||
do_hasmj_test 2.1 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
COMMIT;
|
||||
} {1}
|
||||
|
||||
# One real, one temp file.
|
||||
do_hasmj_test 2.2 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t3 VALUES(1);
|
||||
COMMIT;
|
||||
} {0}
|
||||
|
||||
# One file, one :memory: db.
|
||||
do_hasmj_test 2.3 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t4 VALUES(1);
|
||||
COMMIT;
|
||||
} {0}
|
||||
|
||||
finish_test
|
||||
|
||||
|
@ -17,8 +17,12 @@ source $testdir/tester.tcl
|
||||
|
||||
unset -nocomplain DEFAULT_SECDEL
|
||||
set DEFAULT_SECDEL 0
|
||||
ifcapable secure_delete {
|
||||
set DEFAULT_SECDEL 1
|
||||
ifcapable fast_secure_delete {
|
||||
set DEFAULT_SECDEL 2
|
||||
} else {
|
||||
ifcapable secure_delete {
|
||||
set DEFAULT_SECDEL 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,6 +93,14 @@ foreach {tn schema output} {
|
||||
} {
|
||||
}
|
||||
|
||||
10 {
|
||||
CREATE TABLE parent (id INTEGER PRIMARY KEY);
|
||||
CREATE TABLE child2 (id INT PRIMARY KEY, parentID INT REFERENCES parent)
|
||||
WITHOUT ROWID;
|
||||
} {
|
||||
CREATE INDEX 'child2_parentID' ON 'child2'('parentID'); --> parent(id)
|
||||
}
|
||||
|
||||
} {
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
|
100
test/snapshot3.test
Normal file
100
test/snapshot3.test
Normal file
@ -0,0 +1,100 @@
|
||||
# 2016 September 23
|
||||
#
|
||||
# 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 the sqlite3_snapshot_xxx() APIs.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !snapshot {finish_test; return}
|
||||
set testprefix snapshot3
|
||||
|
||||
# This test does not work with the inmemory_journal permutation. The reason
|
||||
# is that each connection opened as part of this permutation executes
|
||||
# "PRAGMA journal_mode=memory", which fails if the database is in wal mode
|
||||
# and there are one or more existing connections.
|
||||
if {[permutation]=="inmemory_journal"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This block of tests verifies that it is not possible to wrap the wal
|
||||
# file - using a writer or a "PRAGMA wal_checkpoint = TRUNCATE" - while
|
||||
# there is an open snapshot transaction (transaction opened using
|
||||
# sqlite3_snapshot_open()).
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(y);
|
||||
PRAGMA journal_mode = wal;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
INSERT INTO t1 VALUES(3);
|
||||
INSERT INTO t1 VALUES(4);
|
||||
} {wal}
|
||||
|
||||
do_test 1.1 {
|
||||
sqlite3 db2 test.db
|
||||
sqlite3 db3 test.db
|
||||
|
||||
execsql {SELECT * FROM sqlite_master} db2
|
||||
execsql {SELECT * FROM sqlite_master} db3
|
||||
|
||||
db2 trans { set snap [sqlite3_snapshot_get_blob db2 main] }
|
||||
db2 eval { SELECT * FROM t1 }
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test 1.2 {
|
||||
execsql BEGIN db2
|
||||
sqlite3_snapshot_open_blob db2 main $snap
|
||||
db2 eval { SELECT * FROM t1 }
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test 1.2 {
|
||||
execsql END db2
|
||||
execsql { PRAGMA wal_checkpoint }
|
||||
|
||||
execsql BEGIN db2
|
||||
sqlite3_snapshot_open_blob db2 main $snap
|
||||
db2 eval { SELECT * FROM t1 }
|
||||
} {1 2 3 4}
|
||||
|
||||
set sz [file size test.db-wal]
|
||||
do_test 1.3 {
|
||||
execsql { PRAGMA wal_checkpoint = truncate }
|
||||
file size test.db-wal
|
||||
} $sz
|
||||
|
||||
do_test 1.4 {
|
||||
execsql BEGIN db3
|
||||
list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg
|
||||
} {0 {}}
|
||||
|
||||
do_test 1.5 {
|
||||
db3 eval { SELECT * FROM t1; END }
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test 1.6 {
|
||||
db2 eval { SELECT * FROM t1; END }
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test 1.7 {
|
||||
execsql { PRAGMA wal_checkpoint = truncate }
|
||||
file size test.db-wal
|
||||
} 0
|
||||
|
||||
do_test 1.8 {
|
||||
execsql BEGIN db3
|
||||
list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg
|
||||
} {1 SQLITE_BUSY_SNAPSHOT}
|
||||
|
||||
finish_test
|
||||
|
@ -78,3 +78,5 @@ db cache flush
|
||||
do_execsql_test stmtvtab1-160 {
|
||||
SELECT * FROM sqlite_stmt WHERE NOT busy;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
@ -31,3 +31,5 @@ do_test bug-20100512-3 {
|
||||
sqlite3_column_int $STMT 0
|
||||
} {555}
|
||||
sqlite3_finalize $STMT
|
||||
|
||||
finish_test
|
||||
|
@ -23,3 +23,5 @@ do_execsql_test tkt-7a31705a7e6-1.1 {
|
||||
CREATE TABLE t2x (b INTEGER PRIMARY KEY);
|
||||
SELECT t1.a FROM ((t1 JOIN t2 ON t1.a=t2.a) AS x JOIN t2x ON x.b=t2x.b) as y;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
@ -91,3 +91,5 @@ do_execsql_test 4.5 {
|
||||
do_execsql_test 4.6 {
|
||||
SELECT '1234x'/'10y';
|
||||
} {123.4}
|
||||
|
||||
finish_test
|
||||
|
@ -82,3 +82,5 @@ do_test tkt3334-1.10 {
|
||||
SELECT count(*) FROM (SELECT a FROM t1) WHERE a=1;
|
||||
}
|
||||
} {3}
|
||||
|
||||
finish_test
|
||||
|
@ -62,4 +62,17 @@ do_execsql_test 200 {
|
||||
SELECT b FROM t2 ORDER BY b;
|
||||
} {20202 20203 20302 20303 30202 30203 30302 30303 40202 40203 40302 40303 50202 50203 50302 50303}
|
||||
|
||||
# At one point the following was causing an assert() to fail.
|
||||
#
|
||||
do_execsql_test 300 {
|
||||
CREATE TABLE t4(x);
|
||||
CREATE TRIGGER tr4 AFTER INSERT ON t4 BEGIN
|
||||
SELECT 0x2147483648e0e0099 AS y WHERE y;
|
||||
END;
|
||||
}
|
||||
|
||||
do_catchsql_test 310 {
|
||||
INSERT INTO t4 VALUES(1);
|
||||
} {1 {hex literal too big: 0x2147483648e0e0099}}
|
||||
|
||||
finish_test
|
||||
|
@ -65,3 +65,5 @@ do_test vacuum4-1.1 {
|
||||
VACUUM;
|
||||
}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
@ -30,3 +30,5 @@ foreach start {0 100 10000 1000000 0x10000000} {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
@ -52,21 +52,21 @@ do_test 1.1 {
|
||||
set ::locks [list]
|
||||
sqlite3 db test.db -vfs T
|
||||
execsql { SELECT * FROM x }
|
||||
lrange $::locks 0 3
|
||||
} [list {0 1 lock exclusive} {1 7 lock exclusive} \
|
||||
{1 7 unlock exclusive} {0 1 unlock exclusive} \
|
||||
lrange $::locks 0 5
|
||||
} [list {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \
|
||||
{1 2 unlock exclusive} {4 4 unlock exclusive} {0 1 unlock exclusive} \
|
||||
]
|
||||
do_test 1.2 {
|
||||
db close
|
||||
set ::locks [list]
|
||||
sqlite3 db test.db -vfs T
|
||||
execsql { SELECT * FROM x }
|
||||
lrange $::locks 0 3
|
||||
} [list {0 1 lock exclusive} {1 7 lock exclusive} \
|
||||
{1 7 unlock exclusive} {0 1 unlock exclusive} \
|
||||
lrange $::locks 0 5
|
||||
} [list {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \
|
||||
{1 2 unlock exclusive} {4 4 unlock exclusive} {0 1 unlock exclusive} \
|
||||
]
|
||||
proc lock_callback {method filename handle lock} {
|
||||
if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY }
|
||||
if {$lock == "1 2 lock exclusive"} { return SQLITE_BUSY }
|
||||
return SQLITE_OK
|
||||
}
|
||||
puts "# Warning: This next test case causes SQLite to call xSleep(1) 100 times."
|
||||
@ -90,6 +90,18 @@ do_test 1.4 {
|
||||
sqlite3 db test.db -vfs T
|
||||
catchsql { SELECT * FROM x }
|
||||
} {1 {locking protocol}}
|
||||
|
||||
puts "# Warning: Third time!"
|
||||
proc lock_callback {method filename handle lock} {
|
||||
if {$lock == "4 4 lock exclusive"} { return SQLITE_BUSY }
|
||||
return SQLITE_OK
|
||||
}
|
||||
do_test 1.5 {
|
||||
db close
|
||||
set ::locks [list]
|
||||
sqlite3 db test.db -vfs T
|
||||
catchsql { SELECT * FROM x }
|
||||
} {1 {locking protocol}}
|
||||
db close
|
||||
T delete
|
||||
|
||||
@ -135,13 +147,14 @@ T filter xShmLock
|
||||
T script lock_callback
|
||||
|
||||
proc lock_callback {method file handle spec} {
|
||||
if {$spec == "1 7 unlock exclusive"} {
|
||||
if {$spec == "1 2 unlock exclusive"} {
|
||||
T filter {}
|
||||
set ::r [catchsql { SELECT * FROM b } db2]
|
||||
}
|
||||
}
|
||||
sqlite3 db test.db
|
||||
sqlite3 db2 test.db
|
||||
puts "# Warning: Another slow test!"
|
||||
do_test 2.5 {
|
||||
execsql { SELECT * FROM b }
|
||||
} {Tehran Qom Markazi Qazvin Gilan Ardabil}
|
||||
@ -157,12 +170,13 @@ sqlite3 db2 test.db
|
||||
T filter xShmLock
|
||||
T script lock_callback
|
||||
proc lock_callback {method file handle spec} {
|
||||
if {$spec == "1 7 unlock exclusive"} {
|
||||
if {$spec == "1 2 unlock exclusive"} {
|
||||
T filter {}
|
||||
set ::r [catchsql { SELECT * FROM b } db2]
|
||||
}
|
||||
}
|
||||
unset ::r
|
||||
puts "# Warning: Last one!"
|
||||
do_test 2.7 {
|
||||
execsql { SELECT * FROM b }
|
||||
} {Tehran Qom Markazi Qazvin Gilan Ardabil}
|
||||
|
@ -262,8 +262,9 @@ do_multiclient_test tn {
|
||||
}
|
||||
} {500}
|
||||
do_test $TN.4.2.2 {
|
||||
file size test.db-wal
|
||||
} {461152}
|
||||
set sz [file size test.db-wal]
|
||||
expr {$sz>400000 && $sz<500000}
|
||||
} {1}
|
||||
do_test $TN.4.2.4 {
|
||||
file_control_persist_wal db 1; db close
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user