Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 365852a6bc | |||
| 1af5e9a494 | |||
| bd1334dfd9 | |||
| fb3828c25f | |||
| 10431c306b | |||
| 0b52b7d0cd | |||
| b69577d3b8 | |||
| 15ad92f2ae | |||
| 9bf3da8eab | |||
| 6d4fb833b7 | |||
| 7cfbeb7fb5 | |||
| 25ca568251 | |||
| 1e4040a4b4 | |||
| 4d26d585d6 | |||
| 534a58a76d | |||
| 951596cdef | |||
| 0ecdeb2414 | |||
| d1cf7e2972 | |||
| ff07ccadee | |||
| 41692e9d7c | |||
| 3778ac15dd | |||
| 2afc704ad8 | |||
| 906b662060 | |||
| 27381bd519 | |||
| a9ef7097c7 | |||
| f3aef49cbd | |||
| 3a5676ce26 | |||
| bee29f4ac1 | |||
| 986d3b95bb | |||
| 40f9837ff6 | |||
| 9f8cf9da27 | |||
| eee50ca5a7 | |||
| 602acb4871 | |||
| c5aae5c90b | |||
| c6aed5424b | |||
| d40d7ec78b | |||
| 0bf1f496b8 | |||
| 54a7347aa1 | |||
| 104a7bba8c | |||
| 39210bdaa6 | |||
| a5657d710b | |||
| 94e7bd55bd | |||
| 47e909bb15 | |||
| 5b3696e8a6 | |||
| a8ab60c648 | |||
| 86596e552e | |||
| efd95a7aca | |||
| da56b15e95 | |||
| 354bfe0363 | |||
| ca94d8bf82 | |||
| 9f4beedb6f | |||
| bbd91944dd | |||
| 444d26065e | |||
| 2e5de2f2b3 | |||
| b7787eef7a | |||
| 5240aebdd8 | |||
| b2c062df71 | |||
| 100335be77 | |||
| 8a3d62224c | |||
| db26d4c9e1 | |||
| 65a0ce16aa | |||
| 4856698fa5 | |||
| 8e93b10a4e | |||
| b29010cd4f | |||
| 72903821e3 | |||
| b9a93d70b8 | |||
| b469f46083 | |||
| 2a58e9cc32 | |||
| e0a55f443b | |||
| 697e965299 | |||
| 29ecd8a077 | |||
| 08bd9f83ce | |||
| 0b12e7f860 | |||
| 9c88d68988 | |||
| cd2f58b374 | |||
| 230bd63011 | |||
| 4278d53efa | |||
| 7d20844542 | |||
| d9c9b78e6c | |||
| 901e994b8b | |||
| d3842765ae | |||
| a4bfd7fde8 | |||
| 7f322e791c | |||
| 10fc727d35 | |||
| e14cd93f2e | |||
| 81d7fd13e4 | |||
| 91412b2446 |
@@ -59,10 +59,6 @@ LIBREADLINE = @TARGET_READLINE_LIBS@
|
||||
#
|
||||
TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@
|
||||
|
||||
# Do threads override each others locks by default (1), or do we test (-1)
|
||||
#
|
||||
TCC += -DSQLITE_THREAD_OVERRIDE_LOCK=@THREADSOVERRIDELOCKS@
|
||||
|
||||
# Any target libraries which libsqlite must be linked against
|
||||
#
|
||||
TLIBS = @LIBS@
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.7.4.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.7.5.
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.7.4'
|
||||
PACKAGE_STRING='sqlite 3.7.4'
|
||||
PACKAGE_VERSION='3.7.5'
|
||||
PACKAGE_STRING='sqlite 3.7.5'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@@ -869,7 +869,6 @@ VERSION_NUMBER
|
||||
BUILD_CC
|
||||
SQLITE_THREADSAFE
|
||||
XTHREADCONNECT
|
||||
THREADSOVERRIDELOCKS
|
||||
ALLOWRELEASE
|
||||
TEMP_STORE
|
||||
BUILD_EXEEXT
|
||||
@@ -912,7 +911,6 @@ enable_largefile
|
||||
with_hints
|
||||
enable_threadsafe
|
||||
enable_cross_thread_connections
|
||||
enable_threads_override_locks
|
||||
enable_releasemode
|
||||
enable_tempstore
|
||||
enable_tcl
|
||||
@@ -1487,7 +1485,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.7.4 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.7.5 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1552,7 +1550,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.4:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.5:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1569,8 +1567,6 @@ Optional Features:
|
||||
--enable-threadsafe Support threadsafe operation
|
||||
--enable-cross-thread-connections
|
||||
Allow connection sharing across threads
|
||||
--enable-threads-override-locks
|
||||
Threads can override each others locks
|
||||
--enable-releasemode Support libtool link to release mode
|
||||
--enable-tempstore Use an in-ram database for temporary tables
|
||||
(never,no,yes,always)
|
||||
@@ -1670,7 +1666,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.7.4
|
||||
sqlite configure 3.7.5
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1684,7 +1680,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.7.4, which was
|
||||
It was created by sqlite $as_me 3.7.5, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -3738,13 +3734,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
|
||||
else
|
||||
lt_cv_nm_interface="BSD nm"
|
||||
echo "int some_variable = 0;" > conftest.$ac_ext
|
||||
(eval echo "\"\$as_me:3741: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3737: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3744: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:3740: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3747: output\"" >&5)
|
||||
(eval echo "\"\$as_me:3743: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
@@ -4966,7 +4962,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 4969 "configure"' > conftest.$ac_ext
|
||||
echo '#line 4965 "configure"' > conftest.$ac_ext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6835,11 +6831,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:6838: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6834: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6842: \$? = $ac_status" >&5
|
||||
echo "$as_me:6838: \$? = $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.
|
||||
@@ -7174,11 +7170,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:7177: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7173: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7181: \$? = $ac_status" >&5
|
||||
echo "$as_me:7177: \$? = $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.
|
||||
@@ -7279,11 +7275,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:7282: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7278: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7286: \$? = $ac_status" >&5
|
||||
echo "$as_me:7282: \$? = $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
|
||||
@@ -7334,11 +7330,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:7337: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7333: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7341: \$? = $ac_status" >&5
|
||||
echo "$as_me:7337: \$? = $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
|
||||
@@ -10147,7 +10143,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 10150 "configure"
|
||||
#line 10146 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -10243,7 +10239,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 10246 "configure"
|
||||
#line 10242 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -12580,32 +12576,6 @@ $as_echo "yes" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
##########
|
||||
# Do we want to set threadsOverrideEachOthersLocks variable to be 1 (true) by
|
||||
# default. Normally, a test at runtime is performed to determine the
|
||||
# appropriate value of this variable. Use this option only if you're sure that
|
||||
# threads can safely override each others locks in all runtime situations.
|
||||
#
|
||||
# Check whether --enable-threads-override-locks was given.
|
||||
if test "${enable_threads_override_locks+set}" = set; then
|
||||
enableval=$enable_threads_override_locks;
|
||||
else
|
||||
enable_threads_override_locks=no
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:$LINENO: checking whether threads can override each others locks" >&5
|
||||
$as_echo_n "checking whether threads can override each others locks... " >&6; }
|
||||
if test "$enable_threads_override_locks" = "no"; then
|
||||
THREADSOVERRIDELOCKS='-1'
|
||||
{ $as_echo "$as_me:$LINENO: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
else
|
||||
THREADSOVERRIDELOCKS='1'
|
||||
{ $as_echo "$as_me:$LINENO: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
##########
|
||||
# Do we want to support release
|
||||
#
|
||||
@@ -13972,7 +13942,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.7.4, which was
|
||||
This file was extended by sqlite $as_me 3.7.5, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -14025,7 +13995,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.7.4
|
||||
sqlite config.status 3.7.5
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
@@ -268,24 +268,6 @@ else
|
||||
fi
|
||||
AC_SUBST(XTHREADCONNECT)
|
||||
|
||||
##########
|
||||
# Do we want to set threadsOverrideEachOthersLocks variable to be 1 (true) by
|
||||
# default. Normally, a test at runtime is performed to determine the
|
||||
# appropriate value of this variable. Use this option only if you're sure that
|
||||
# threads can safely override each others locks in all runtime situations.
|
||||
#
|
||||
AC_ARG_ENABLE(threads-override-locks,
|
||||
AC_HELP_STRING([--enable-threads-override-locks],[Threads can override each others locks]),,enable_threads_override_locks=no)
|
||||
AC_MSG_CHECKING([whether threads can override each others locks])
|
||||
if test "$enable_threads_override_locks" = "no"; then
|
||||
THREADSOVERRIDELOCKS='-1'
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
THREADSOVERRIDELOCKS='1'
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
AC_SUBST(THREADSOVERRIDELOCKS)
|
||||
|
||||
##########
|
||||
# Do we want to support release
|
||||
#
|
||||
|
||||
+8
-1
@@ -3106,9 +3106,16 @@ char *sqlite3Fts3FindPositions(
|
||||
assert( pExpr->isLoaded );
|
||||
if( pExpr->aDoclist ){
|
||||
char *pEnd = &pExpr->aDoclist[pExpr->nDoclist];
|
||||
char *pCsr = pExpr->pCurrent;
|
||||
char *pCsr;
|
||||
|
||||
if( pExpr->pCurrent==0 ){
|
||||
pExpr->pCurrent = pExpr->aDoclist;
|
||||
pExpr->iCurrent = 0;
|
||||
pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent);
|
||||
}
|
||||
pCsr = pExpr->pCurrent;
|
||||
assert( pCsr );
|
||||
|
||||
while( pCsr<pEnd ){
|
||||
if( pExpr->iCurrent<iDocid ){
|
||||
fts3PoslistCopy(0, &pCsr);
|
||||
|
||||
+3
-21
@@ -226,7 +226,7 @@ static int fts3ExprNearTrim(Fts3Expr *pExpr){
|
||||
** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
|
||||
** fts3ExprLoadDoclists().
|
||||
*/
|
||||
static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
int rc = SQLITE_OK;
|
||||
LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
|
||||
|
||||
@@ -246,22 +246,6 @@ static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is an fts3ExprIterate() callback used while loading the doclists
|
||||
** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
|
||||
** fts3ExprLoadDoclists().
|
||||
*/
|
||||
static int fts3ExprLoadDoclistsCb2(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
UNUSED_PARAMETER(iPhrase);
|
||||
UNUSED_PARAMETER(ctx);
|
||||
if( pExpr->aDoclist ){
|
||||
pExpr->pCurrent = pExpr->aDoclist;
|
||||
pExpr->iCurrent = 0;
|
||||
pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent, &pExpr->iCurrent);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Load the doclists for each phrase in the query associated with FTS3 cursor
|
||||
** pCsr.
|
||||
@@ -280,10 +264,7 @@ static int fts3ExprLoadDoclists(
|
||||
int rc; /* Return Code */
|
||||
LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
|
||||
sCtx.pCsr = pCsr;
|
||||
rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb1, (void *)&sCtx);
|
||||
if( rc==SQLITE_OK ){
|
||||
(void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
|
||||
}
|
||||
rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
|
||||
if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
|
||||
if( pnToken ) *pnToken = sCtx.nToken;
|
||||
return rc;
|
||||
@@ -975,6 +956,7 @@ static int fts3MatchinfoSelectDoctotal(
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
pStmt = *ppStmt;
|
||||
assert( sqlite3_data_count(pStmt)==1 );
|
||||
|
||||
a = sqlite3_column_blob(pStmt, 0);
|
||||
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||
|
||||
+19
-15
@@ -1102,24 +1102,28 @@ int sqlite3Fts3SegReaderCost(
|
||||
** to right.
|
||||
*/
|
||||
sqlite3_stmt *pStmt;
|
||||
rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
|
||||
sqlite3_int64 nDoc = 0;
|
||||
sqlite3_int64 nByte = 0;
|
||||
const char *a;
|
||||
rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
|
||||
if( rc ) return rc;
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
sqlite3_int64 nDoc = 0;
|
||||
sqlite3_int64 nByte = 0;
|
||||
const char *a = sqlite3_column_blob(pStmt, 0);
|
||||
if( a ){
|
||||
const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
|
||||
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||
while( a<pEnd ){
|
||||
a += sqlite3Fts3GetVarint(a, &nByte);
|
||||
}
|
||||
a = sqlite3_column_blob(pStmt, 0);
|
||||
if( a ){
|
||||
const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
|
||||
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||
while( a<pEnd ){
|
||||
a += sqlite3Fts3GetVarint(a, &nByte);
|
||||
}
|
||||
|
||||
pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz - 1) / pgsz);
|
||||
}
|
||||
if( nDoc==0 || nByte==0 ){
|
||||
sqlite3_reset(pStmt);
|
||||
return SQLITE_CORRUPT;
|
||||
}
|
||||
|
||||
pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz);
|
||||
assert( pCsr->nRowAvg>0 );
|
||||
rc = sqlite3_reset(pStmt);
|
||||
if( rc!=SQLITE_OK || pCsr->nRowAvg==0 ) return rc;
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
/* Assume that a blob flows over onto overflow pages if it is larger
|
||||
@@ -2240,7 +2244,7 @@ int sqlite3Fts3SegReaderIterate(
|
||||
nByte = sqlite3Fts3VarintLen(iDocid-iPrev) + (isRequirePos?nList+1:0);
|
||||
if( nDoclist+nByte>nAlloc ){
|
||||
char *aNew;
|
||||
nAlloc = nDoclist+nByte*2;
|
||||
nAlloc = (nDoclist+nByte)*2;
|
||||
aNew = sqlite3_realloc(aBuffer, nAlloc);
|
||||
if( !aNew ){
|
||||
rc = SQLITE_NOMEM;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Version\s3.7.4\srelease\scandidate\s4
|
||||
D 2010-12-07T20:14:09
|
||||
C SQLite\sversion\s3.7.5\srelease\scandidate\s2
|
||||
D 2011-01-28T17:03:50.592
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 4547616ad2286053af6ccccefa242dc925e49bf0
|
||||
F Makefile.in de6498556d536ae60bb8bb10e8c1ba011448658c
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 3466c92381170cedd7c04fc6ac2760b53a61cde9
|
||||
F VERSION de8d3477dbf0d6cc226ccc6e046273627eb55fc5
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
|
||||
@@ -25,8 +25,8 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 868fdb48c028421a203470e15c69ada15b9ba673
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure daed6cfdb4c1449a4335b3eeddc0d836e33fb54e x
|
||||
F configure.ac 699040cc9abb7465dca5a2972bc89d227fd8f734
|
||||
F configure 0eb10c03a6536d8e5ce52ab70fda0a152d8a3262 x
|
||||
F configure.ac 87a3c71bbe9c925381c154413eea7f3cdc397244
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
|
||||
F doc/pager-invariants.txt 870107036470d7c419e93768676fae2f8749cf9e
|
||||
@@ -64,7 +64,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 44f998657ec849362484bb389c5728e821fc8c59
|
||||
F ext/fts3/fts3.c 28ada7d1c700e57b072b2c95d70565b05925fa46
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h a6c69c1c5e2c8c19172ddff42d262c087dcd7337
|
||||
F ext/fts3/fts3_expr.c 5f49e0deaf723724b08100bb3ff40aab02ad0c93
|
||||
@@ -72,11 +72,11 @@ F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
|
||||
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
||||
F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
|
||||
F ext/fts3/fts3_porter.c d61cfd81fb0fd8fbcb25adcaee0ba671aefaa5c2
|
||||
F ext/fts3/fts3_snippet.c 6c87b55965124920d6461d79ea44b22cc3f307aa
|
||||
F ext/fts3/fts3_snippet.c 196c5e6cde57bfc1907c2d60e9c29590e4f93fb6
|
||||
F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d
|
||||
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
||||
F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
|
||||
F ext/fts3/fts3_write.c 13012755d59e5d4f09a41fd3b5ad17de7dafe3e7
|
||||
F ext/fts3/fts3_write.c 3eea26b9ca4219e1711b0db74fd5a9d448a6afbb
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||
@@ -116,25 +116,25 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c 6a0c176e64a34929a4436048066a84ef4f1445b3
|
||||
F src/analyze.c 1ea594a912a14138e20a05db09d9065e46f29a2a
|
||||
F src/analyze.c a038162344265ac21dfb24b3fcc06c666ebb9c07
|
||||
F src/attach.c 252c4f7e36cc219349451ed63e278c60e80b26f3
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c d5b0137bc20327af08c14772227cc35134839c30
|
||||
F src/backup.c 6728d6d48d55b449af76a3e51c0808849cb32a2e
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c b70bf1dc563ec532851715ce51aa1ea0c0c592b9
|
||||
F src/btree.c 9004c98fc576306eee4fc0562ffeb362ef53912c
|
||||
F src/btree.h 10f9296bf4edf034f5adce921b7b4383a56a1c90
|
||||
F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0
|
||||
F src/btreeInt.h 20f73dc93b1eeb83afd7259fbc6bd7dcf2df7fe4
|
||||
F src/build.c 00a327120d81ace6267e714ae8010c997d55de5d
|
||||
F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
|
||||
F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4
|
||||
F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b
|
||||
F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd
|
||||
F src/expr.c 1810f3056b11de99cc10e24629edf00e5fbd3a75
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 17950a28f28b23e8ad3feaac5fc88c324d2f600a
|
||||
F src/func.c 2b7cf54d2569c2eba42fe81165d1932b546681a3
|
||||
F src/func.c cb41f614edc43b00bfeb030f9768e80eaff47edd
|
||||
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
@@ -144,8 +144,8 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e
|
||||
F src/main.c 721e5530b14b91a1fb6aead279af8b8729fa9a20
|
||||
F src/malloc.c 3d7284cd9346ab6e3945535761e68c23c6cf40ef
|
||||
F src/main.c 6653e46db7ecb5a7449d8a12900147192f748b97
|
||||
F src/malloc.c 92d59a007d7a42857d4e9454aa25b6b703286be1
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
|
||||
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
|
||||
@@ -156,37 +156,37 @@ F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f
|
||||
F src/mutex.h fe2ef5e1c4dae531d5a544f9241f19c56d26803d
|
||||
F src/mutex_noop.c d5cfbca87168c661a0b118cd8e329a908e453151
|
||||
F src/mutex_os2.c 6a62583e374ba3ac1a3fcc0da2bfdac7d3942689
|
||||
F src/mutex_unix.c abb8c98a6c27c57280e71522d059e929c708d019
|
||||
F src/mutex_w32.c b7ed3366a1d44a62a17d4eaefdaa2e7c25f944c2
|
||||
F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579
|
||||
F src/mutex_w32.c 3ade5ae71449d1d023f0ebb3184c2ae6aa9307e4
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
|
||||
F src/os_unix.c 0240c5b547b4cf585c8cac351a95c3e85ce00772
|
||||
F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad
|
||||
F src/pager.c c0aca5c733c15a16fe158c3215d857841a4e5381
|
||||
F src/os_os2.c 2e452c9f2ca507623ad351c33a8a8b27849b1863
|
||||
F src/os_unix.c 1be46a35bad4bec5171e4de88aaff817260eb378
|
||||
F src/os_win.c 9abdcdd925416d854eabb0996c96debd92abfef5
|
||||
F src/pager.c b0fcbe3038fd08b111e1cf1deddd5f42418004d8
|
||||
F src/pager.h 0ea59db2a33bc6c2c02cae34de33367e1effdf76
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c e9578a3beac26f229ee558a4e16c863f2498185f
|
||||
F src/pcache1.c d548e31beafa792d1994b663a29a5303569efc4e
|
||||
F src/pragma.c 8a6cd3c787f882fa44f6490d2411fc26839ce8f3
|
||||
F src/prepare.c c8b877b80721d70b68053fd9ae30ec6d63eeeadc
|
||||
F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
|
||||
F src/prepare.c 395b3fab1b93f45b6aa194b23ebc201221c47b99
|
||||
F src/printf.c df2ff3bb5409e8958136933342c46464fbd017e7
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 8a7ba246b0b4bb45df7fbc52681728a0e3deaaa7
|
||||
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
|
||||
F src/sqlite.h.in b7e8a4e4749cfae9c99e1fbe3f9f87763cbbf7a2
|
||||
F src/shell.c 83c6f0cc5a79a081c7b9ddfe4f557b47e0bad976
|
||||
F src/sqlite.h.in 76955fcd1c5371268ecc8afe0ce6c49ea750ae38
|
||||
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
|
||||
F src/sqliteInt.h b96d5ddb8b419a2ed7cf69a7778b53872d73e8a7
|
||||
F src/sqliteInt.h 45926deaf59b1ce3f55d21d5f91a8cecb6a7eb4c
|
||||
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
|
||||
F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 77c5c4b8ac7b2d94ee480e1ad626fbd921d948e4
|
||||
F src/test1.c 397809a3069c171a507a49b6f6edfc4255b0afbc
|
||||
F src/tclsqlite.c 549859dc2c143f3deb6a92636a2d27973652c164
|
||||
F src/test1.c 771407a49ae199241f0efb7055634e4a1899c026
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
|
||||
F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
|
||||
@@ -199,7 +199,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
||||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
|
||||
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
|
||||
F src/test_config.c 55918873f0a2ebbd5b52417319987f9f99c401fa
|
||||
F src/test_config.c 9f025a7f3686c94e82dc6d6bd3cbf0f89cd67487
|
||||
F src/test_demovfs.c 0aed671636735116fc872c5b03706fd5612488b5
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20
|
||||
@@ -209,13 +209,13 @@ F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
|
||||
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
|
||||
F src/test_journal.c 785edd54f963aefb3c1628124170a56697c68c70
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c 09a88f0c111201dc4f8c20470aa1b5f611d59200
|
||||
F src/test_malloc.c fd6188b1501c0010fb4241ddc9f0d5ac402c688d
|
||||
F src/test_multiplex.c 5990431a852aa21c9a67da748f23d2cf1e21f8fc
|
||||
F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
|
||||
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
|
||||
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
|
||||
F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
|
||||
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
|
||||
F src/test_quota.c 6d32dd5885777f432db91e3a6c9e39008dd67d86
|
||||
F src/test_quota.c b5576f17d701af461effd7ca1e71f0d100071192
|
||||
F src/test_rtree.c 30c981837445a4e187ee850a49c4760d9642f7c3
|
||||
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
@@ -223,7 +223,7 @@ F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
|
||||
F src/test_vfs.c e10fcca756cafa89438311b31522ac1f95bf784b
|
||||
F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
|
||||
F src/trigger.c b8bedb9c0084ceb51a40f54fcca2ce048c8de852
|
||||
@@ -233,17 +233,17 @@ F src/util.c ab1c92426494f499f42b9e307537b03e923d75c1
|
||||
F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
|
||||
F src/vdbe.c 5d310eaf1a4d8383602126fa82e01291ab7d3cf3
|
||||
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
|
||||
F src/vdbeInt.h 1f2137b905969f4de0648256aeb73abdf88f9213
|
||||
F src/vdbeapi.c fb0036185b3c56e15916a5ee96309cd4acf6818f
|
||||
F src/vdbeaux.c b810a66902ee40c71cdb9c64f43760da516c91df
|
||||
F src/vdbeInt.h 6e6f28e9bccc6c703dca1372fd661c57b5c15fb0
|
||||
F src/vdbeapi.c 8e9324fd35eb70d0b5904bd1af40f2598744dc4d
|
||||
F src/vdbeaux.c 33448d23b857654dd69ed2103611f5c733606f68
|
||||
F src/vdbeblob.c 18955f0ee6b133cd08e1592010cb9a6b11e9984c
|
||||
F src/vdbemem.c 411649a35686f54268ccabeda175322c4697f5a6
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
|
||||
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
|
||||
F src/wal.c f26b8d297bd11cb792e609917f9d4c6718ac8e0e
|
||||
F src/wal.c dbca424f71678f663a286ab2a98f947af1d412a7
|
||||
F src/wal.h c1aac6593a0b02b15dc625987e619edeab39292e
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c fa22d45b2577c77146f2e894d58011d472d64103
|
||||
F src/where.c af069e6b53234118014dabfece96a9515b69d76b
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 51756962d522e474338e9b2ebb26e7364d4aa125
|
||||
@@ -255,6 +255,7 @@ F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test c1eb87067fc16ece7c07e823d6395fd831b270c5
|
||||
F test/analyze2.test 3bde8f0879d9c1f2df3af21fcf42e706d8ee1e43
|
||||
F test/analyze3.test 820ddfb7591b49607fbaf77240c7955ac3cabb04
|
||||
F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045
|
||||
F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3
|
||||
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
@@ -295,7 +296,7 @@ F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
|
||||
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 754baab2f18089fc9bcba7afaeb4dc907c6c6de2
|
||||
F test/capi2.test 00032d7504b9c14f1b36331670c5e7b0f73e3c5d
|
||||
F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360
|
||||
F test/capi3.test 1945a2ba75e3f4c49d5beb8fc092115b6292d471
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test bea67403a5e37a4b33230ee4723e315a2ffb31e7
|
||||
@@ -376,14 +377,14 @@ F test/enc4.test 4b575ef09e0eff896e73bd24076f96c2aa6a42de
|
||||
F test/eqp.test 69670e7919030f21de29fb99bf1d68f97aedcbdb
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062
|
||||
F test/exclusive2.test 76e63c05349cb70d09d60b99d2ae625525ff5155
|
||||
F test/exclusive2.test b65264c3e76e1db6c6eda15c02000a40743f6541
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/expr.test 620a636cf7b7d4e5834a0b9d83a4da372e24a7b7
|
||||
F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6
|
||||
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
|
||||
F test/filefmt.test f77c92141960b7933bc6691631d2ad62257ef40a
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
F test/fkey2.test e028cd80aa0bd38541c99214e3ba2dfccadffe6f
|
||||
F test/fkey2.test 080969fe219b3b082b0e097ac18c6af2e5b0631f
|
||||
F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
|
||||
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
@@ -452,7 +453,7 @@ F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246
|
||||
F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b
|
||||
F test/fts3matchinfo.test ae910aa666285e14743a80799214bfb3f1aab8f2
|
||||
F test/fts3matchinfo.test cc0b009edbbf575283d5fdb53271179e0d8019ba
|
||||
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
|
||||
F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2
|
||||
F test/fts3rnd.test 2b1a579be557ab8ac54a51b39caa4aa8043cc4ad
|
||||
@@ -511,7 +512,7 @@ F test/journal2.test 50a3604768494d4a337f194f0a9480e7c57dcb72
|
||||
F test/journal3.test ff175219be1b02d2f7e54297ad7e491b7533edb6
|
||||
F test/jrnlmode.test e3fe6c4a2c3213d285650dc8e33aab7eaaa5ce53
|
||||
F test/jrnlmode2.test a19e28de1a6ec898067e46a122f1b71c9323bf00
|
||||
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
|
||||
F test/jrnlmode3.test c6522b276ba315fd1416198de6fc1da9e72409fb
|
||||
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
|
||||
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
@@ -528,7 +529,7 @@ F test/lock5.test b2abb5e711bc59b0eae00f6c97a36ec9f458fada
|
||||
F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5
|
||||
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
|
||||
F test/lock_common.tcl d279887a0ab16cdb6d935c1203e64113c5a000e9
|
||||
F test/lookaside.test 382e7bc2fab23d902c8eafb1b9ed7ababfff75a6
|
||||
F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
|
||||
F test/main.test 9d7bbfcc1b52c88ba7b2ba6554068ecf9939f252
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test 927e6c8668a1d48c23aa6189bda02aff5a1b83de
|
||||
@@ -551,11 +552,11 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
||||
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
|
||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||
F test/malloc_common.tcl 27087a2bfad8f695ca6f8b463ecac5d71b9b0712
|
||||
F test/malloc_common.tcl 660b82ab528521cc4a48ff6df05ca3b6a00d47c5
|
||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test 4cbec6f202c91504bfc4717bfc2ffd6160316c4c
|
||||
F test/memsubsys1.test 679db68394a5692791737b150852173b3e2fea10
|
||||
F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
|
||||
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
|
||||
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||
@@ -569,7 +570,7 @@ F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3
|
||||
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
|
||||
F test/multiplex.test 92a4839213fd8cba8b59f86d42b7a1da1857db39
|
||||
F test/mutex1.test 5b71777fc127509cd257910c8db799de557a02de
|
||||
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test a44e04df1486fcfb02d32468cbcd3c8e1e433723
|
||||
F test/notify1.test 8433bc74bd952fb8a6e3f8d7a4c2b28dfd69e310
|
||||
@@ -578,14 +579,15 @@ F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a
|
||||
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
|
||||
F test/pager1.test e066fb2e2dc1ac1cd9ef2b44a28ae3cc79a9150f
|
||||
F test/pager2.test 0fbb6b6dc40ce1fecfe758c555a748ad2e9beaa3
|
||||
F test/pager1.test 7006a8b5dd3df1fe0d51d7da014333d7dc099778
|
||||
F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
F test/pagerfault.test 9de4d3e0c59970b4c6cb8dac511fa242f335d8a7
|
||||
F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401
|
||||
F test/pagerfault3.test 9b413f48a3e9a9a8c26968118f8db19fd7bfb8c7
|
||||
F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
|
||||
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||
F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d
|
||||
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
|
||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||
F test/permutations.test c0ce0f3b741dd92a6d4c2671dbacba4b92dd81eb
|
||||
F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
|
||||
@@ -606,7 +608,7 @@ F test/rollback.test 1a83118ea6db4e7d8c10eaa63871b5e90502ffdc
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test e58e0acef38b527ed1b0b70d3ada588f804af287
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/savepoint.test d3dd00e0137fc4b4659bde378a4d8f2cd07238a3
|
||||
F test/savepoint.test a1bef7ace82cc7922975fa96b06176e9bd5114cf
|
||||
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
||||
F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
|
||||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
@@ -686,6 +688,7 @@ F test/tkt-38cb5df375.test 9e9b19857dba0896a8efdaf334d405ba423492f2
|
||||
F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7
|
||||
F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
|
||||
F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
|
||||
F test/tkt-5d863f876e.test 884072c2de496ddbb90c387c9ebc0d4f44a91b8e
|
||||
F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
|
||||
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
|
||||
F test/tkt-78e04e52ea.test ab52f0c1e2de6e46c910f4cc16b086bba05952b7
|
||||
@@ -787,6 +790,7 @@ F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
|
||||
F test/trace2.test 092bc2c5776272700450d60a36919921095bdc21
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
|
||||
F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97
|
||||
@@ -875,17 +879,17 @@ F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c.tcl e0db70c2c52b0e3d0867ca931229e5b90ffe7837
|
||||
F tool/mksqlite3h.tcl 03b6ca938c833814923674d8a160e91fcedb4571
|
||||
F tool/mksqlite3h.tcl d76c226a5e8e1f3b5f6593bcabe5e98b3b1ec9ff
|
||||
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
|
||||
F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/shell1.test 6c66ada564076681d38cba7eb00468e72a4764f4
|
||||
F tool/shell1.test c31b0814a9c543db51ca0cc63edb5e77ea532303
|
||||
F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3
|
||||
F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836
|
||||
F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce
|
||||
F tool/shell5.test 62bfaf9267296da1b91e4b1c03e44e7b393f6a94
|
||||
F tool/showdb.c c7a978cf525ef0f8bc2fd29cd52108dd1dfa605a
|
||||
F tool/showdb.c 471c0f8fa472e71bb7654500096a5bdb4ea1fb2a
|
||||
F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02
|
||||
F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
@@ -897,14 +901,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P fe441df9ba447d97571e919099846efa3ec87427
|
||||
R 6bbeb99b0a61f7ea1af21c5b74072ff6
|
||||
P 682fe41efd3578e8c9abc7138b61f361c3adbe95
|
||||
R 7fccaf9f7c013ddef8926255f6aeb773
|
||||
U drh
|
||||
Z 584aed3667b20c0c4d105810047e9fd4
|
||||
Z 4223173e58f25d45d236e232b9c90989
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFM/pWUoxKgR168RlERAuOQAJ9BLHxhysfzWC+psYkAVcf2xDsyTgCeIRqp
|
||||
FF5a9ESJ6yucR80Re9sEWmU=
|
||||
=ZPd3
|
||||
iD8DBQFNQvb6oxKgR168RlERAtOTAJ9BaewewKXL3RGZUy5ycaHwjeEmJACeOPbw
|
||||
/JKqOugR+37RH7HnLCo9DBk=
|
||||
=kgPx
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
a586a4deeb25330037a49df295b36aaf624d0f45
|
||||
ed759d5a9edb3bba5f48f243df47be29e3fe8cd7
|
||||
+21
-8
@@ -233,9 +233,10 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
|
||||
|
||||
for(i=0; i<nCol; i++){
|
||||
CollSeq *pColl;
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
if( i==0 ){
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
/* Check if the record that cursor iIdxCur points to contains a
|
||||
** value that should be stored in the sqlite_stat2 table. If so,
|
||||
** store it. */
|
||||
@@ -264,12 +265,17 @@ static void analyzeOneTable(
|
||||
|
||||
sqlite3VdbeJumpHere(v, ne);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regRecno, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
|
||||
/**** TODO: add collating sequence *****/
|
||||
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
||||
/* Always record the very first row */
|
||||
sqlite3VdbeAddOp1(v, OP_IfNot, iMem+1);
|
||||
}
|
||||
assert( pIdx->azColl!=0 );
|
||||
assert( pIdx->azColl[i]!=0 );
|
||||
pColl = sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
|
||||
sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem+nCol+i+1,
|
||||
(char*)pColl, P4_COLLSEQ);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
/* If a malloc failure has occurred, then the result of the expression
|
||||
@@ -280,7 +286,11 @@ static void analyzeOneTable(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-(nCol*2));
|
||||
int addr2 = sqlite3VdbeCurrentAddr(v) - (nCol*2);
|
||||
if( i==0 ){
|
||||
sqlite3VdbeJumpHere(v, addr2-1); /* Set jump dest for the OP_IfNot */
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr2); /* Set jump dest for the OP_Ne */
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
|
||||
}
|
||||
@@ -626,8 +636,11 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char *zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
Index *pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase);
|
||||
char *zIndex; /* Index name */
|
||||
Index *pIdx; /* Pointer to the index object */
|
||||
|
||||
zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
pIdx = zIndex ? sqlite3FindIndex(db, zIndex, sInfo.zDatabase) : 0;
|
||||
if( pIdx ){
|
||||
int iSample = sqlite3_column_int(pStmt, 1);
|
||||
if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){
|
||||
|
||||
+47
-22
@@ -117,6 +117,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
return pDb->aDb[i].pBt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to set the page size of the destination to match the page size
|
||||
** of the source.
|
||||
*/
|
||||
static int setDestPgsz(sqlite3_backup *p){
|
||||
int rc;
|
||||
rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create an sqlite3_backup process to copy the contents of zSrcDb from
|
||||
** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
|
||||
@@ -170,10 +180,11 @@ sqlite3_backup *sqlite3_backup_init(
|
||||
p->iNext = 1;
|
||||
p->isAttached = 0;
|
||||
|
||||
if( 0==p->pSrc || 0==p->pDest ){
|
||||
/* One (or both) of the named databases did not exist. An error has
|
||||
** already been written into the pDestDb handle. All that is left
|
||||
** to do here is free the sqlite3_backup structure.
|
||||
if( 0==p->pSrc || 0==p->pDest || setDestPgsz(p)==SQLITE_NOMEM ){
|
||||
/* One (or both) of the named databases did not exist or an OOM
|
||||
** error was hit. The error has already been written into the
|
||||
** pDestDb handle. All that is left to do here is free the
|
||||
** sqlite3_backup structure.
|
||||
*/
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
@@ -430,32 +441,46 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
*/
|
||||
const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
|
||||
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
|
||||
i64 iOff;
|
||||
i64 iEnd;
|
||||
|
||||
assert( pFile );
|
||||
assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
|
||||
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
|
||||
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
|
||||
));
|
||||
if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
|
||||
&& SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
|
||||
&& SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
|
||||
|
||||
/* This call ensures that all data required to recreate the original
|
||||
** database has been stored in the journal for pDestPager and the
|
||||
** journal synced to disk. So at this point we may safely modify
|
||||
** the database file in any way, knowing that if a power failure
|
||||
** occurs, the original database will be reconstructed from the
|
||||
** journal file. */
|
||||
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
|
||||
|
||||
/* Write the extra pages and truncate the database file as required. */
|
||||
iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
|
||||
for(
|
||||
iOff=PENDING_BYTE+pgszSrc;
|
||||
rc==SQLITE_OK && iOff<iEnd;
|
||||
iOff+=pgszSrc
|
||||
){
|
||||
i64 iOff;
|
||||
i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
|
||||
for(
|
||||
iOff=PENDING_BYTE+pgszSrc;
|
||||
rc==SQLITE_OK && iOff<iEnd;
|
||||
iOff+=pgszSrc
|
||||
){
|
||||
PgHdr *pSrcPg = 0;
|
||||
const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
|
||||
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 *zData = sqlite3PagerGetData(pSrcPg);
|
||||
rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
|
||||
}
|
||||
sqlite3PagerUnref(pSrcPg);
|
||||
PgHdr *pSrcPg = 0;
|
||||
const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
|
||||
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 *zData = sqlite3PagerGetData(pSrcPg);
|
||||
rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
|
||||
}
|
||||
sqlite3PagerUnref(pSrcPg);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = backupTruncateFile(pFile, iSize);
|
||||
}
|
||||
|
||||
/* Sync the database file to disk. */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerSync(pDestPager);
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
|
||||
|
||||
+2
-7
@@ -918,14 +918,9 @@ static void btreeParseCellPtr(
|
||||
/* This is the (easy) common case where the entire payload fits
|
||||
** on the local page. No overflow is required.
|
||||
*/
|
||||
int nSize; /* Total size of cell content in bytes */
|
||||
nSize = nPayload + n;
|
||||
if( (pInfo->nSize = (u16)(n+nPayload))<4 ) pInfo->nSize = 4;
|
||||
pInfo->nLocal = (u16)nPayload;
|
||||
pInfo->iOverflow = 0;
|
||||
if( (nSize & ~3)==0 ){
|
||||
nSize = 4; /* Minimum cell size is 4 */
|
||||
}
|
||||
pInfo->nSize = (u16)nSize;
|
||||
}else{
|
||||
/* If the payload will not fit completely on the local page, we have
|
||||
** to decide how much to store locally and how much to spill onto
|
||||
@@ -2386,7 +2381,7 @@ static int lockBtree(BtShared *pBt){
|
||||
pageSize-usableSize);
|
||||
return rc;
|
||||
}
|
||||
if( nPageHeader>nPageFile ){
|
||||
if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPageHeader>nPageFile ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto page1_init_failed;
|
||||
}
|
||||
|
||||
+8
-8
@@ -414,12 +414,12 @@ struct BtShared {
|
||||
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
||||
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
||||
#endif
|
||||
u8 inTransaction; /* Transaction state */
|
||||
u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
|
||||
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
|
||||
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
|
||||
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
|
||||
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
|
||||
u8 inTransaction; /* Transaction state */
|
||||
u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
|
||||
u32 pageSize; /* Total number of bytes on a page */
|
||||
u32 usableSize; /* Number of usable bytes on each page */
|
||||
int nTransaction; /* Number of open transactions (read + write) */
|
||||
@@ -446,8 +446,8 @@ struct BtShared {
|
||||
*/
|
||||
typedef struct CellInfo CellInfo;
|
||||
struct CellInfo {
|
||||
u8 *pCell; /* Pointer to the start of cell content */
|
||||
i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
|
||||
u8 *pCell; /* Pointer to the start of cell content */
|
||||
u32 nData; /* Number of bytes of data */
|
||||
u32 nPayload; /* Total amount of payload */
|
||||
u16 nHeader; /* Size of the cell content header in bytes */
|
||||
@@ -489,20 +489,20 @@ struct BtCursor {
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
|
||||
CellInfo info; /* A parse of the cell we are pointing at */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
void *pKey; /* Saved key that was cursor's last known position */
|
||||
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
|
||||
u8 wrFlag; /* True if writable */
|
||||
u8 atLast; /* Cursor pointing to the last entry */
|
||||
u8 validNKey; /* True if info.nKey is valid */
|
||||
u8 eState; /* One of the CURSOR_XXX constants (see below) */
|
||||
void *pKey; /* Saved key that was cursor's last known position */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
|
||||
Pgno *aOverflow; /* Cache of overflow page locations */
|
||||
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
|
||||
#endif
|
||||
i16 iPage; /* Index of current page in apPage */
|
||||
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
|
||||
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -174,6 +174,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
"OMIT_AUTOMATIC_INDEX",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_AUTORESET
|
||||
"OMIT_AUTORESET",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
"OMIT_AUTOVACUUM",
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -1450,9 +1450,9 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
||||
}else{
|
||||
pInfo = (struct compareInfo*)&likeInfoNorm;
|
||||
}
|
||||
sqlite3CreateFunc(db, "like", 2, SQLITE_ANY, pInfo, likeFunc, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 3, SQLITE_ANY, pInfo, likeFunc, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "glob", 2, SQLITE_ANY,
|
||||
sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
|
||||
(struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
|
||||
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
|
||||
setLikeOptFlag(db, "like",
|
||||
|
||||
+6
-1
@@ -816,7 +816,7 @@ const char *sqlite3ErrStr(int rc){
|
||||
/* SQLITE_INTERRUPT */ "interrupted",
|
||||
/* SQLITE_IOERR */ "disk I/O error",
|
||||
/* SQLITE_CORRUPT */ "database disk image is malformed",
|
||||
/* SQLITE_NOTFOUND */ 0,
|
||||
/* SQLITE_NOTFOUND */ "unknown operation",
|
||||
/* SQLITE_FULL */ "database or disk is full",
|
||||
/* SQLITE_CANTOPEN */ "unable to open database file",
|
||||
/* SQLITE_PROTOCOL */ "locking protocol",
|
||||
@@ -1821,6 +1821,9 @@ static int openDatabase(
|
||||
#endif
|
||||
#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
|
||||
| SQLITE_RecTriggers
|
||||
#endif
|
||||
#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS
|
||||
| SQLITE_ForeignKeys
|
||||
#endif
|
||||
;
|
||||
sqlite3HashInit(&db->aCollSeq);
|
||||
@@ -2361,6 +2364,8 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
rc = SQLITE_OK;
|
||||
}else if( fd->pMethods ){
|
||||
rc = sqlite3OsFileControl(fd, op, pArg);
|
||||
}else{
|
||||
rc = SQLITE_NOTFOUND;
|
||||
}
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
|
||||
+13
-7
@@ -616,14 +616,20 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){
|
||||
if( db->mallocFailed ){
|
||||
return 0;
|
||||
}
|
||||
if( db->lookaside.bEnabled && n<=db->lookaside.sz
|
||||
&& (pBuf = db->lookaside.pFree)!=0 ){
|
||||
db->lookaside.pFree = pBuf->pNext;
|
||||
db->lookaside.nOut++;
|
||||
if( db->lookaside.nOut>db->lookaside.mxOut ){
|
||||
db->lookaside.mxOut = db->lookaside.nOut;
|
||||
if( db->lookaside.bEnabled ){
|
||||
if( n>db->lookaside.sz ){
|
||||
db->lookaside.anStat[1]++;
|
||||
}else if( (pBuf = db->lookaside.pFree)==0 ){
|
||||
db->lookaside.anStat[2]++;
|
||||
}else{
|
||||
db->lookaside.pFree = pBuf->pNext;
|
||||
db->lookaside.nOut++;
|
||||
db->lookaside.anStat[0]++;
|
||||
if( db->lookaside.nOut>db->lookaside.mxOut ){
|
||||
db->lookaside.mxOut = db->lookaside.nOut;
|
||||
}
|
||||
return (void*)pBuf;
|
||||
}
|
||||
return (void*)pBuf;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU2
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ static int winMutexEnd(void){
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU2
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
|
||||
+1
-1
@@ -533,7 +533,7 @@ static int os2FileControl(sqlite3_file *id, int op, void *pArg){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
return SQLITE_NOTFOUND;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+14
-8
@@ -119,7 +119,9 @@
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
# include <sys/ioctl.h>
|
||||
@@ -3133,8 +3135,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
return proxyFileControl(id,op,pArg);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
|
||||
case SQLITE_FCNTL_SYNC_OMITTED: {
|
||||
return SQLITE_OK; /* A no-op */
|
||||
}
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
return SQLITE_NOTFOUND;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5403,18 +5408,19 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait);
|
||||
** bytes of writable memory.
|
||||
*/
|
||||
static int proxyGetHostID(unsigned char *pHostID, int *pError){
|
||||
struct timespec timeout = {1, 0}; /* 1 sec timeout */
|
||||
|
||||
assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
|
||||
memset(pHostID, 0, PROXY_HOSTIDLEN);
|
||||
#if defined(__MAX_OS_X_VERSION_MIN_REQUIRED)\
|
||||
&& __MAC_OS_X_VERSION_MIN_REQUIRED<1050
|
||||
if( gethostuuid(pHostID, &timeout) ){
|
||||
int err = errno;
|
||||
if( pError ){
|
||||
*pError = err;
|
||||
{
|
||||
static const struct timespec timeout = {1, 0}; /* 1 sec timeout */
|
||||
if( gethostuuid(pHostID, &timeout) ){
|
||||
int err = errno;
|
||||
if( pError ){
|
||||
*pError = err;
|
||||
}
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
|
||||
+4
-1
@@ -1183,8 +1183,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
SimulateIOErrorBenign(0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_SYNC_OMITTED: {
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
return SQLITE_NOTFOUND;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+78
-27
@@ -2477,15 +2477,21 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
|
||||
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
|
||||
){
|
||||
i64 currentSize, newSize;
|
||||
int szPage = pPager->pageSize;
|
||||
assert( pPager->eLock==EXCLUSIVE_LOCK );
|
||||
/* TODO: Is it safe to use Pager.dbFileSize here? */
|
||||
rc = sqlite3OsFileSize(pPager->fd, ¤tSize);
|
||||
newSize = pPager->pageSize*(i64)nPage;
|
||||
newSize = szPage*(i64)nPage;
|
||||
if( rc==SQLITE_OK && currentSize!=newSize ){
|
||||
if( currentSize>newSize ){
|
||||
rc = sqlite3OsTruncate(pPager->fd, newSize);
|
||||
}else{
|
||||
rc = sqlite3OsWrite(pPager->fd, "", 1, newSize-1);
|
||||
char *pTmp = pPager->pTmpSpace;
|
||||
memset(pTmp, 0, szPage);
|
||||
testcase( (newSize-szPage) < currentSize );
|
||||
testcase( (newSize-szPage) == currentSize );
|
||||
testcase( (newSize-szPage) > currentSize );
|
||||
rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pPager->dbFileSize = nPage;
|
||||
@@ -2749,10 +2755,10 @@ end_playback:
|
||||
rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
}
|
||||
if( rc==SQLITE_OK && !pPager->noSync
|
||||
if( rc==SQLITE_OK
|
||||
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
|
||||
){
|
||||
rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
|
||||
rc = sqlite3PagerSync(pPager);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_end_transaction(pPager, zMaster[0]!='\0');
|
||||
@@ -2915,11 +2921,37 @@ static int pagerRollbackWal(Pager *pPager){
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Update the value of the change-counter at offsets 24 and 92 in
|
||||
** the header and the sqlite version number at offset 96.
|
||||
**
|
||||
** This is an unconditional update. See also the pager_incr_changecounter()
|
||||
** routine which only updates the change-counter if the update is actually
|
||||
** needed, as determined by the pPager->changeCountDone state variable.
|
||||
*/
|
||||
static void pager_write_changecounter(PgHdr *pPg){
|
||||
u32 change_counter;
|
||||
|
||||
/* Increment the value just read and write it back to byte 24. */
|
||||
change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
|
||||
put32bits(((char*)pPg->pData)+24, change_counter);
|
||||
|
||||
/* Also store the SQLite version number in bytes 96..99 and in
|
||||
** bytes 92..95 store the change counter for which the version number
|
||||
** is valid. */
|
||||
put32bits(((char*)pPg->pData)+92, change_counter);
|
||||
put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is a wrapper around sqlite3WalFrames(). As well as logging
|
||||
** the contents of the list of pages headed by pList (connected by pDirty),
|
||||
** this function notifies any active backup processes that the pages have
|
||||
** changed.
|
||||
** changed.
|
||||
**
|
||||
** The list of pages passed into this routine is always sorted by page number.
|
||||
** Hence, if page 1 appears anywhere on the list, it will be the first page.
|
||||
*/
|
||||
static int pagerWalFrames(
|
||||
Pager *pPager, /* Pager object */
|
||||
@@ -2929,8 +2961,19 @@ static int pagerWalFrames(
|
||||
int syncFlags /* Flags to pass to OsSync() (or 0) */
|
||||
){
|
||||
int rc; /* Return code */
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
|
||||
PgHdr *p; /* For looping over pages */
|
||||
#endif
|
||||
|
||||
assert( pPager->pWal );
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Verify that the page list is in accending order */
|
||||
for(p=pList; p && p->pDirty; p=p->pDirty){
|
||||
assert( p->pgno < p->pDirty->pgno );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( pList->pgno==1 ) pager_write_changecounter(pList);
|
||||
rc = sqlite3WalFrames(pPager->pWal,
|
||||
pPager->pageSize, pList, nTruncate, isCommit, syncFlags
|
||||
);
|
||||
@@ -2942,9 +2985,8 @@ static int pagerWalFrames(
|
||||
}
|
||||
|
||||
#ifdef SQLITE_CHECK_PAGES
|
||||
{
|
||||
PgHdr *p;
|
||||
for(p=pList; p; p=p->pDirty) pager_set_pagehash(p);
|
||||
for(p=pList; p; p=p->pDirty){
|
||||
pager_set_pagehash(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3969,6 +4011,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
|
||||
char *pData; /* Data to write */
|
||||
|
||||
assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
|
||||
if( pList->pgno==1 ) pager_write_changecounter(pList);
|
||||
|
||||
/* Encode the database */
|
||||
CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
|
||||
@@ -5489,7 +5532,13 @@ void sqlite3PagerDontWrite(PgHdr *pPg){
|
||||
/*
|
||||
** This routine is called to increment the value of the database file
|
||||
** change-counter, stored as a 4-byte big-endian integer starting at
|
||||
** byte offset 24 of the pager file.
|
||||
** byte offset 24 of the pager file. The secondary change counter at
|
||||
** 92 is also updated, as is the SQLite version number at offset 96.
|
||||
**
|
||||
** But this only happens if the pPager->changeCountDone flag is false.
|
||||
** To avoid excess churning of page 1, the update only happens once.
|
||||
** See also the pager_write_changecounter() routine that does an
|
||||
** unconditional update of the change counters.
|
||||
**
|
||||
** If the isDirectMode flag is zero, then this is done by calling
|
||||
** sqlite3PagerWrite() on page 1, then modifying the contents of the
|
||||
@@ -5530,7 +5579,6 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
|
||||
|
||||
if( !pPager->changeCountDone && pPager->dbSize>0 ){
|
||||
PgHdr *pPgHdr; /* Reference to page 1 */
|
||||
u32 change_counter; /* Initial value of change-counter field */
|
||||
|
||||
assert( !pPager->tempFile && isOpen(pPager->fd) );
|
||||
|
||||
@@ -5548,16 +5596,8 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
/* Increment the value just read and write it back to byte 24. */
|
||||
change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
|
||||
change_counter++;
|
||||
put32bits(((char*)pPgHdr->pData)+24, change_counter);
|
||||
|
||||
/* Also store the SQLite version number in bytes 96..99 and in
|
||||
** bytes 92..95 store the change counter for which the version number
|
||||
** is valid. */
|
||||
put32bits(((char*)pPgHdr->pData)+92, change_counter);
|
||||
put32bits(((char*)pPgHdr->pData)+96, SQLITE_VERSION_NUMBER);
|
||||
/* Actually do the update of the change counter */
|
||||
pager_write_changecounter(pPgHdr);
|
||||
|
||||
/* If running in direct mode, write the contents of page 1 to the file. */
|
||||
if( DIRECT_MODE ){
|
||||
@@ -5589,12 +5629,13 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
|
||||
** function returns SQLITE_OK. Otherwise, an IO error code is returned.
|
||||
*/
|
||||
int sqlite3PagerSync(Pager *pPager){
|
||||
int rc; /* Return code */
|
||||
assert( !MEMDB );
|
||||
if( pPager->noSync ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
int rc = SQLITE_OK;
|
||||
if( !pPager->noSync ){
|
||||
assert( !MEMDB );
|
||||
rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
|
||||
}else if( isOpen(pPager->fd) ){
|
||||
assert( !MEMDB );
|
||||
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, (void *)&rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -5813,8 +5854,8 @@ int sqlite3PagerCommitPhaseOne(
|
||||
}
|
||||
|
||||
/* Finally, sync the database file. */
|
||||
if( !pPager->noSync && !noSync ){
|
||||
rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
|
||||
if( !noSync ){
|
||||
rc = sqlite3PagerSync(pPager);
|
||||
}
|
||||
IOTRACE(("DBSYNC %p\n", pPager))
|
||||
}
|
||||
@@ -5926,7 +5967,17 @@ int sqlite3PagerRollback(Pager *pPager){
|
||||
rc2 = pager_end_transaction(pPager, pPager->setMaster);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
}else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
|
||||
int eState = pPager->eState;
|
||||
rc = pager_end_transaction(pPager, 0);
|
||||
if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
|
||||
/* This can happen using journal_mode=off. Move the pager to the error
|
||||
** state to indicate that the contents of the cache may not be trusted.
|
||||
** Any active readers will get SQLITE_ABORT.
|
||||
*/
|
||||
pPager->errCode = SQLITE_ABORT;
|
||||
pPager->eState = PAGER_ERROR;
|
||||
return rc;
|
||||
}
|
||||
}else{
|
||||
rc = pager_playback(pPager, 0);
|
||||
}
|
||||
|
||||
+250
-136
@@ -22,6 +22,38 @@
|
||||
typedef struct PCache1 PCache1;
|
||||
typedef struct PgHdr1 PgHdr1;
|
||||
typedef struct PgFreeslot PgFreeslot;
|
||||
typedef struct PGroup PGroup;
|
||||
|
||||
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
|
||||
** of one or more PCaches that are able to recycle each others unpinned
|
||||
** pages when they are under memory pressure. A PGroup is an instance of
|
||||
** the following object.
|
||||
**
|
||||
** This page cache implementation works in one of two modes:
|
||||
**
|
||||
** (1) Every PCache is the sole member of its own PGroup. There is
|
||||
** one PGroup per PCache.
|
||||
**
|
||||
** (2) There is a single global PGroup that all PCaches are a member
|
||||
** of.
|
||||
**
|
||||
** Mode 1 uses more memory (since PCache instances are not able to rob
|
||||
** unused pages from other PCaches) but it also operates without a mutex,
|
||||
** and is therefore often faster. Mode 2 requires a mutex in order to be
|
||||
** threadsafe, but is able recycle pages more efficient.
|
||||
**
|
||||
** For mode (1), PGroup.mutex is NULL. For mode (2) there is only a single
|
||||
** PGroup which is the pcache1.grp global variable and its mutex is
|
||||
** SQLITE_MUTEX_STATIC_LRU.
|
||||
*/
|
||||
struct PGroup {
|
||||
sqlite3_mutex *mutex; /* MUTEX_STATIC_LRU or NULL */
|
||||
int nMaxPage; /* Sum of nMax for purgeable caches */
|
||||
int nMinPage; /* Sum of nMin for purgeable caches */
|
||||
int mxPinned; /* nMaxpage + 10 - nMinPage */
|
||||
int nCurrentPage; /* Number of purgeable pages allocated */
|
||||
PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
|
||||
};
|
||||
|
||||
/* Each page cache is an instance of the following object. Every
|
||||
** open database file (including each in-memory database and each
|
||||
@@ -35,16 +67,17 @@ struct PCache1 {
|
||||
/* Cache configuration parameters. Page size (szPage) and the purgeable
|
||||
** flag (bPurgeable) are set when the cache is created. nMax may be
|
||||
** modified at any time by a call to the pcache1CacheSize() method.
|
||||
** The global mutex must be held when accessing nMax.
|
||||
** The PGroup mutex must be held when accessing nMax.
|
||||
*/
|
||||
PGroup *pGroup; /* PGroup this cache belongs to */
|
||||
int szPage; /* Size of allocated pages in bytes */
|
||||
int bPurgeable; /* True if cache is purgeable */
|
||||
unsigned int nMin; /* Minimum number of pages reserved */
|
||||
unsigned int nMax; /* Configured "cache_size" value */
|
||||
unsigned int n90pct; /* nMax*9/10 */
|
||||
|
||||
/* Hash table of all pages. The following variables may only be accessed
|
||||
** when the accessor is holding the global mutex (see pcache1EnterMutex()
|
||||
** and pcache1LeaveMutex()).
|
||||
** when the accessor is holding the PGroup mutex.
|
||||
*/
|
||||
unsigned int nRecyclable; /* Number of pages in the LRU list */
|
||||
unsigned int nPage; /* Total number of pages in apHash */
|
||||
@@ -80,21 +113,27 @@ struct PgFreeslot {
|
||||
** Global data used by this cache.
|
||||
*/
|
||||
static SQLITE_WSD struct PCacheGlobal {
|
||||
sqlite3_mutex *mutex; /* static mutex MUTEX_STATIC_LRU */
|
||||
PGroup grp; /* The global PGroup for mode (2) */
|
||||
|
||||
int nMaxPage; /* Sum of nMaxPage for purgeable caches */
|
||||
int nMinPage; /* Sum of nMinPage for purgeable caches */
|
||||
int nCurrentPage; /* Number of purgeable pages allocated */
|
||||
PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
|
||||
|
||||
/* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
|
||||
int szSlot; /* Size of each free slot */
|
||||
int nSlot; /* The number of pcache slots */
|
||||
int nFreeSlot; /* Number of unused pcache slots */
|
||||
int nReserve; /* Try to keep nFreeSlot above this */
|
||||
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
|
||||
PgFreeslot *pFree; /* Free page blocks */
|
||||
int isInit; /* True if initialized */
|
||||
/* Variables related to SQLITE_CONFIG_PAGECACHE settings. The
|
||||
** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
|
||||
** fixed at sqlite3_initialize() time and do not require mutex protection.
|
||||
** The nFreeSlot and pFree values do require mutex protection.
|
||||
*/
|
||||
int isInit; /* True if initialized */
|
||||
int szSlot; /* Size of each free slot */
|
||||
int nSlot; /* The number of pcache slots */
|
||||
int nReserve; /* Try to keep nFreeSlot above this */
|
||||
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
|
||||
/* Above requires no mutex. Use mutex below for variable that follow. */
|
||||
sqlite3_mutex *mutex; /* Mutex for accessing the following: */
|
||||
int nFreeSlot; /* Number of unused pcache slots */
|
||||
PgFreeslot *pFree; /* Free page blocks */
|
||||
/* The following value requires a mutex to change. We skip the mutex on
|
||||
** reading because (1) most platforms read a 32-bit integer atomically and
|
||||
** (2) even if an incorrect value is read, no great harm is done since this
|
||||
** is really just an optimization. */
|
||||
int bUnderPressure; /* True if low on PAGECACHE memory */
|
||||
} pcache1_g;
|
||||
|
||||
/*
|
||||
@@ -120,10 +159,10 @@ static SQLITE_WSD struct PCacheGlobal {
|
||||
#define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage)
|
||||
|
||||
/*
|
||||
** Macros to enter and leave the global LRU mutex.
|
||||
** Macros to enter and leave the PCache LRU mutex.
|
||||
*/
|
||||
#define pcache1EnterMutex() sqlite3_mutex_enter(pcache1.mutex)
|
||||
#define pcache1LeaveMutex() sqlite3_mutex_leave(pcache1.mutex)
|
||||
#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
|
||||
#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
|
||||
|
||||
/******************************************************************************/
|
||||
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
|
||||
@@ -133,6 +172,9 @@ static SQLITE_WSD struct PCacheGlobal {
|
||||
** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
|
||||
** verb to sqlite3_config(). Parameter pBuf points to an allocation large
|
||||
** enough to contain 'n' buffers of 'sz' bytes each.
|
||||
**
|
||||
** This routine is called from sqlite3_initialize() and so it is guaranteed
|
||||
** to be serialized already. There is no need for further mutexing.
|
||||
*/
|
||||
void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
|
||||
if( pcache1.isInit ){
|
||||
@@ -143,6 +185,7 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
|
||||
pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
|
||||
pcache1.pStart = pBuf;
|
||||
pcache1.pFree = 0;
|
||||
pcache1.bUnderPressure = 0;
|
||||
while( n-- ){
|
||||
p = (PgFreeslot*)pBuf;
|
||||
p->pNext = pcache1.pFree;
|
||||
@@ -158,32 +201,36 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
|
||||
** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
|
||||
** such buffer exists or there is no space left in it, this function falls
|
||||
** back to sqlite3Malloc().
|
||||
**
|
||||
** Multiple threads can run this routine at the same time. Global variables
|
||||
** in pcache1 need to be protected via mutex.
|
||||
*/
|
||||
static void *pcache1Alloc(int nByte){
|
||||
void *p;
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
void *p = 0;
|
||||
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
|
||||
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
|
||||
if( nByte<=pcache1.szSlot && pcache1.pFree ){
|
||||
assert( pcache1.isInit );
|
||||
if( nByte<=pcache1.szSlot ){
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
p = (PgHdr1 *)pcache1.pFree;
|
||||
pcache1.pFree = pcache1.pFree->pNext;
|
||||
pcache1.nFreeSlot--;
|
||||
assert( pcache1.nFreeSlot>=0 );
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
|
||||
}else{
|
||||
|
||||
/* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the
|
||||
** global pcache mutex and unlock the pager-cache object pCache. This is
|
||||
** so that if the attempt to allocate a new buffer causes the the
|
||||
** configured soft-heap-limit to be breached, it will be possible to
|
||||
** reclaim memory from this pager-cache.
|
||||
if( p ){
|
||||
pcache1.pFree = pcache1.pFree->pNext;
|
||||
pcache1.nFreeSlot--;
|
||||
pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
|
||||
assert( pcache1.nFreeSlot>=0 );
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
|
||||
}
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
}
|
||||
if( p==0 ){
|
||||
/* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get
|
||||
** it from sqlite3Malloc instead.
|
||||
*/
|
||||
pcache1LeaveMutex();
|
||||
p = sqlite3Malloc(nByte);
|
||||
pcache1EnterMutex();
|
||||
if( p ){
|
||||
int sz = sqlite3MallocSize(p);
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
}
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
|
||||
}
|
||||
@@ -194,22 +241,26 @@ static void *pcache1Alloc(int nByte){
|
||||
** Free an allocated buffer obtained from pcache1Alloc().
|
||||
*/
|
||||
static void pcache1Free(void *p){
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
if( p==0 ) return;
|
||||
if( p>=pcache1.pStart && p<pcache1.pEnd ){
|
||||
PgFreeslot *pSlot;
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
|
||||
pSlot = (PgFreeslot*)p;
|
||||
pSlot->pNext = pcache1.pFree;
|
||||
pcache1.pFree = pSlot;
|
||||
pcache1.nFreeSlot++;
|
||||
pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
|
||||
assert( pcache1.nFreeSlot<=pcache1.nSlot );
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
}else{
|
||||
int iSize;
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
iSize = sqlite3MallocSize(p);
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
@@ -219,7 +270,6 @@ static void pcache1Free(void *p){
|
||||
** Return the size of a pcache allocation
|
||||
*/
|
||||
static int pcache1MemSize(void *p){
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
if( p>=pcache1.pStart && p<pcache1.pEnd ){
|
||||
return pcache1.szSlot;
|
||||
}else{
|
||||
@@ -243,7 +293,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
|
||||
if( pPg ){
|
||||
p = PAGE_TO_PGHDR1(pCache, pPg);
|
||||
if( pCache->bPurgeable ){
|
||||
pcache1.nCurrentPage++;
|
||||
pCache->pGroup->nCurrentPage++;
|
||||
}
|
||||
}else{
|
||||
p = 0;
|
||||
@@ -260,8 +310,9 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
|
||||
*/
|
||||
static void pcache1FreePage(PgHdr1 *p){
|
||||
if( ALWAYS(p) ){
|
||||
if( p->pCache->bPurgeable ){
|
||||
pcache1.nCurrentPage--;
|
||||
PCache1 *pCache = p->pCache;
|
||||
if( pCache->bPurgeable ){
|
||||
pCache->pGroup->nCurrentPage--;
|
||||
}
|
||||
pcache1Free(PGHDR1_TO_PAGE(p));
|
||||
}
|
||||
@@ -273,20 +324,14 @@ static void pcache1FreePage(PgHdr1 *p){
|
||||
** exists, this function falls back to sqlite3Malloc().
|
||||
*/
|
||||
void *sqlite3PageMalloc(int sz){
|
||||
void *p;
|
||||
pcache1EnterMutex();
|
||||
p = pcache1Alloc(sz);
|
||||
pcache1LeaveMutex();
|
||||
return p;
|
||||
return pcache1Alloc(sz);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free an allocated buffer obtained from sqlite3PageMalloc().
|
||||
*/
|
||||
void sqlite3PageFree(void *p){
|
||||
pcache1EnterMutex();
|
||||
pcache1Free(p);
|
||||
pcache1LeaveMutex();
|
||||
}
|
||||
|
||||
|
||||
@@ -307,9 +352,8 @@ void sqlite3PageFree(void *p){
|
||||
** the heap even further.
|
||||
*/
|
||||
static int pcache1UnderMemoryPressure(PCache1 *pCache){
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
if( pcache1.nSlot && pCache->szPage<=pcache1.szSlot ){
|
||||
return pcache1.nFreeSlot<pcache1.nReserve;
|
||||
return pcache1.bUnderPressure;
|
||||
}else{
|
||||
return sqlite3HeapNearlyFull();
|
||||
}
|
||||
@@ -322,25 +366,25 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){
|
||||
** This function is used to resize the hash table used by the cache passed
|
||||
** as the first argument.
|
||||
**
|
||||
** The global mutex must be held when this function is called.
|
||||
** The PCache mutex must be held when this function is called.
|
||||
*/
|
||||
static int pcache1ResizeHash(PCache1 *p){
|
||||
PgHdr1 **apNew;
|
||||
unsigned int nNew;
|
||||
unsigned int i;
|
||||
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
assert( sqlite3_mutex_held(p->pGroup->mutex) );
|
||||
|
||||
nNew = p->nHash*2;
|
||||
if( nNew<256 ){
|
||||
nNew = 256;
|
||||
}
|
||||
|
||||
pcache1LeaveMutex();
|
||||
pcache1LeaveMutex(p->pGroup);
|
||||
if( p->nHash ){ sqlite3BeginBenignMalloc(); }
|
||||
apNew = (PgHdr1 **)sqlite3_malloc(sizeof(PgHdr1 *)*nNew);
|
||||
if( p->nHash ){ sqlite3EndBenignMalloc(); }
|
||||
pcache1EnterMutex();
|
||||
pcache1EnterMutex(p->pGroup);
|
||||
if( apNew ){
|
||||
memset(apNew, 0, sizeof(PgHdr1 *)*nNew);
|
||||
for(i=0; i<p->nHash; i++){
|
||||
@@ -363,25 +407,33 @@ static int pcache1ResizeHash(PCache1 *p){
|
||||
|
||||
/*
|
||||
** This function is used internally to remove the page pPage from the
|
||||
** global LRU list, if is part of it. If pPage is not part of the global
|
||||
** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
|
||||
** LRU list, then this function is a no-op.
|
||||
**
|
||||
** The global mutex must be held when this function is called.
|
||||
** The PGroup mutex must be held when this function is called.
|
||||
**
|
||||
** If pPage is NULL then this routine is a no-op.
|
||||
*/
|
||||
static void pcache1PinPage(PgHdr1 *pPage){
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
if( pPage && (pPage->pLruNext || pPage==pcache1.pLruTail) ){
|
||||
PCache1 *pCache;
|
||||
PGroup *pGroup;
|
||||
|
||||
if( pPage==0 ) return;
|
||||
pCache = pPage->pCache;
|
||||
pGroup = pCache->pGroup;
|
||||
assert( sqlite3_mutex_held(pGroup->mutex) );
|
||||
if( pPage->pLruNext || pPage==pGroup->pLruTail ){
|
||||
if( pPage->pLruPrev ){
|
||||
pPage->pLruPrev->pLruNext = pPage->pLruNext;
|
||||
}
|
||||
if( pPage->pLruNext ){
|
||||
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
|
||||
}
|
||||
if( pcache1.pLruHead==pPage ){
|
||||
pcache1.pLruHead = pPage->pLruNext;
|
||||
if( pGroup->pLruHead==pPage ){
|
||||
pGroup->pLruHead = pPage->pLruNext;
|
||||
}
|
||||
if( pcache1.pLruTail==pPage ){
|
||||
pcache1.pLruTail = pPage->pLruPrev;
|
||||
if( pGroup->pLruTail==pPage ){
|
||||
pGroup->pLruTail = pPage->pLruPrev;
|
||||
}
|
||||
pPage->pLruNext = 0;
|
||||
pPage->pLruPrev = 0;
|
||||
@@ -394,13 +446,14 @@ static void pcache1PinPage(PgHdr1 *pPage){
|
||||
** Remove the page supplied as an argument from the hash table
|
||||
** (PCache1.apHash structure) that it is currently stored in.
|
||||
**
|
||||
** The global mutex must be held when this function is called.
|
||||
** The PGroup mutex must be held when this function is called.
|
||||
*/
|
||||
static void pcache1RemoveFromHash(PgHdr1 *pPage){
|
||||
unsigned int h;
|
||||
PCache1 *pCache = pPage->pCache;
|
||||
PgHdr1 **pp;
|
||||
|
||||
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
|
||||
h = pPage->iKey % pCache->nHash;
|
||||
for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext);
|
||||
*pp = (*pp)->pNext;
|
||||
@@ -409,13 +462,14 @@ static void pcache1RemoveFromHash(PgHdr1 *pPage){
|
||||
}
|
||||
|
||||
/*
|
||||
** If there are currently more than pcache.nMaxPage pages allocated, try
|
||||
** to recycle pages to reduce the number allocated to pcache.nMaxPage.
|
||||
** If there are currently more than nMaxPage pages allocated, try
|
||||
** to recycle pages to reduce the number allocated to nMaxPage.
|
||||
*/
|
||||
static void pcache1EnforceMaxPage(void){
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
while( pcache1.nCurrentPage>pcache1.nMaxPage && pcache1.pLruTail ){
|
||||
PgHdr1 *p = pcache1.pLruTail;
|
||||
static void pcache1EnforceMaxPage(PGroup *pGroup){
|
||||
assert( sqlite3_mutex_held(pGroup->mutex) );
|
||||
while( pGroup->nCurrentPage>pGroup->nMaxPage && pGroup->pLruTail ){
|
||||
PgHdr1 *p = pGroup->pLruTail;
|
||||
assert( p->pCache->pGroup==pGroup );
|
||||
pcache1PinPage(p);
|
||||
pcache1RemoveFromHash(p);
|
||||
pcache1FreePage(p);
|
||||
@@ -427,15 +481,15 @@ static void pcache1EnforceMaxPage(void){
|
||||
** greater than or equal to iLimit. Any pinned pages that meet this
|
||||
** criteria are unpinned before they are discarded.
|
||||
**
|
||||
** The global mutex must be held when this function is called.
|
||||
** The PCache mutex must be held when this function is called.
|
||||
*/
|
||||
static void pcache1TruncateUnsafe(
|
||||
PCache1 *pCache,
|
||||
unsigned int iLimit
|
||||
PCache1 *pCache, /* The cache to truncate */
|
||||
unsigned int iLimit /* Drop pages with this pgno or larger */
|
||||
){
|
||||
TESTONLY( unsigned int nPage = 0; ) /* Used to assert pCache->nPage is correct */
|
||||
TESTONLY( unsigned int nPage = 0; ) /* To assert pCache->nPage is correct */
|
||||
unsigned int h;
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
|
||||
for(h=0; h<pCache->nHash; h++){
|
||||
PgHdr1 **pp = &pCache->apHash[h];
|
||||
PgHdr1 *pPage;
|
||||
@@ -465,8 +519,10 @@ static int pcache1Init(void *NotUsed){
|
||||
assert( pcache1.isInit==0 );
|
||||
memset(&pcache1, 0, sizeof(pcache1));
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
|
||||
pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
|
||||
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
|
||||
}
|
||||
pcache1.grp.mxPinned = 10;
|
||||
pcache1.isInit = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -488,18 +544,47 @@ static void pcache1Shutdown(void *NotUsed){
|
||||
** Allocate a new cache.
|
||||
*/
|
||||
static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
|
||||
PCache1 *pCache;
|
||||
PCache1 *pCache; /* The newly created page cache */
|
||||
PGroup *pGroup; /* The group the new page cache will belong to */
|
||||
int sz; /* Bytes of memory required to allocate the new cache */
|
||||
|
||||
pCache = (PCache1 *)sqlite3_malloc(sizeof(PCache1));
|
||||
/*
|
||||
** The seperateCache variable is true if each PCache has its own private
|
||||
** PGroup. In other words, separateCache is true for mode (1) where no
|
||||
** mutexing is required.
|
||||
**
|
||||
** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
|
||||
**
|
||||
** * Always use a unified cache in single-threaded applications
|
||||
**
|
||||
** * Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
|
||||
** use separate caches (mode-1)
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
|
||||
const int separateCache = 0;
|
||||
#else
|
||||
int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
|
||||
#endif
|
||||
|
||||
sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
|
||||
pCache = (PCache1 *)sqlite3_malloc(sz);
|
||||
if( pCache ){
|
||||
memset(pCache, 0, sizeof(PCache1));
|
||||
memset(pCache, 0, sz);
|
||||
if( separateCache ){
|
||||
pGroup = (PGroup*)&pCache[1];
|
||||
pGroup->mxPinned = 10;
|
||||
}else{
|
||||
pGroup = &pcache1_g.grp;
|
||||
}
|
||||
pCache->pGroup = pGroup;
|
||||
pCache->szPage = szPage;
|
||||
pCache->bPurgeable = (bPurgeable ? 1 : 0);
|
||||
if( bPurgeable ){
|
||||
pCache->nMin = 10;
|
||||
pcache1EnterMutex();
|
||||
pcache1.nMinPage += pCache->nMin;
|
||||
pcache1LeaveMutex();
|
||||
pcache1EnterMutex(pGroup);
|
||||
pGroup->nMinPage += pCache->nMin;
|
||||
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
|
||||
pcache1LeaveMutex(pGroup);
|
||||
}
|
||||
}
|
||||
return (sqlite3_pcache *)pCache;
|
||||
@@ -513,11 +598,14 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
|
||||
static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
if( pCache->bPurgeable ){
|
||||
pcache1EnterMutex();
|
||||
pcache1.nMaxPage += (nMax - pCache->nMax);
|
||||
PGroup *pGroup = pCache->pGroup;
|
||||
pcache1EnterMutex(pGroup);
|
||||
pGroup->nMaxPage += (nMax - pCache->nMax);
|
||||
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
|
||||
pCache->nMax = nMax;
|
||||
pcache1EnforceMaxPage();
|
||||
pcache1LeaveMutex();
|
||||
pCache->n90pct = pCache->nMax*9/10;
|
||||
pcache1EnforceMaxPage(pGroup);
|
||||
pcache1LeaveMutex(pGroup);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,9 +614,10 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
|
||||
*/
|
||||
static int pcache1Pagecount(sqlite3_pcache *p){
|
||||
int n;
|
||||
pcache1EnterMutex();
|
||||
n = ((PCache1 *)p)->nPage;
|
||||
pcache1LeaveMutex();
|
||||
PCache1 *pCache = (PCache1*)p;
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
n = pCache->nPage;
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -587,30 +676,49 @@ static int pcache1Pagecount(sqlite3_pcache *p){
|
||||
** 5. Otherwise, allocate and return a new page buffer.
|
||||
*/
|
||||
static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
|
||||
unsigned int nPinned;
|
||||
int nPinned;
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PGroup *pGroup;
|
||||
PgHdr1 *pPage = 0;
|
||||
|
||||
assert( pCache->bPurgeable || createFlag!=1 );
|
||||
pcache1EnterMutex();
|
||||
if( createFlag==1 ) sqlite3BeginBenignMalloc();
|
||||
assert( pCache->bPurgeable || pCache->nMin==0 );
|
||||
assert( pCache->bPurgeable==0 || pCache->nMin==10 );
|
||||
assert( pCache->nMin==0 || pCache->bPurgeable );
|
||||
pcache1EnterMutex(pGroup = pCache->pGroup);
|
||||
|
||||
/* Search the hash table for an existing entry. */
|
||||
/* Step 1: Search the hash table for an existing entry. */
|
||||
if( pCache->nHash>0 ){
|
||||
unsigned int h = iKey % pCache->nHash;
|
||||
for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
|
||||
}
|
||||
|
||||
/* Step 2: Abort if no existing page is found and createFlag is 0 */
|
||||
if( pPage || createFlag==0 ){
|
||||
pcache1PinPage(pPage);
|
||||
goto fetch_out;
|
||||
}
|
||||
|
||||
/* Step 3 of header comment. */
|
||||
/* The pGroup local variable will normally be initialized by the
|
||||
** pcache1EnterMutex() macro above. But if SQLITE_MUTEX_OMIT is defined,
|
||||
** then pcache1EnterMutex() is a no-op, so we have to initialize the
|
||||
** local variable here. Delaying the initialization of pGroup is an
|
||||
** optimization: The common case is to exit the module before reaching
|
||||
** this point.
|
||||
*/
|
||||
#ifdef SQLITE_MUTEX_OMIT
|
||||
pGroup = pCache->pGroup;
|
||||
#endif
|
||||
|
||||
|
||||
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
|
||||
nPinned = pCache->nPage - pCache->nRecyclable;
|
||||
assert( nPinned>=0 );
|
||||
assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
|
||||
assert( pCache->n90pct == pCache->nMax*9/10 );
|
||||
if( createFlag==1 && (
|
||||
nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
|
||||
|| nPinned>=(pCache->nMax * 9 / 10)
|
||||
nPinned>=pGroup->mxPinned
|
||||
|| nPinned>=(int)pCache->n90pct
|
||||
|| pcache1UnderMemoryPressure(pCache)
|
||||
)){
|
||||
goto fetch_out;
|
||||
@@ -620,20 +728,22 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
|
||||
goto fetch_out;
|
||||
}
|
||||
|
||||
/* Step 4. Try to recycle a page buffer if appropriate. */
|
||||
if( pCache->bPurgeable && pcache1.pLruTail && (
|
||||
/* Step 4. Try to recycle a page. */
|
||||
if( pCache->bPurgeable && pGroup->pLruTail && (
|
||||
(pCache->nPage+1>=pCache->nMax)
|
||||
|| pcache1.nCurrentPage>=pcache1.nMaxPage
|
||||
|| pGroup->nCurrentPage>=pGroup->nMaxPage
|
||||
|| pcache1UnderMemoryPressure(pCache)
|
||||
)){
|
||||
pPage = pcache1.pLruTail;
|
||||
PCache1 *pOtherCache;
|
||||
pPage = pGroup->pLruTail;
|
||||
pcache1RemoveFromHash(pPage);
|
||||
pcache1PinPage(pPage);
|
||||
if( pPage->pCache->szPage!=pCache->szPage ){
|
||||
if( (pOtherCache = pPage->pCache)->szPage!=pCache->szPage ){
|
||||
pcache1FreePage(pPage);
|
||||
pPage = 0;
|
||||
}else{
|
||||
pcache1.nCurrentPage -= (pPage->pCache->bPurgeable - pCache->bPurgeable);
|
||||
pGroup->nCurrentPage -=
|
||||
(pOtherCache->bPurgeable - pCache->bPurgeable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,7 +751,11 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
|
||||
** attempt to allocate a new one.
|
||||
*/
|
||||
if( !pPage ){
|
||||
if( createFlag==1 ) sqlite3BeginBenignMalloc();
|
||||
pcache1LeaveMutex(pGroup);
|
||||
pPage = pcache1AllocPage(pCache);
|
||||
pcache1EnterMutex(pGroup);
|
||||
if( createFlag==1 ) sqlite3EndBenignMalloc();
|
||||
}
|
||||
|
||||
if( pPage ){
|
||||
@@ -660,8 +774,7 @@ fetch_out:
|
||||
if( pPage && iKey>pCache->iMaxKey ){
|
||||
pCache->iMaxKey = iKey;
|
||||
}
|
||||
if( createFlag==1 ) sqlite3EndBenignMalloc();
|
||||
pcache1LeaveMutex();
|
||||
pcache1LeaveMutex(pGroup);
|
||||
return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
|
||||
}
|
||||
|
||||
@@ -674,37 +787,34 @@ fetch_out:
|
||||
static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
|
||||
PGroup *pGroup = pCache->pGroup;
|
||||
|
||||
assert( pPage->pCache==pCache );
|
||||
pcache1EnterMutex();
|
||||
pcache1EnterMutex(pGroup);
|
||||
|
||||
/* It is an error to call this function if the page is already
|
||||
** part of the global LRU list.
|
||||
** part of the PGroup LRU list.
|
||||
*/
|
||||
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
|
||||
assert( pcache1.pLruHead!=pPage && pcache1.pLruTail!=pPage );
|
||||
assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
|
||||
|
||||
if( reuseUnlikely || pcache1.nCurrentPage>pcache1.nMaxPage ){
|
||||
if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
|
||||
pcache1RemoveFromHash(pPage);
|
||||
pcache1FreePage(pPage);
|
||||
}else{
|
||||
/* Add the page to the global LRU list. Normally, the page is added to
|
||||
** the head of the list (last page to be recycled). However, if the
|
||||
** reuseUnlikely flag passed to this function is true, the page is added
|
||||
** to the tail of the list (first page to be recycled).
|
||||
*/
|
||||
if( pcache1.pLruHead ){
|
||||
pcache1.pLruHead->pLruPrev = pPage;
|
||||
pPage->pLruNext = pcache1.pLruHead;
|
||||
pcache1.pLruHead = pPage;
|
||||
/* Add the page to the PGroup LRU list. */
|
||||
if( pGroup->pLruHead ){
|
||||
pGroup->pLruHead->pLruPrev = pPage;
|
||||
pPage->pLruNext = pGroup->pLruHead;
|
||||
pGroup->pLruHead = pPage;
|
||||
}else{
|
||||
pcache1.pLruTail = pPage;
|
||||
pcache1.pLruHead = pPage;
|
||||
pGroup->pLruTail = pPage;
|
||||
pGroup->pLruHead = pPage;
|
||||
}
|
||||
pCache->nRecyclable++;
|
||||
}
|
||||
|
||||
pcache1LeaveMutex();
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -723,7 +833,7 @@ static void pcache1Rekey(
|
||||
assert( pPage->iKey==iOld );
|
||||
assert( pPage->pCache==pCache );
|
||||
|
||||
pcache1EnterMutex();
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
|
||||
h = iOld%pCache->nHash;
|
||||
pp = &pCache->apHash[h];
|
||||
@@ -740,7 +850,7 @@ static void pcache1Rekey(
|
||||
pCache->iMaxKey = iNew;
|
||||
}
|
||||
|
||||
pcache1LeaveMutex();
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -752,12 +862,12 @@ static void pcache1Rekey(
|
||||
*/
|
||||
static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
pcache1EnterMutex();
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
if( iLimit<=pCache->iMaxKey ){
|
||||
pcache1TruncateUnsafe(pCache, iLimit);
|
||||
pCache->iMaxKey = iLimit-1;
|
||||
}
|
||||
pcache1LeaveMutex();
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -767,13 +877,15 @@ static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
|
||||
*/
|
||||
static void pcache1Destroy(sqlite3_pcache *p){
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PGroup *pGroup = pCache->pGroup;
|
||||
assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
|
||||
pcache1EnterMutex();
|
||||
pcache1EnterMutex(pGroup);
|
||||
pcache1TruncateUnsafe(pCache, 0);
|
||||
pcache1.nMaxPage -= pCache->nMax;
|
||||
pcache1.nMinPage -= pCache->nMin;
|
||||
pcache1EnforceMaxPage();
|
||||
pcache1LeaveMutex();
|
||||
pGroup->nMaxPage -= pCache->nMax;
|
||||
pGroup->nMinPage -= pCache->nMin;
|
||||
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
|
||||
pcache1EnforceMaxPage(pGroup);
|
||||
pcache1LeaveMutex(pGroup);
|
||||
sqlite3_free(pCache->apHash);
|
||||
sqlite3_free(pCache);
|
||||
}
|
||||
@@ -812,16 +924,18 @@ void sqlite3PCacheSetDefault(void){
|
||||
*/
|
||||
int sqlite3PcacheReleaseMemory(int nReq){
|
||||
int nFree = 0;
|
||||
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
|
||||
assert( sqlite3_mutex_notheld(pcache1.mutex) );
|
||||
if( pcache1.pStart==0 ){
|
||||
PgHdr1 *p;
|
||||
pcache1EnterMutex();
|
||||
while( (nReq<0 || nFree<nReq) && ((p=pcache1.pLruTail)!=0) ){
|
||||
pcache1EnterMutex(&pcache1.grp);
|
||||
while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
|
||||
nFree += pcache1MemSize(PGHDR1_TO_PAGE(p));
|
||||
pcache1PinPage(p);
|
||||
pcache1RemoveFromHash(p);
|
||||
pcache1FreePage(p);
|
||||
}
|
||||
pcache1LeaveMutex();
|
||||
pcache1LeaveMutex(&pcache1.grp);
|
||||
}
|
||||
return nFree;
|
||||
}
|
||||
@@ -840,12 +954,12 @@ void sqlite3PcacheStats(
|
||||
){
|
||||
PgHdr1 *p;
|
||||
int nRecyclable = 0;
|
||||
for(p=pcache1.pLruHead; p; p=p->pLruNext){
|
||||
for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
|
||||
nRecyclable++;
|
||||
}
|
||||
*pnCurrent = pcache1.nCurrentPage;
|
||||
*pnMax = pcache1.nMaxPage;
|
||||
*pnMin = pcache1.nMinPage;
|
||||
*pnCurrent = pcache1.grp.nCurrentPage;
|
||||
*pnMax = pcache1.grp.nMaxPage;
|
||||
*pnMin = pcache1.grp.nMinPage;
|
||||
*pnRecyclable = nRecyclable;
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -784,7 +784,7 @@ int sqlite3_prepare_v2(
|
||||
*/
|
||||
static int sqlite3Prepare16(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const void *zSql, /* UTF-8 encoded SQL statement. */
|
||||
const void *zSql, /* UTF-16 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
@@ -834,7 +834,7 @@ static int sqlite3Prepare16(
|
||||
*/
|
||||
int sqlite3_prepare16(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const void *zSql, /* UTF-8 encoded SQL statement. */
|
||||
const void *zSql, /* UTF-16 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const void **pzTail /* OUT: End of parsed string */
|
||||
@@ -846,7 +846,7 @@ int sqlite3_prepare16(
|
||||
}
|
||||
int sqlite3_prepare16_v2(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const void *zSql, /* UTF-8 encoded SQL statement. */
|
||||
const void *zSql, /* UTF-16 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const void **pzTail /* OUT: End of parsed string */
|
||||
|
||||
+20
-13
@@ -763,6 +763,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
|
||||
i64 szNew = p->nChar;
|
||||
szNew += N + 1;
|
||||
if( szNew > p->mxAlloc ){
|
||||
@@ -773,13 +774,12 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
p->nAlloc = (int)szNew;
|
||||
}
|
||||
if( p->useMalloc==1 ){
|
||||
zNew = sqlite3DbMallocRaw(p->db, p->nAlloc );
|
||||
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
|
||||
}else{
|
||||
zNew = sqlite3_malloc(p->nAlloc);
|
||||
zNew = sqlite3_realloc(zOld, p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
memcpy(zNew, p->zText, p->nChar);
|
||||
sqlite3StrAccumReset(p);
|
||||
if( zOld==0 ) memcpy(zNew, p->zText, p->nChar);
|
||||
p->zText = zNew;
|
||||
}else{
|
||||
p->mallocFailed = 1;
|
||||
@@ -934,21 +934,28 @@ char *sqlite3_mprintf(const char *zFormat, ...){
|
||||
** current locale settings. This is important for SQLite because we
|
||||
** are not able to use a "," as the decimal point in place of "." as
|
||||
** specified by some locales.
|
||||
**
|
||||
** Oops: The first two arguments of sqlite3_snprintf() are backwards
|
||||
** from the snprintf() standard. Unfortunately, it is too late to change
|
||||
** this without breaking compatibility, so we just have to live with the
|
||||
** mistake.
|
||||
**
|
||||
** sqlite3_vsnprintf() is the varargs version.
|
||||
*/
|
||||
char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
|
||||
StrAccum acc;
|
||||
if( n<=0 ) return zBuf;
|
||||
sqlite3StrAccumInit(&acc, zBuf, n, 0);
|
||||
acc.useMalloc = 0;
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
return sqlite3StrAccumFinish(&acc);
|
||||
}
|
||||
char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
|
||||
char *z;
|
||||
va_list ap;
|
||||
StrAccum acc;
|
||||
|
||||
if( n<=0 ){
|
||||
return zBuf;
|
||||
}
|
||||
sqlite3StrAccumInit(&acc, zBuf, n, 0);
|
||||
acc.useMalloc = 0;
|
||||
va_start(ap,zFormat);
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
z = sqlite3_vsnprintf(n, zBuf, zFormat, ap);
|
||||
va_end(ap);
|
||||
z = sqlite3StrAccumFinish(&acc);
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
+32
-7
@@ -38,10 +38,14 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EDITLINE
|
||||
# include <editline/editline.h>
|
||||
#endif
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#else
|
||||
#endif
|
||||
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
|
||||
# define readline(p) local_getline(p,stdin)
|
||||
# define add_history(X)
|
||||
# define read_history(X)
|
||||
@@ -980,7 +984,7 @@ static int display_stats(
|
||||
fprintf(pArg->out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Number of Allocations: %d (max %d)\n", iCur, iHiwtr);
|
||||
fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr);
|
||||
/*
|
||||
** Not currently used by the CLI.
|
||||
** iHiwtr = iCur = -1;
|
||||
@@ -1019,6 +1023,12 @@ static int display_stats(
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur);
|
||||
@@ -2538,6 +2548,7 @@ int main(int argc, char **argv){
|
||||
|
||||
/* Do an initial pass through the command-line argument to locate
|
||||
** the name of the database file, the name of the initialization file,
|
||||
** the size of the alternative malloc heap,
|
||||
** and the first command to execute.
|
||||
*/
|
||||
for(i=1; i<argc-1; i++){
|
||||
@@ -2556,6 +2567,22 @@ int main(int argc, char **argv){
|
||||
*/
|
||||
}else if( strcmp(argv[i],"-batch")==0 ){
|
||||
stdin_is_interactive = 0;
|
||||
}else if( strcmp(argv[i],"-heap")==0 ){
|
||||
int j, c;
|
||||
const char *zSize;
|
||||
sqlite3_int64 szHeap;
|
||||
|
||||
zSize = argv[++i];
|
||||
szHeap = atoi(zSize);
|
||||
for(j=0; (c = zSize[j])!=0; j++){
|
||||
if( c=='M' ){ szHeap *= 1000000; break; }
|
||||
if( c=='K' ){ szHeap *= 1000; break; }
|
||||
if( c=='G' ){ szHeap *= 1000000000; break; }
|
||||
}
|
||||
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
|
||||
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
|
||||
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if( i<argc ){
|
||||
@@ -2662,6 +2689,8 @@ int main(int argc, char **argv){
|
||||
stdin_is_interactive = 1;
|
||||
}else if( strcmp(z,"-batch")==0 ){
|
||||
stdin_is_interactive = 0;
|
||||
}else if( strcmp(z,"-heap")==0 ){
|
||||
i++;
|
||||
}else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
|
||||
usage(1);
|
||||
}else{
|
||||
@@ -2723,11 +2752,7 @@ int main(int argc, char **argv){
|
||||
}
|
||||
set_table_name(&data, 0);
|
||||
if( data.db ){
|
||||
if( sqlite3_close(data.db)!=SQLITE_OK ){
|
||||
fprintf(stderr,"Error: cannot close database \"%s\"\n",
|
||||
sqlite3_errmsg(db));
|
||||
rc++;
|
||||
}
|
||||
sqlite3_close(data.db);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+115
-42
@@ -385,7 +385,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
|
||||
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
||||
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
||||
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
|
||||
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
|
||||
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||
@@ -617,7 +617,9 @@ struct sqlite3_file {
|
||||
** core reserves all opcodes less than 100 for its own use.
|
||||
** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
|
||||
** Applications that define a custom xFileControl method should use opcodes
|
||||
** greater than 100 to avoid conflicts.
|
||||
** greater than 100 to avoid conflicts. VFS implementations should
|
||||
** return [SQLITE_NOTFOUND] for file control opcodes that they do not
|
||||
** recognize.
|
||||
**
|
||||
** The xSectorSize() method returns the sector size of the
|
||||
** device that underlies the file. The sector size is the
|
||||
@@ -710,6 +712,21 @@ struct sqlite3_io_methods {
|
||||
** for the nominated database. Allocating database file space in large
|
||||
** chunks (say 1MB at a time), may reduce file-system fragmentation and
|
||||
** improve performance on some systems.
|
||||
**
|
||||
** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
|
||||
** to the [sqlite3_file] object associated with a particular database
|
||||
** connection. See the [sqlite3_file_control()] documentation for
|
||||
** additional information.
|
||||
**
|
||||
** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
|
||||
** SQLite and sent to all VFSes in place of a call to the xSync method
|
||||
** when the database connection has [PRAGMA synchronous] set to OFF.)^
|
||||
** Some specialized VFSes need this signal in order to operate correctly
|
||||
** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most
|
||||
** VFSes do not need this signal and should silently ignore this opcode.
|
||||
** Applications should not call [sqlite3_file_control()] with this
|
||||
** opcode as doing so may disrupt the operation of the specilized VFSes
|
||||
** that do require it.
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
#define SQLITE_GET_LOCKPROXYFILE 2
|
||||
@@ -718,6 +735,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_SIZE_HINT 5
|
||||
#define SQLITE_FCNTL_CHUNK_SIZE 6
|
||||
#define SQLITE_FCNTL_FILE_POINTER 7
|
||||
#define SQLITE_FCNTL_SYNC_OMITTED 8
|
||||
|
||||
|
||||
/*
|
||||
@@ -1837,7 +1855,7 @@ void sqlite3_free_table(char **result);
|
||||
** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
|
||||
** memory to hold the resulting string.
|
||||
**
|
||||
** ^(In sqlite3_snprintf() routine is similar to "snprintf()" from
|
||||
** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
|
||||
** the standard C library. The result is written into the
|
||||
** buffer supplied as the second parameter whose size is given by
|
||||
** the first parameter. Note that the order of the
|
||||
@@ -1856,6 +1874,8 @@ void sqlite3_free_table(char **result);
|
||||
** the zero terminator. So the longest string that can be completely
|
||||
** written will be n-1 characters.
|
||||
**
|
||||
** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
|
||||
**
|
||||
** These routines all implement some additional formatting
|
||||
** options that are useful for constructing SQL statements.
|
||||
** All of the usual printf() formatting options apply. In addition, there
|
||||
@@ -1919,6 +1939,7 @@ void sqlite3_free_table(char **result);
|
||||
char *sqlite3_mprintf(const char*,...);
|
||||
char *sqlite3_vmprintf(const char*, va_list);
|
||||
char *sqlite3_snprintf(int,char*,const char*, ...);
|
||||
char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Memory Allocation Subsystem
|
||||
@@ -2296,7 +2317,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** case the database must already exist, otherwise an error is returned.</dd>)^
|
||||
**
|
||||
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
|
||||
** <dd>The database is opened for reading and writing, and is creates it if
|
||||
** <dd>The database is opened for reading and writing, and is created if
|
||||
** it does not already exist. This is the behavior that is always used for
|
||||
** sqlite3_open() and sqlite3_open16().</dd>)^
|
||||
** </dl>
|
||||
@@ -2645,14 +2666,31 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
||||
/*
|
||||
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
||||
**
|
||||
** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
|
||||
** the [prepared statement] X is [SELECT] statement and false (zero) if
|
||||
** X is an [INSERT], [UPDATE], [DELETE], CREATE, DROP, [ANALYZE],
|
||||
** [ALTER], or [REINDEX] statement.
|
||||
** If X is a NULL pointer or any other kind of statement, including but
|
||||
** not limited to [ATTACH], [DETACH], [COMMIT], [ROLLBACK], [RELEASE],
|
||||
** [SAVEPOINT], [PRAGMA], or [VACUUM] the result of sqlite3_stmt_readonly(X) is
|
||||
** undefined.
|
||||
** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
|
||||
** and only if the [prepared statement] X makes no direct changes to
|
||||
** the content of the database file.
|
||||
**
|
||||
** Note that [application-defined SQL functions] or
|
||||
** [virtual tables] might change the database indirectly as a side effect.
|
||||
** ^(For example, if an application defines a function "eval()" that
|
||||
** calls [sqlite3_exec()], then the following SQL statement would
|
||||
** change the database file through side-effects:
|
||||
**
|
||||
** <blockquote><pre>
|
||||
** SELECT eval('DELETE FROM t1') FROM t2;
|
||||
** </pre></blockquote>
|
||||
**
|
||||
** But because the [SELECT] statement does not change the database file
|
||||
** directly, sqlite3_stmt_readonly() would still return true.)^
|
||||
**
|
||||
** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
|
||||
** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
|
||||
** since the statements themselves do not actually modify the database but
|
||||
** rather they control the timing of when other statements modify the
|
||||
** database. ^The [ATTACH] and [DETACH] statements also cause
|
||||
** sqlite3_stmt_readonly() to return true since, while those statements
|
||||
** change the configuration of a database connection, they do not make
|
||||
** changes to the content of the database files on disk.
|
||||
*/
|
||||
int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
||||
|
||||
@@ -3046,13 +3084,17 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
||||
** be the case that the same database connection is being used by two or
|
||||
** more threads at the same moment in time.
|
||||
**
|
||||
** For all versions of SQLite up to and including 3.6.23.1, it was required
|
||||
** after sqlite3_step() returned anything other than [SQLITE_ROW] that
|
||||
** [sqlite3_reset()] be called before any subsequent invocation of
|
||||
** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way would
|
||||
** result in an [SQLITE_MISUSE] return from sqlite3_step(). But after
|
||||
** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()]
|
||||
** automatically in this circumstance rather than returning [SQLITE_MISUSE].
|
||||
** For all versions of SQLite up to and including 3.6.23.1, a call to
|
||||
** [sqlite3_reset()] was required after sqlite3_step() returned anything
|
||||
** other than [SQLITE_ROW] before any subsequent invocation of
|
||||
** sqlite3_step(). Failure to reset the prepared statement using
|
||||
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
|
||||
** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began
|
||||
** calling [sqlite3_reset()] automatically in this circumstance rather
|
||||
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
|
||||
** break because any application that ever receives an SQLITE_MISUSE error
|
||||
** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option
|
||||
** can be used to restore the legacy behavior.
|
||||
**
|
||||
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
|
||||
** API always returns a generic error code, [SQLITE_ERROR], following any
|
||||
@@ -3389,7 +3431,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
|
||||
** function can gain access to this pointer using [sqlite3_user_data()].)^
|
||||
**
|
||||
** ^The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
|
||||
** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are
|
||||
** pointers to C-language functions that implement the SQL function or
|
||||
** aggregate. ^A scalar SQL function requires an implementation of the xFunc
|
||||
** callback only; NULL pointers must be passed as the xStep and xFinal
|
||||
@@ -3398,7 +3440,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** SQL function or aggregate, pass NULL poiners for all three function
|
||||
** callbacks.
|
||||
**
|
||||
** ^(If the tenth parameter to sqlite3_create_function_v2() is not NULL,
|
||||
** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL,
|
||||
** then it is destructor for the application data pointer.
|
||||
** The destructor is invoked when the function is deleted, either by being
|
||||
** overloaded or when the database connection closes.)^
|
||||
@@ -3502,7 +3544,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void
|
||||
** The xFunc (for scalar functions) or xStep (for aggregates) parameters
|
||||
** to [sqlite3_create_function()] and [sqlite3_create_function16()]
|
||||
** define callbacks that implement the SQL functions and aggregates.
|
||||
** The 4th parameter to these callbacks is an array of pointers to
|
||||
** The 3rd parameter to these callbacks is an array of pointers to
|
||||
** [protected sqlite3_value] objects. There is one [sqlite3_value] object for
|
||||
** each parameter to the SQL function. These routines are used to
|
||||
** extract values from the [sqlite3_value] objects.
|
||||
@@ -5230,7 +5272,8 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
|
||||
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
|
||||
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
|
||||
#define SQLITE_MUTEX_STATIC_LRU2 7 /* lru page list */
|
||||
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
|
||||
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieve the mutex for a database connection
|
||||
@@ -5381,7 +5424,8 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
** The value written into the *pCurrent parameter is undefined.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
|
||||
** <dd>This parameter records the number of separate memory allocations.</dd>)^
|
||||
** <dd>This parameter records the number of separate memory allocations
|
||||
** currently checked out.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
|
||||
** <dd>This parameter returns the number of pages used out of the
|
||||
@@ -5487,6 +5531,28 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** <dd>This parameter returns the number of lookaside memory slots currently
|
||||
** checked out.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
|
||||
** <dd>This parameter returns the number malloc attempts that were
|
||||
** satisfied using lookaside memory. Only the high-water value is meaningful;
|
||||
** the current value is always zero.
|
||||
** checked out.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
|
||||
** <dd>This parameter returns the number malloc attempts that might have
|
||||
** been satisfied using lookaside memory but failed due to the amount of
|
||||
** memory requested being larger than the lookaside slot size.
|
||||
** Only the high-water value is meaningful;
|
||||
** the current value is always zero.
|
||||
** checked out.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
|
||||
** <dd>This parameter returns the number malloc attempts that might have
|
||||
** been satisfied using lookaside memory but failed due to all lookaside
|
||||
** memory already being in use.
|
||||
** Only the high-water value is meaningful;
|
||||
** the current value is always zero.
|
||||
** checked out.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** memory used by all pager caches associated with the database connection.)^
|
||||
@@ -5509,11 +5575,14 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** </dd>
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
|
||||
#define SQLITE_DBSTATUS_CACHE_USED 1
|
||||
#define SQLITE_DBSTATUS_SCHEMA_USED 2
|
||||
#define SQLITE_DBSTATUS_STMT_USED 3
|
||||
#define SQLITE_DBSTATUS_MAX 3 /* Largest defined DBSTATUS */
|
||||
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
|
||||
#define SQLITE_DBSTATUS_CACHE_USED 1
|
||||
#define SQLITE_DBSTATUS_SCHEMA_USED 2
|
||||
#define SQLITE_DBSTATUS_STMT_USED 3
|
||||
#define SQLITE_DBSTATUS_LOOKASIDE_HIT 4
|
||||
#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5
|
||||
#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
|
||||
#define SQLITE_DBSTATUS_MAX 6 /* Largest defined DBSTATUS */
|
||||
|
||||
|
||||
/*
|
||||
@@ -5641,11 +5710,13 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** first parameter, szPage, is the size in bytes of the pages that must
|
||||
** be allocated by the cache. ^szPage will not be a power of two. ^szPage
|
||||
** will the page size of the database file that is to be cached plus an
|
||||
** increment (here called "R") of about 100 or 200. SQLite will use the
|
||||
** increment (here called "R") of less than 250. SQLite will use the
|
||||
** extra R bytes on each page to store metadata about the underlying
|
||||
** database page on disk. The value of R depends
|
||||
** on the SQLite version, the target platform, and how SQLite was compiled.
|
||||
** ^R is constant for a particular build of SQLite. ^The second argument to
|
||||
** ^(R is constant for a particular build of SQLite. Except, there are two
|
||||
** distinct values of R when SQLite is compiled with the proprietary
|
||||
** ZIPVFS extension.)^ ^The second argument to
|
||||
** xCreate(), bPurgeable, is true if the cache being created will
|
||||
** be used to cache database pages of a file stored on disk, or
|
||||
** false if it is used for an in-memory database. The cache implementation
|
||||
@@ -5677,7 +5748,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** If the requested page is already in the page cache, then the page cache
|
||||
** implementation must return a pointer to the page buffer with its content
|
||||
** intact. If the requested page is not already in the cache, then the
|
||||
** behavior of the cache implementation should use the value of the createFlag
|
||||
** cache implementation should use the value of the createFlag
|
||||
** parameter to help it determined what action to take:
|
||||
**
|
||||
** <table border=1 width=85% align=center>
|
||||
@@ -5761,11 +5832,12 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
**
|
||||
** See Also: [Using the SQLite Online Backup API]
|
||||
**
|
||||
** ^Exclusive access is required to the destination database for the
|
||||
** duration of the operation. ^However the source database is only
|
||||
** read-locked while it is actually being read; it is not locked
|
||||
** continuously for the entire backup operation. ^Thus, the backup may be
|
||||
** performed on a live source database without preventing other users from
|
||||
** ^SQLite holds a write transaction open on the destination database file
|
||||
** for the duration of the backup operation.
|
||||
** ^The source database is read-locked only while it is being read;
|
||||
** it is not locked continuously for the entire backup operation.
|
||||
** ^Thus, the backup may be performed on a live source database without
|
||||
** preventing other database connections from
|
||||
** reading or writing to the source database while the backup is underway.
|
||||
**
|
||||
** ^(To perform a backup operation:
|
||||
@@ -5792,11 +5864,11 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** sqlite3_backup_init(D,N,S,M) identify the [database connection]
|
||||
** and database name of the source database, respectively.
|
||||
** ^The source and destination [database connections] (parameters S and D)
|
||||
** must be different or else sqlite3_backup_init(D,N,S,M) will file with
|
||||
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
|
||||
** an error.
|
||||
**
|
||||
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
|
||||
** returned and an error code and error message are store3d in the
|
||||
** returned and an error code and error message are stored in the
|
||||
** destination [database connection] D.
|
||||
** ^The error code and message for the failed call to sqlite3_backup_init()
|
||||
** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or
|
||||
@@ -5813,7 +5885,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** the source and destination databases specified by [sqlite3_backup] object B.
|
||||
** ^If N is negative, all remaining source pages are copied.
|
||||
** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
|
||||
** are still more pages to be copied, then the function resturns [SQLITE_OK].
|
||||
** are still more pages to be copied, then the function returns [SQLITE_OK].
|
||||
** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
|
||||
** from source to destination, then it returns [SQLITE_DONE].
|
||||
** ^If an error occurs while running sqlite3_backup_step(B,N),
|
||||
@@ -5827,7 +5899,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** <li> the destination database was opened read-only, or
|
||||
** <li> the destination database is using write-ahead-log journaling
|
||||
** and the destination and source page sizes differ, or
|
||||
** <li> The destination database is an in-memory database and the
|
||||
** <li> the destination database is an in-memory database and the
|
||||
** destination and source page sizes differ.
|
||||
** </ol>)^
|
||||
**
|
||||
@@ -6158,7 +6230,8 @@ void *sqlite3_wal_hook(
|
||||
** from SQL.
|
||||
**
|
||||
** ^Every new [database connection] defaults to having the auto-checkpoint
|
||||
** enabled with a threshold of 1000 pages. The use of this interface
|
||||
** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
|
||||
** pages. The use of this interface
|
||||
** is only necessary if the default setting is found to be suboptimal
|
||||
** for a particular application.
|
||||
*/
|
||||
|
||||
@@ -737,6 +737,7 @@ struct Lookaside {
|
||||
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
|
||||
int nOut; /* Number of buffers currently checked out */
|
||||
int mxOut; /* Highwater mark for nOut */
|
||||
int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
|
||||
LookasideSlot *pFree; /* List of available buffers */
|
||||
void *pStart; /* First byte of available memory space */
|
||||
void *pEnd; /* First byte past end of available space */
|
||||
@@ -815,6 +816,7 @@ struct sqlite3 {
|
||||
struct Vdbe *pVdbe; /* List of active virtual machines */
|
||||
int activeVdbeCnt; /* Number of VDBEs currently executing */
|
||||
int writeVdbeCnt; /* Number of active VDBEs that are writing */
|
||||
int vdbeExecCnt; /* Number of nested calls to VdbeExec() */
|
||||
void (*xTrace)(void*,const char*); /* Trace function */
|
||||
void *pTraceArg; /* Argument to the trace function */
|
||||
void (*xProfile)(void*,const char*,u64); /* Profiling function */
|
||||
|
||||
@@ -116,6 +116,22 @@ int sqlite3_db_status(
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_DBSTATUS_LOOKASIDE_HIT:
|
||||
case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
|
||||
case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
|
||||
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT );
|
||||
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
|
||||
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
|
||||
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
|
||||
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
|
||||
*pCurrent = 0;
|
||||
*pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
|
||||
if( resetFlag ){
|
||||
db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return an approximation for the amount of memory currently used
|
||||
** by all pagers associated with the given database connection. The
|
||||
|
||||
@@ -3582,6 +3582,11 @@ static void init_all(Tcl_Interp *interp){
|
||||
extern int Sqlitemultiplex_Init(Tcl_Interp*);
|
||||
extern int SqliteSuperlock_Init(Tcl_Interp*);
|
||||
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
extern int Zipvfs_Init(Tcl_Interp*);
|
||||
Zipvfs_Init(interp);
|
||||
#endif
|
||||
|
||||
Sqliteconfig_Init(interp);
|
||||
Sqlitetest1_Init(interp);
|
||||
Sqlitetest2_Init(interp);
|
||||
|
||||
+3
-3
@@ -4801,13 +4801,13 @@ static int file_control_test(
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_file_control(db, 0, 0, &iArg);
|
||||
assert( rc==SQLITE_ERROR );
|
||||
assert( rc==SQLITE_NOTFOUND );
|
||||
rc = sqlite3_file_control(db, "notadatabase", SQLITE_FCNTL_LOCKSTATE, &iArg);
|
||||
assert( rc==SQLITE_ERROR );
|
||||
rc = sqlite3_file_control(db, "main", -1, &iArg);
|
||||
assert( rc==SQLITE_ERROR );
|
||||
assert( rc==SQLITE_NOTFOUND );
|
||||
rc = sqlite3_file_control(db, "temp", -1, &iArg);
|
||||
assert( rc==SQLITE_ERROR );
|
||||
assert( rc==SQLITE_NOTFOUND || rc==SQLITE_ERROR );
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "autoindex", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_AUTORESET
|
||||
Tcl_SetVar2(interp, "sqlite_options", "autoreset", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "autoreset", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
+9
-4
@@ -1290,10 +1290,13 @@ static int test_db_status(
|
||||
const char *zName;
|
||||
int op;
|
||||
} aOp[] = {
|
||||
{ "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
|
||||
{ "SQLITE_DBSTATUS_CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
|
||||
{ "SQLITE_DBSTATUS_SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED },
|
||||
{ "SQLITE_DBSTATUS_STMT_USED", SQLITE_DBSTATUS_STMT_USED }
|
||||
{ "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
|
||||
{ "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
|
||||
{ "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED },
|
||||
{ "STMT_USED", SQLITE_DBSTATUS_STMT_USED },
|
||||
{ "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT },
|
||||
{ "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },
|
||||
{ "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL }
|
||||
};
|
||||
Tcl_Obj *pResult;
|
||||
if( objc!=4 ){
|
||||
@@ -1302,6 +1305,8 @@ static int test_db_status(
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zOpName = Tcl_GetString(objv[2]);
|
||||
if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;
|
||||
if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;
|
||||
for(i=0; i<ArraySize(aOp); i++){
|
||||
if( strcmp(aOp[i].zName, zOpName)==0 ){
|
||||
op = aOp[i].op;
|
||||
|
||||
+1
-1
@@ -247,7 +247,7 @@ static int test_read_mutex_counters(
|
||||
int ii;
|
||||
char *aName[8] = {
|
||||
"fast", "recursive", "static_master", "static_mem",
|
||||
"static_open", "static_prng", "static_lru", "static_lru2"
|
||||
"static_open", "static_prng", "static_lru", "static_pmem"
|
||||
};
|
||||
|
||||
if( objc!=1 ){
|
||||
|
||||
@@ -31,6 +31,20 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
** For an build without mutexes, no-op the mutex calls.
|
||||
*/
|
||||
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0
|
||||
#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8)
|
||||
#define sqlite3_mutex_free(X)
|
||||
#define sqlite3_mutex_enter(X)
|
||||
#define sqlite3_mutex_try(X) SQLITE_OK
|
||||
#define sqlite3_mutex_leave(X)
|
||||
#define sqlite3_mutex_held(X) ((void)(X),1)
|
||||
#define sqlite3_mutex_notheld(X) ((void)(X),1)
|
||||
#endif /* SQLITE_THREADSAFE==0 */
|
||||
|
||||
|
||||
/************************ Object Definitions ******************************/
|
||||
|
||||
/* Forward declaration of all object types */
|
||||
|
||||
@@ -540,6 +540,7 @@ static int tvfsOpen(
|
||||
pFd->zFilename = zName;
|
||||
pFd->pVfs = pVfs;
|
||||
pFd->pReal = (sqlite3_file *)&pFd[1];
|
||||
memset(pTestfile, 0, sizeof(TestvfsFile));
|
||||
pTestfile->pFd = pFd;
|
||||
|
||||
/* Evaluate the Tcl script:
|
||||
|
||||
+33
-57
@@ -39,16 +39,14 @@ typedef unsigned char Bool;
|
||||
**
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
**
|
||||
** If the VdbeCursor.isTriggerRow flag is set it means that this cursor is
|
||||
** really a single row that represents the NEW or OLD pseudo-table of
|
||||
** a row trigger. The data for the row is stored in VdbeCursor.pData and
|
||||
** the rowid is in VdbeCursor.iKey.
|
||||
*/
|
||||
struct VdbeCursor {
|
||||
BtCursor *pCursor; /* The cursor structure of the backend */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
int iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
||||
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
|
||||
int pseudoTableReg; /* Register holding pseudotable content. */
|
||||
int nField; /* Number of fields in the header */
|
||||
Bool zeroed; /* True if zeroed out and ready for reuse */
|
||||
Bool rowidIsValid; /* True if lastRowid is valid */
|
||||
Bool atFirst; /* True if pointing to first entry */
|
||||
@@ -58,14 +56,11 @@ struct VdbeCursor {
|
||||
Bool isTable; /* True if a table requiring integer keys */
|
||||
Bool isIndex; /* True if an index containing keys only - no data */
|
||||
Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
int pseudoTableReg; /* Register holding pseudotable content. */
|
||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
int nField; /* Number of fields in the header */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
|
||||
const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
|
||||
|
||||
/* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or
|
||||
** OP_IsUnique opcode on this cursor. */
|
||||
@@ -137,25 +132,19 @@ struct VdbeFrame {
|
||||
/*
|
||||
** Internally, the vdbe manipulates nearly all SQL values as Mem
|
||||
** structures. Each Mem struct may cache multiple representations (string,
|
||||
** integer etc.) of the same value. A value (and therefore Mem structure)
|
||||
** has the following properties:
|
||||
**
|
||||
** Each value has a manifest type. The manifest type of the value stored
|
||||
** in a Mem struct is returned by the MemType(Mem*) macro. The type is
|
||||
** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or
|
||||
** SQLITE_BLOB.
|
||||
** integer etc.) of the same value.
|
||||
*/
|
||||
struct Mem {
|
||||
sqlite3 *db; /* The associated database connection */
|
||||
char *z; /* String or BLOB value */
|
||||
double r; /* Real value */
|
||||
union {
|
||||
i64 i; /* Integer value. */
|
||||
i64 i; /* Integer value used when MEM_Int is set in flags */
|
||||
int nZero; /* Used when bit MEM_Zero is set in flags */
|
||||
FuncDef *pDef; /* Used only when flags==MEM_Agg */
|
||||
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
|
||||
VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
|
||||
} u;
|
||||
double r; /* Real value */
|
||||
sqlite3 *db; /* The associated database connection */
|
||||
char *z; /* String or BLOB value */
|
||||
int n; /* Number of characters in string value, excluding '\0' */
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
|
||||
@@ -179,9 +168,6 @@ struct Mem {
|
||||
** database (see below for exceptions). If the MEM_Term flag is also
|
||||
** set, then the string is nul terminated. The MEM_Int and MEM_Real
|
||||
** flags may coexist with the MEM_Str flag.
|
||||
**
|
||||
** Multiple of these values can appear in Mem.flags. But only one
|
||||
** at a time can appear in Mem.type.
|
||||
*/
|
||||
#define MEM_Null 0x0001 /* Value is NULL */
|
||||
#define MEM_Str 0x0002 /* Value is a string */
|
||||
@@ -264,23 +250,11 @@ struct sqlite3_context {
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
};
|
||||
|
||||
/*
|
||||
** A Set structure is used for quick testing to see if a value
|
||||
** is part of a small set. Sets are used to implement code like
|
||||
** this:
|
||||
** x.y IN ('hi','hoo','hum')
|
||||
*/
|
||||
typedef struct Set Set;
|
||||
struct Set {
|
||||
Hash hash; /* A set is just a hash table */
|
||||
HashElem *prev; /* Previously accessed hash elemen */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the virtual machine. This structure contains the complete
|
||||
** state of the virtual machine.
|
||||
**
|
||||
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
|
||||
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
|
||||
** is really a pointer to an instance of this structure.
|
||||
**
|
||||
** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
|
||||
@@ -293,31 +267,31 @@ struct Set {
|
||||
*/
|
||||
struct Vdbe {
|
||||
sqlite3 *db; /* The database connection that owns this statement */
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
int nOp; /* Number of instructions in the program */
|
||||
int nOpAlloc; /* Number of slots allocated for aOp[] */
|
||||
Op *aOp; /* Space to hold the virtual machine's program */
|
||||
int nLabel; /* Number of labels used */
|
||||
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
|
||||
int *aLabel; /* Space to hold the labels */
|
||||
Mem *aMem; /* The memory locations */
|
||||
Mem **apArg; /* Arguments to currently executing user function */
|
||||
Mem *aColName; /* Column names to return */
|
||||
Mem *pResultSet; /* Pointer to an array of results */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
int nOp; /* Number of instructions in the program */
|
||||
int nOpAlloc; /* Number of slots allocated for aOp[] */
|
||||
int nLabel; /* Number of labels used */
|
||||
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
|
||||
int *aLabel; /* Space to hold the labels */
|
||||
u16 nResColumn; /* Number of columns in one row of the result set */
|
||||
u16 nCursor; /* Number of slots in apCsr[] */
|
||||
u32 magic; /* Magic number for sanity checking */
|
||||
char *zErrMsg; /* Error message written here */
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
VdbeCursor **apCsr; /* One element of this array for each open cursor */
|
||||
u8 errorAction; /* Recovery action to do in case of an error */
|
||||
u8 okVar; /* True if azVar[] has been initialized */
|
||||
ynVar nVar; /* Number of entries in aVar[] */
|
||||
Mem *aVar; /* Values for the OP_Variable opcode. */
|
||||
char **azVar; /* Name of variables */
|
||||
u32 magic; /* Magic number for sanity checking */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
Mem *aMem; /* The memory locations */
|
||||
ynVar nVar; /* Number of entries in aVar[] */
|
||||
u32 cacheCtr; /* VdbeCursor row cache generation counter */
|
||||
int pc; /* The program counter */
|
||||
int rc; /* Value to return */
|
||||
char *zErrMsg; /* Error message written here */
|
||||
u8 errorAction; /* Recovery action to do in case of an error */
|
||||
u8 okVar; /* True if azVar[] has been initialized */
|
||||
u8 explain; /* True if EXPLAIN present on SQL command */
|
||||
u8 changeCntOn; /* True to update the change-counter */
|
||||
u8 expired; /* True if the VM needs to be recompiled */
|
||||
@@ -329,14 +303,16 @@ struct Vdbe {
|
||||
u8 isPrepareV2; /* True if prepared with prepare_v2() */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
|
||||
i64 startTime; /* Time when query started - used for profiling */
|
||||
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
|
||||
int iStatement; /* Statement number (or 0 if has not opened stmt) */
|
||||
int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
|
||||
char *zSql; /* Text of the SQL statement that generated this */
|
||||
void *pFree; /* Free this when deleting the vdbe */
|
||||
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
i64 startTime; /* Time when query started - used for profiling */
|
||||
#endif
|
||||
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
|
||||
i64 nStmtDefCons; /* Number of def. constraints when stmt started */
|
||||
int iStatement; /* Statement number (or 0 if has not opened stmt) */
|
||||
char *zSql; /* Text of the SQL statement that generated this */
|
||||
void *pFree; /* Free this when deleting the vdbe */
|
||||
#ifdef SQLITE_DEBUG
|
||||
FILE *trace; /* Write an execution trace here, if not NULL */
|
||||
#endif
|
||||
|
||||
+25
-4
@@ -345,11 +345,30 @@ static int sqlite3Step(Vdbe *p){
|
||||
assert(p);
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
/* We used to require that sqlite3_reset() be called before retrying
|
||||
** sqlite3_step() after any error. But after 3.6.23, we changed this
|
||||
** so that sqlite3_reset() would be called automatically instead of
|
||||
** throwing the error.
|
||||
** sqlite3_step() after any error or after SQLITE_DONE. But beginning
|
||||
** with version 3.7.0, we changed this so that sqlite3_reset() would
|
||||
** be called automatically instead of throwing the SQLITE_MISUSE error.
|
||||
** This "automatic-reset" change is not technically an incompatibility,
|
||||
** since any application that receives an SQLITE_MISUSE is broken by
|
||||
** definition.
|
||||
**
|
||||
** Nevertheless, some published applications that were originally written
|
||||
** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
|
||||
** returns, and the so were broken by the automatic-reset change. As a
|
||||
** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
|
||||
** legacy behavior of returning SQLITE_MISUSE for cases where the
|
||||
** previous sqlite3_step() returned something other than a SQLITE_LOCKED
|
||||
** or SQLITE_BUSY error.
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_AUTORESET
|
||||
if( p->rc==SQLITE_BUSY || p->rc==SQLITE_LOCKED ){
|
||||
sqlite3_reset((sqlite3_stmt*)p);
|
||||
}else{
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#else
|
||||
sqlite3_reset((sqlite3_stmt*)p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check that malloc() has not failed. If it has, return early. */
|
||||
@@ -391,7 +410,9 @@ static int sqlite3Step(Vdbe *p){
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
{
|
||||
db->vdbeExecCnt++;
|
||||
rc = sqlite3VdbeExec(p);
|
||||
db->vdbeExecCnt--;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
@@ -685,7 +706,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
||||
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
|
||||
__attribute__((aligned(8)))
|
||||
#endif
|
||||
= {{0}, (double)0, 0, "", 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
|
||||
= {0, "", (double)0, {0}, 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
|
||||
|
||||
if( pVm && ALWAYS(pVm->db) ){
|
||||
sqlite3_mutex_enter(pVm->db->mutex);
|
||||
|
||||
+1
-1
@@ -408,7 +408,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
pOp->opflags = sqlite3OpcodeProperty[opcode];
|
||||
if( opcode==OP_Function || opcode==OP_AggStep ){
|
||||
if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
|
||||
}else if( opcode==OP_Transaction && pOp->p2!=0 ){
|
||||
}else if( (opcode==OP_Transaction && pOp->p2!=0) || opcode==OP_Vacuum ){
|
||||
p->readOnly = 0;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
}else if( opcode==OP_VUpdate ){
|
||||
|
||||
+68
-56
@@ -44,9 +44,12 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to a string in memory obtained form sqlite3DbMalloc() which
|
||||
** holds a copy of zRawSql but with host parameters expanded to their
|
||||
** current bindings.
|
||||
** This function returns a pointer to a nul-terminated string in memory
|
||||
** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the
|
||||
** string contains a copy of zRawSql but with host parameters expanded to
|
||||
** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1,
|
||||
** then the returned string holds a copy of zRawSql with "-- " prepended
|
||||
** to each line of text.
|
||||
**
|
||||
** The calling function is responsible for making sure the memory returned
|
||||
** is eventually freed.
|
||||
@@ -77,63 +80,72 @@ char *sqlite3VdbeExpandSql(
|
||||
sqlite3StrAccumInit(&out, zBase, sizeof(zBase),
|
||||
db->aLimit[SQLITE_LIMIT_LENGTH]);
|
||||
out.db = db;
|
||||
while( zRawSql[0] ){
|
||||
n = findNextHostParameter(zRawSql, &nToken);
|
||||
assert( n>0 );
|
||||
sqlite3StrAccumAppend(&out, zRawSql, n);
|
||||
zRawSql += n;
|
||||
assert( zRawSql[0] || nToken==0 );
|
||||
if( nToken==0 ) break;
|
||||
if( zRawSql[0]=='?' ){
|
||||
if( nToken>1 ){
|
||||
assert( sqlite3Isdigit(zRawSql[1]) );
|
||||
sqlite3GetInt32(&zRawSql[1], &idx);
|
||||
}else{
|
||||
idx = nextIndex;
|
||||
}
|
||||
}else{
|
||||
assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
|
||||
testcase( zRawSql[0]==':' );
|
||||
testcase( zRawSql[0]=='$' );
|
||||
testcase( zRawSql[0]=='@' );
|
||||
idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
|
||||
assert( idx>0 );
|
||||
if( db->vdbeExecCnt>1 ){
|
||||
while( *zRawSql ){
|
||||
const char *zStart = zRawSql;
|
||||
while( *(zRawSql++)!='\n' && *zRawSql );
|
||||
sqlite3StrAccumAppend(&out, "-- ", 3);
|
||||
sqlite3StrAccumAppend(&out, zStart, zRawSql-zStart);
|
||||
}
|
||||
zRawSql += nToken;
|
||||
nextIndex = idx + 1;
|
||||
assert( idx>0 && idx<=p->nVar );
|
||||
pVar = &p->aVar[idx-1];
|
||||
if( pVar->flags & MEM_Null ){
|
||||
sqlite3StrAccumAppend(&out, "NULL", 4);
|
||||
}else if( pVar->flags & MEM_Int ){
|
||||
sqlite3XPrintf(&out, "%lld", pVar->u.i);
|
||||
}else if( pVar->flags & MEM_Real ){
|
||||
sqlite3XPrintf(&out, "%!.15g", pVar->r);
|
||||
}else if( pVar->flags & MEM_Str ){
|
||||
}else{
|
||||
while( zRawSql[0] ){
|
||||
n = findNextHostParameter(zRawSql, &nToken);
|
||||
assert( n>0 );
|
||||
sqlite3StrAccumAppend(&out, zRawSql, n);
|
||||
zRawSql += n;
|
||||
assert( zRawSql[0] || nToken==0 );
|
||||
if( nToken==0 ) break;
|
||||
if( zRawSql[0]=='?' ){
|
||||
if( nToken>1 ){
|
||||
assert( sqlite3Isdigit(zRawSql[1]) );
|
||||
sqlite3GetInt32(&zRawSql[1], &idx);
|
||||
}else{
|
||||
idx = nextIndex;
|
||||
}
|
||||
}else{
|
||||
assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
|
||||
testcase( zRawSql[0]==':' );
|
||||
testcase( zRawSql[0]=='$' );
|
||||
testcase( zRawSql[0]=='@' );
|
||||
idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
|
||||
assert( idx>0 );
|
||||
}
|
||||
zRawSql += nToken;
|
||||
nextIndex = idx + 1;
|
||||
assert( idx>0 && idx<=p->nVar );
|
||||
pVar = &p->aVar[idx-1];
|
||||
if( pVar->flags & MEM_Null ){
|
||||
sqlite3StrAccumAppend(&out, "NULL", 4);
|
||||
}else if( pVar->flags & MEM_Int ){
|
||||
sqlite3XPrintf(&out, "%lld", pVar->u.i);
|
||||
}else if( pVar->flags & MEM_Real ){
|
||||
sqlite3XPrintf(&out, "%!.15g", pVar->r);
|
||||
}else if( pVar->flags & MEM_Str ){
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
u8 enc = ENC(db);
|
||||
if( enc!=SQLITE_UTF8 ){
|
||||
Mem utf8;
|
||||
memset(&utf8, 0, sizeof(utf8));
|
||||
utf8.db = db;
|
||||
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
|
||||
sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
|
||||
sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
|
||||
sqlite3VdbeMemRelease(&utf8);
|
||||
}else
|
||||
u8 enc = ENC(db);
|
||||
if( enc!=SQLITE_UTF8 ){
|
||||
Mem utf8;
|
||||
memset(&utf8, 0, sizeof(utf8));
|
||||
utf8.db = db;
|
||||
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
|
||||
sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
|
||||
sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
|
||||
sqlite3VdbeMemRelease(&utf8);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
|
||||
{
|
||||
sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
|
||||
}
|
||||
}else if( pVar->flags & MEM_Zero ){
|
||||
sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
|
||||
}else{
|
||||
assert( pVar->flags & MEM_Blob );
|
||||
sqlite3StrAccumAppend(&out, "x'", 2);
|
||||
for(i=0; i<pVar->n; i++){
|
||||
sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
|
||||
}
|
||||
sqlite3StrAccumAppend(&out, "'", 1);
|
||||
}
|
||||
}else if( pVar->flags & MEM_Zero ){
|
||||
sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
|
||||
}else{
|
||||
assert( pVar->flags & MEM_Blob );
|
||||
sqlite3StrAccumAppend(&out, "x'", 2);
|
||||
for(i=0; i<pVar->n; i++){
|
||||
sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
|
||||
}
|
||||
sqlite3StrAccumAppend(&out, "'", 1);
|
||||
}
|
||||
}
|
||||
return sqlite3StrAccumFinish(&out);
|
||||
|
||||
@@ -458,14 +458,14 @@ typedef u16 ht_slot;
|
||||
*/
|
||||
struct WalIterator {
|
||||
int iPrior; /* Last result returned from the iterator */
|
||||
int nSegment; /* Size of the aSegment[] array */
|
||||
int nSegment; /* Number of entries in aSegment[] */
|
||||
struct WalSegment {
|
||||
int iNext; /* Next slot in aIndex[] not yet returned */
|
||||
ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
|
||||
u32 *aPgno; /* Array of page numbers. */
|
||||
int nEntry; /* Max size of aPgno[] and aIndex[] arrays */
|
||||
int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
|
||||
int iZero; /* Frame number associated with aPgno[0] */
|
||||
} aSegment[1]; /* One for every 32KB page in the WAL */
|
||||
} aSegment[1]; /* One for every 32KB page in the wal-index */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1329,9 +1329,29 @@ static int walIteratorNext(
|
||||
|
||||
/*
|
||||
** This function merges two sorted lists into a single sorted list.
|
||||
**
|
||||
** aLeft[] and aRight[] are arrays of indices. The sort key is
|
||||
** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following
|
||||
** is guaranteed for all J<K:
|
||||
**
|
||||
** aContent[aLeft[J]] < aContent[aLeft[K]]
|
||||
** aContent[aRight[J]] < aContent[aRight[K]]
|
||||
**
|
||||
** This routine overwrites aRight[] with a new (probably longer) sequence
|
||||
** of indices such that the aRight[] contains every index that appears in
|
||||
** either aLeft[] or the old aRight[] and such that the second condition
|
||||
** above is still met.
|
||||
**
|
||||
** The aContent[aLeft[X]] values will be unique for all X. And the
|
||||
** aContent[aRight[X]] values will be unique too. But there might be
|
||||
** one or more combinations of X and Y such that
|
||||
**
|
||||
** aLeft[X]!=aRight[Y] && aContent[aLeft[X]] == aContent[aRight[Y]]
|
||||
**
|
||||
** When that happens, omit the aLeft[X] and use the aRight[Y] index.
|
||||
*/
|
||||
static void walMerge(
|
||||
u32 *aContent, /* Pages in wal */
|
||||
const u32 *aContent, /* Pages in wal - keys for the sort */
|
||||
ht_slot *aLeft, /* IN: Left hand input list */
|
||||
int nLeft, /* IN: Elements in array *paLeft */
|
||||
ht_slot **paRight, /* IN/OUT: Right hand input list */
|
||||
@@ -1371,10 +1391,24 @@ static void walMerge(
|
||||
}
|
||||
|
||||
/*
|
||||
** Sort the elements in list aList, removing any duplicates.
|
||||
** Sort the elements in list aList using aContent[] as the sort key.
|
||||
** Remove elements with duplicate keys, preferring to keep the
|
||||
** larger aList[] values.
|
||||
**
|
||||
** The aList[] entries are indices into aContent[]. The values in
|
||||
** aList[] are to be sorted so that for all J<K:
|
||||
**
|
||||
** aContent[aList[J]] < aContent[aList[K]]
|
||||
**
|
||||
** For any X and Y such that
|
||||
**
|
||||
** aContent[aList[X]] == aContent[aList[Y]]
|
||||
**
|
||||
** Keep the larger of the two values aList[X] and aList[Y] and discard
|
||||
** the smaller.
|
||||
*/
|
||||
static void walMergesort(
|
||||
u32 *aContent, /* Pages in wal */
|
||||
const u32 *aContent, /* Pages in wal */
|
||||
ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
|
||||
ht_slot *aList, /* IN/OUT: List to sort */
|
||||
int *pnList /* IN/OUT: Number of elements in aList[] */
|
||||
@@ -1439,6 +1473,7 @@ static void walIteratorFree(WalIterator *p){
|
||||
/*
|
||||
** Construct a WalInterator object that can be used to loop over all
|
||||
** pages in the WAL in ascending order. The caller must hold the checkpoint
|
||||
** lock.
|
||||
**
|
||||
** On success, make *pp point to the newly allocated WalInterator object
|
||||
** return SQLITE_OK. Otherwise, return an error code. If this routine
|
||||
@@ -1573,7 +1608,8 @@ static int walCheckpoint(
|
||||
szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
if( pWal->hdr.mxFrame==0 ) return SQLITE_OK;
|
||||
pInfo = walCkptInfo(pWal);
|
||||
if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
|
||||
|
||||
/* Allocate the iterator */
|
||||
rc = walIteratorInit(pWal, &pIter);
|
||||
@@ -1595,7 +1631,6 @@ static int walCheckpoint(
|
||||
*/
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
pInfo = walCkptInfo(pWal);
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
if( mxSafeFrame>=y ){
|
||||
|
||||
+3
-4
@@ -2315,10 +2315,9 @@ static int valueFromExpr(
|
||||
u8 aff,
|
||||
sqlite3_value **pp
|
||||
){
|
||||
/* The evalConstExpr() function will have already converted any TK_VARIABLE
|
||||
** expression involved in an comparison into a TK_REGISTER. */
|
||||
assert( pExpr->op!=TK_VARIABLE );
|
||||
if( pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE ){
|
||||
if( pExpr->op==TK_VARIABLE
|
||||
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
|
||||
){
|
||||
int iVar = pExpr->iColumn;
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-23257-02778 */
|
||||
*pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
# 2011 January 04
|
||||
#
|
||||
# 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. This file
|
||||
# implements tests for ANALYZE to verify that multiple rows containing
|
||||
# a NULL value count as distinct rows for the purposes of analyze
|
||||
# statistics.
|
||||
#
|
||||
# Also include test cases for collating sequences on indices.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_test analyze4-1.0 {
|
||||
db eval {
|
||||
CREATE TABLE t1(a,b);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
INSERT INTO t1 VALUES(1,NULL);
|
||||
INSERT INTO t1 SELECT a+1, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+2, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+4, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+8, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+16, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+32, b FROM t1;
|
||||
INSERT INTO t1 SELECT a+64, b FROM t1;
|
||||
ANALYZE;
|
||||
}
|
||||
|
||||
# Should choose the t1a index since it is more specific than t1b.
|
||||
db eval {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=5 AND b IS NULL}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
|
||||
|
||||
# Verify that the t1b index shows that it does not narrow down the
|
||||
# search any at all.
|
||||
#
|
||||
do_test analyze4-1.1 {
|
||||
db eval {
|
||||
SELECT idx, stat FROM sqlite_stat1 WHERE tbl='t1' ORDER BY idx;
|
||||
}
|
||||
} {t1a {128 1} t1b {128 128}}
|
||||
|
||||
# Change half of the b values from NULL to a constant. Verify
|
||||
# that the number of rows selected in stat1 is half the total
|
||||
# number of rows.
|
||||
#
|
||||
do_test analyze4-1.2 {
|
||||
db eval {
|
||||
UPDATE t1 SET b='x' WHERE a%2;
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 WHERE tbl='t1' ORDER BY idx;
|
||||
}
|
||||
} {t1a {128 1} t1b {128 64}}
|
||||
|
||||
# Change the t1.b values all back to NULL. Add columns t1.c and t1.d.
|
||||
# Create a multi-column indices using t1.b and verify that ANALYZE
|
||||
# processes them correctly.
|
||||
#
|
||||
do_test analyze4-1.3 {
|
||||
db eval {
|
||||
UPDATE t1 SET b=NULL;
|
||||
ALTER TABLE t1 ADD COLUMN c;
|
||||
ALTER TABLE t1 ADD COLUMN d;
|
||||
UPDATE t1 SET c=a/4, d=a/2;
|
||||
CREATE INDEX t1bcd ON t1(b,c,d);
|
||||
CREATE INDEX t1cdb ON t1(c,d,b);
|
||||
CREATE INDEX t1cbd ON t1(c,b,d);
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 WHERE tbl='t1' ORDER BY idx;
|
||||
}
|
||||
} {t1a {128 1} t1b {128 128} t1bcd {128 128 4 2} t1cbd {128 4 4 2} t1cdb {128 4 2 2}}
|
||||
|
||||
# Verify that collating sequences are taken into account when computing
|
||||
# ANALYZE statistics.
|
||||
#
|
||||
do_test analyze4-2.0 {
|
||||
db eval {
|
||||
CREATE TABLE t2(
|
||||
x INTEGER PRIMARY KEY,
|
||||
a TEXT COLLATE nocase,
|
||||
b TEXT COLLATE rtrim,
|
||||
c TEXT COLLATE binary
|
||||
);
|
||||
CREATE INDEX t2a ON t2(a);
|
||||
CREATE INDEX t2b ON t2(b);
|
||||
CREATE INDEX t2c ON t2(c);
|
||||
CREATE INDEX t2c2 ON t2(c COLLATE nocase);
|
||||
CREATE INDEX t2c3 ON t2(c COLLATE rtrim);
|
||||
INSERT INTO t2 VALUES(1, 'abc', 'abc', 'abc');
|
||||
INSERT INTO t2 VALUES(2, 'abC', 'abC', 'abC');
|
||||
INSERT INTO t2 VALUES(3, 'abc ', 'abc ', 'abc ');
|
||||
INSERT INTO t2 VALUES(4, 'abC ', 'abC ', 'abC ');
|
||||
INSERT INTO t2 VALUES(5, 'aBc', 'aBc', 'aBc');
|
||||
INSERT INTO t2 VALUES(6, 'aBC', 'aBC', 'aBC');
|
||||
INSERT INTO t2 VALUES(7, 'aBc ', 'aBc ', 'aBc ');
|
||||
INSERT INTO t2 VALUES(8, 'aBC ', 'aBC ', 'aBC ');
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 WHERE tbl='t2' ORDER BY idx;
|
||||
}
|
||||
} {t2a {8 4} t2b {8 2} t2c {8 1} t2c2 {8 4} t2c3 {8 2}}
|
||||
|
||||
finish_test
|
||||
+9
-3
@@ -74,9 +74,15 @@ do_test capi2-1.7 {
|
||||
|
||||
# This used to be SQLITE_MISUSE. But now we automatically reset prepared
|
||||
# statements.
|
||||
do_test capi2-1.8 {
|
||||
sqlite3_step $VM
|
||||
} {SQLITE_ROW}
|
||||
ifcapable autoreset {
|
||||
do_test capi2-1.8 {
|
||||
sqlite3_step $VM
|
||||
} {SQLITE_ROW}
|
||||
} else {
|
||||
do_test capi2-1.8 {
|
||||
sqlite3_step $VM
|
||||
} {SQLITE_MISUSE}
|
||||
}
|
||||
|
||||
# Update: In v2, once SQLITE_MISUSE is returned the statement handle cannot
|
||||
# be interrogated for more information. However in v3, since the column
|
||||
|
||||
+10
-9
@@ -163,6 +163,7 @@ do_test exclusive2-1.10 {
|
||||
do_test exclusive2-1.11 {
|
||||
expr {[t1sig] eq $::sig}
|
||||
} {0}
|
||||
db2 close
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# These tests - exclusive2-2.X - are similar to exclusive2-1.X,
|
||||
@@ -252,7 +253,6 @@ do_test exclusive2-2.8 {
|
||||
#
|
||||
|
||||
db close
|
||||
db2 close
|
||||
catch {close $::fd}
|
||||
file delete -force test.db
|
||||
file delete -force test.db-journal
|
||||
@@ -262,47 +262,48 @@ do_test exclusive2-3.0 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
CREATE TABLE t1(a UNIQUE);
|
||||
INSERT INTO t1 VALUES(randstr(10, 400));
|
||||
INSERT INTO t1 VALUES(randstr(10, 400));
|
||||
INSERT INTO t1 VALUES(randstr(200, 200));
|
||||
INSERT INTO t1 VALUES(randstr(200, 200));
|
||||
COMMIT;
|
||||
}
|
||||
readPagerChangeCounter test.db
|
||||
} {1}
|
||||
do_test exclusive2-3.1 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(randstr(10, 400));
|
||||
INSERT INTO t1 VALUES(randstr(200, 200));
|
||||
}
|
||||
readPagerChangeCounter test.db
|
||||
} {2}
|
||||
do_test exclusive2-3.2 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(randstr(10, 400));
|
||||
INSERT INTO t1 VALUES(randstr(200, 200));
|
||||
}
|
||||
readPagerChangeCounter test.db
|
||||
} {3}
|
||||
do_test exclusive2-3.3 {
|
||||
execsql {
|
||||
PRAGMA locking_mode = exclusive;
|
||||
INSERT INTO t1 VALUES(randstr(10, 400));
|
||||
INSERT INTO t1 VALUES(randstr(200, 200));
|
||||
}
|
||||
readPagerChangeCounter test.db
|
||||
} {4}
|
||||
do_test exclusive2-3.4 {
|
||||
breakpoint
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(randstr(10, 400));
|
||||
INSERT INTO t1 VALUES(randstr(200, 200));
|
||||
}
|
||||
readPagerChangeCounter test.db
|
||||
} {4}
|
||||
do_test exclusive2-3.5 {
|
||||
execsql {
|
||||
PRAGMA locking_mode = normal;
|
||||
INSERT INTO t1 VALUES(randstr(10, 400));
|
||||
INSERT INTO t1 VALUES(randstr(200, 200));
|
||||
}
|
||||
readPagerChangeCounter test.db
|
||||
} {4}
|
||||
do_test exclusive2-3.6 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(randstr(10, 400));
|
||||
INSERT INTO t1 VALUES(randstr(200, 200));
|
||||
}
|
||||
readPagerChangeCounter test.db
|
||||
} {5}
|
||||
|
||||
+9
-3
@@ -1414,9 +1414,15 @@ do_test fkey2-17.1.2 {
|
||||
set STMT [sqlite3_prepare_v2 db "INSERT INTO two VALUES(4, 5, 6)" -1 dummy]
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_CONSTRAINT}
|
||||
do_test fkey2-17.1.3 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_CONSTRAINT}
|
||||
ifcapable autoreset {
|
||||
do_test fkey2-17.1.3 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_CONSTRAINT}
|
||||
} else {
|
||||
do_test fkey2-17.1.3 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_MISUSE}
|
||||
}
|
||||
do_test fkey2-17.1.4 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_CONSTRAINT}
|
||||
|
||||
@@ -337,6 +337,48 @@ do_execsql_test 7.4 {
|
||||
FROM t10 WHERE t10 MATCH 'record'
|
||||
} {blob 20 blob 20}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test a special case - matchinfo('nxa') with many zero length documents.
|
||||
# Special because "x" internally uses a statement used by both "n" and "a".
|
||||
# This was causing a problem at one point in the obscure case where the
|
||||
# total number of bytes of data stored in an fts3 table was greater than
|
||||
# the number of rows. i.e. when the following query returns true:
|
||||
#
|
||||
# SELECT sum(length(content)) < count(*) FROM fts4table;
|
||||
#
|
||||
do_execsql_test 8.1 {
|
||||
CREATE VIRTUAL TABLE t11 USING fts4;
|
||||
INSERT INTO t11(t11) VALUES('nodesize=24');
|
||||
INSERT INTO t11 VALUES('quitealongstringoftext');
|
||||
INSERT INTO t11 VALUES('anotherquitealongstringoftext');
|
||||
INSERT INTO t11 VALUES('athirdlongstringoftext');
|
||||
INSERT INTO t11 VALUES('andonemoreforgoodluck');
|
||||
}
|
||||
do_test 8.2 {
|
||||
for {set i 0} {$i < 200} {incr i} {
|
||||
execsql { INSERT INTO t11 VALUES('') }
|
||||
}
|
||||
execsql { INSERT INTO t11(t11) VALUES('optimize') }
|
||||
} {}
|
||||
do_execsql_test 8.3 {
|
||||
SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
|
||||
} {{204 1 3 3 0} {204 1 3 3 0} {204 1 3 3 0}}
|
||||
|
||||
# Corruption related tests.
|
||||
do_execsql_test 8.4.1.1 { UPDATE t11_stat SET value = X'0000'; }
|
||||
do_catchsql_test 8.5.1.2 {
|
||||
SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_execsql_test 8.4.2.1 { UPDATE t11_stat SET value = X'00'; }
|
||||
do_catchsql_test 8.5.2.2 {
|
||||
SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_execsql_test 8.4.3.1 { UPDATE t11_stat SET value = NULL; }
|
||||
do_catchsql_test 8.5.3.2 {
|
||||
SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+5
-6
@@ -45,7 +45,7 @@ do_test jrnlmode3-1.2 {
|
||||
ROLLBACK;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 2}
|
||||
} {1}
|
||||
|
||||
db close
|
||||
file delete -force test.db test.db-journal
|
||||
@@ -67,7 +67,7 @@ do_test jrnlmode3-2.2 {
|
||||
ROLLBACK;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 2}
|
||||
} {1}
|
||||
|
||||
# Test cases to verify that we can move from any journal_mode
|
||||
# to any other, as long as we are not in a transaction. Verify
|
||||
@@ -112,15 +112,14 @@ foreach fromjmode $all_journal_modes {
|
||||
db eval "PRAGMA journal_mode=$tojmode"
|
||||
} $fromjmode
|
||||
|
||||
# Rollback the transaction. Verify that the rollback occurred
|
||||
# if journal_mode!=OFF.
|
||||
# Rollback the transaction.
|
||||
#
|
||||
do_test jrnlmode3-3.$cnt.4 {
|
||||
db eval {
|
||||
ROLLBACK;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} [expr {$fromjmode=="off"?$cnt:""}]
|
||||
} {}
|
||||
|
||||
# Now change the journal mode again. This time the new mode
|
||||
# should take.
|
||||
@@ -143,7 +142,7 @@ foreach fromjmode $all_journal_modes {
|
||||
db eval {
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} [expr {$tojmode=="off"?"1":""}]
|
||||
} {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-10
@@ -46,36 +46,48 @@ do_test lookaside-1.1 {
|
||||
do_test lookaside-1.2 {
|
||||
sqlite3_db_config_lookaside db 1 18 18
|
||||
} {0}
|
||||
do_test lookaside-1.3 {
|
||||
sqlite3_db_status db SQLITE_DBSTATUS_LOOKASIDE_USED 0
|
||||
do_test lookaside-1.3.1 {
|
||||
sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 0
|
||||
} {0 0 0}
|
||||
do_test lookaside-1.3.2 {
|
||||
sqlite3_db_status db DBSTATUS_LOOKASIDE_HIT 0
|
||||
} {0 0 0}
|
||||
do_test lookaside-1.3.3 {
|
||||
sqlite3_db_status db DBSTATUS_LOOKASIDE_MISS_SIZE 0
|
||||
} {0 0 0}
|
||||
do_test lookaside-1.3.4 {
|
||||
sqlite3_db_status db DBSTATUS_LOOKASIDE_MISS_FULL 0
|
||||
} {0 0 0}
|
||||
|
||||
do_test lookaside-1.4 {
|
||||
db eval {CREATE TABLE t1(w,x,y,z);}
|
||||
foreach {x y z} [sqlite3_db_status db SQLITE_DBSTATUS_LOOKASIDE_USED 0] break
|
||||
expr {$x==0 && $y<$z && $z==18}
|
||||
foreach {x y z} [sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 0] break
|
||||
set p [lindex [sqlite3_db_status db DBSTATUS_LOOKASIDE_HIT 0] 2]
|
||||
set q [lindex [sqlite3_db_status db DBSTATUS_LOOKASIDE_MISS_SIZE 0] 2]
|
||||
set r [lindex [sqlite3_db_status db DBSTATUS_LOOKASIDE_MISS_FULL 0] 2]
|
||||
expr {$x==0 && $y<$z && $z==18 && $p>0 && $q>0 && $r>0}
|
||||
} {0}
|
||||
do_test lookaside-1.5 {
|
||||
foreach {x y z} [sqlite3_db_status db SQLITE_DBSTATUS_LOOKASIDE_USED 1] break
|
||||
foreach {x y z} [sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 1] break
|
||||
expr {$x==0 && $y<$z && $z==18}
|
||||
} {0}
|
||||
do_test lookaside-1.6 {
|
||||
foreach {x y z} [sqlite3_db_status db SQLITE_DBSTATUS_LOOKASIDE_USED 0] break
|
||||
foreach {x y z} [sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 0] break
|
||||
expr {$x==0 && $y==$z && $y<18}
|
||||
} {1}
|
||||
do_test lookaside-1.7 {
|
||||
db cache flush
|
||||
foreach {x y z} [sqlite3_db_status db SQLITE_DBSTATUS_LOOKASIDE_USED 0] break
|
||||
foreach {x y z} [sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 0] break
|
||||
expr {$x==0 && $y==0 && $z<18}
|
||||
} {1}
|
||||
do_test lookaside-1.8 {
|
||||
db cache flush
|
||||
foreach {x y z} [sqlite3_db_status db SQLITE_DBSTATUS_LOOKASIDE_USED 1] break
|
||||
foreach {x y z} [sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 1] break
|
||||
expr {$x==0 && $y==0 && $z<18}
|
||||
} {1}
|
||||
do_test lookaside-1.9 {
|
||||
db cache flush
|
||||
sqlite3_db_status db SQLITE_DBSTATUS_LOOKASIDE_USED 0
|
||||
sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 0
|
||||
} {0 0 0}
|
||||
|
||||
do_test lookaside-2.1 {
|
||||
@@ -83,7 +95,7 @@ do_test lookaside-2.1 {
|
||||
} {0}
|
||||
do_test lookaside-2.2 {
|
||||
db eval {CREATE TABLE t2(x);}
|
||||
foreach {x y z} [sqlite3_db_status db SQLITE_DBSTATUS_LOOKASIDE_USED 0] break
|
||||
foreach {x y z} [sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 0] break
|
||||
expr {$x==0 && $y<$z && $z>10 && $z<100}
|
||||
} {1}
|
||||
do_test lookaside-2.3 {
|
||||
|
||||
+13
-1
@@ -106,6 +106,10 @@ set FAULTSIM(cantopen-persistent) [list \
|
||||
#
|
||||
# -test Script to execute after -body.
|
||||
#
|
||||
# -install Script to execute after faultsim -injectinstall
|
||||
#
|
||||
# -uninstall Script to execute after faultsim -uninjectinstall
|
||||
#
|
||||
proc do_faultsim_test {name args} {
|
||||
global FAULTSIM
|
||||
|
||||
@@ -113,6 +117,8 @@ proc do_faultsim_test {name args} {
|
||||
set DEFAULT(-prep) ""
|
||||
set DEFAULT(-body) ""
|
||||
set DEFAULT(-test) ""
|
||||
set DEFAULT(-install) ""
|
||||
set DEFAULT(-uninstall) ""
|
||||
|
||||
fix_testname name
|
||||
|
||||
@@ -129,7 +135,9 @@ proc do_faultsim_test {name args} {
|
||||
set faultlist [concat $faultlist $flist]
|
||||
}
|
||||
|
||||
set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)]
|
||||
set testspec [list -prep $O(-prep) -body $O(-body) \
|
||||
-test $O(-test) -install $O(-install) -uninstall $O(-uninstall)
|
||||
]
|
||||
foreach f [lsort -unique $faultlist] {
|
||||
eval do_one_faultsim_test "$name-$f" $FAULTSIM($f) $testspec
|
||||
}
|
||||
@@ -294,6 +302,8 @@ proc do_one_faultsim_test {testname args} {
|
||||
set DEFAULT(-prep) ""
|
||||
set DEFAULT(-body) ""
|
||||
set DEFAULT(-test) ""
|
||||
set DEFAULT(-install) ""
|
||||
set DEFAULT(-uninstall) ""
|
||||
|
||||
array set O [array get DEFAULT]
|
||||
array set O $args
|
||||
@@ -307,6 +317,7 @@ proc do_one_faultsim_test {testname args} {
|
||||
"
|
||||
|
||||
eval $O(-injectinstall)
|
||||
eval $O(-install)
|
||||
|
||||
set stop 0
|
||||
for {set iFail 1} {!$stop} {incr iFail} {
|
||||
@@ -338,6 +349,7 @@ proc do_one_faultsim_test {testname args} {
|
||||
if {$nfail==0} { set stop 1 }
|
||||
}
|
||||
|
||||
eval $O(-uninstall)
|
||||
eval $O(-injectuninstall)
|
||||
}
|
||||
|
||||
|
||||
@@ -96,9 +96,10 @@ sqlite3_initialize
|
||||
reset_highwater_marks
|
||||
build_test_db memsubsys1-2 {PRAGMA page_size=1024}
|
||||
#show_memstats
|
||||
set MEMORY_MANAGEMENT $sqlite_options(memorymanage)
|
||||
do_test memsubsys1-2.3 {
|
||||
set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
|
||||
} [expr ($AUTOVACUUM+$TEMP_STORE>=2)*1024]
|
||||
} [expr ($TEMP_STORE>1 || $MEMORY_MANAGEMENT==0)*1024]
|
||||
do_test memsubsys1-2.4 {
|
||||
set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
|
||||
} 20
|
||||
|
||||
+11
-3
@@ -101,8 +101,14 @@ ifcapable threadsafe&&shared_cache {
|
||||
set enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
foreach {mode mutexes} {
|
||||
singlethread {}
|
||||
multithread {fast static_lru static_master static_mem static_open static_prng }
|
||||
serialized {fast recursive static_lru static_master static_mem static_open static_prng}
|
||||
multithread {
|
||||
fast static_lru static_master static_mem static_open static_prng
|
||||
static_pmem
|
||||
}
|
||||
serialized {
|
||||
fast recursive static_lru static_master static_mem static_open
|
||||
static_prng static_pmem
|
||||
}
|
||||
} {
|
||||
|
||||
do_test mutex1.2.$mode.1 {
|
||||
@@ -120,7 +126,9 @@ ifcapable threadsafe&&shared_cache {
|
||||
INSERT INTO abc VALUES(1, 2, 3);
|
||||
}
|
||||
} {}
|
||||
|
||||
ifcapable !memorymanage {
|
||||
regsub { static_lru} $mutexes {} mutexes
|
||||
}
|
||||
do_test mutex1.2.$mode.3 {
|
||||
mutex_counters counters
|
||||
|
||||
|
||||
+2
-2
@@ -1614,7 +1614,7 @@ do_catchsql_test pager1-14.1.2 {
|
||||
} {0 {}}
|
||||
do_execsql_test pager1-14.1.3 {
|
||||
SELECT * FROM t1;
|
||||
} {1 2 3 4}
|
||||
} {1 2}
|
||||
do_catchsql_test pager1-14.1.4 {
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
|
||||
@@ -1623,7 +1623,7 @@ do_catchsql_test pager1-14.1.4 {
|
||||
do_execsql_test pager1-14.1.5 {
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
} {1 2 3 4 2 2 4 4}
|
||||
} {1 2 2 2}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test opening and closing the pager sub-system with different values
|
||||
|
||||
+1
-1
@@ -133,7 +133,7 @@ do_test pager2-2.1 {
|
||||
ROLLBACK;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {off 1 2}
|
||||
} {off}
|
||||
do_test pager2-2.2 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# 2011 January 28
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
if {[permutation] == "inmemory_journal"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Create a database with page-size 2048 bytes that uses 2 pages. Populate
|
||||
# it so that if the page-size is changed to 1024 bytes and the db vacuumed,
|
||||
# the new db size is 3 pages.
|
||||
#
|
||||
do_test pagerfault3-pre1 {
|
||||
execsql {
|
||||
PRAGMA page_size = 2048;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(randomblob(1200));
|
||||
PRAGMA page_count;
|
||||
}
|
||||
} {2}
|
||||
do_test pagerfault3-pre2 {
|
||||
faultsim_save_and_close
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
VACUUM;
|
||||
PRAGMA page_count;
|
||||
}
|
||||
} {3}
|
||||
|
||||
# Now do the page-size change and VACUUM with IO error injection. When
|
||||
# an IO error is injected into the final xSync() of the commit, the pager
|
||||
# will have to extend the db file from 3072 to 4096 byts when rolling
|
||||
# back the hot-journal file. This is a special case in pager_truncate().
|
||||
#
|
||||
do_faultsim_test pagerfault3-1 -faults ioerr-transient -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
VACUUM;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
faultsim_integrity_check
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -21,6 +21,14 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# Only works with a mode-2 pcache where all pcaches share a single set
|
||||
# of pages.
|
||||
#
|
||||
ifcapable {!memorymanage && threadsafe} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# The pcache module limits the number of pages available to purgeable
|
||||
# caches to the sum of the 'cache_size' values for the set of open
|
||||
# caches. This block of tests, pcache-1.*, test that the library behaves
|
||||
|
||||
+1
-1
@@ -905,7 +905,7 @@ if {[wal_is_wal_mode]==0} {
|
||||
ROLLBACK;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
|
||||
} {1 2 3 4 5 6 7 8 9 10 11 12}
|
||||
}
|
||||
|
||||
db close
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# 2011 January 15
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# This file implements tests to verify that ticket [5d863f876e] has been
|
||||
# fixed.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
|
||||
do_multiclient_test tn {
|
||||
do_test $tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
PRAGMA journal_mode = WAL;
|
||||
VACUUM;
|
||||
PRAGMA journal_mode = DELETE;
|
||||
}
|
||||
} {wal delete}
|
||||
|
||||
do_test $tn.2 {
|
||||
sql2 { SELECT * FROM t1 }
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test $tn.3 {
|
||||
sql1 {
|
||||
INSERT INTO t1 VALUES(5, 6);
|
||||
PRAGMA journal_mode = WAL;
|
||||
VACUUM;
|
||||
PRAGMA journal_mode = DELETE;
|
||||
}
|
||||
} {wal delete}
|
||||
|
||||
do_test $tn.2 {
|
||||
sql2 { PRAGMA integrity_check }
|
||||
} {ok}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,152 @@
|
||||
# 2011 Jan 21
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file implements tests for the "sqlite3_trace()" API. Specifically,
|
||||
# it tests the special handling of nested SQL statements (those executed
|
||||
# by virtual table or user function callbacks). These statements are treated
|
||||
# differently in two respects:
|
||||
#
|
||||
# 1. Each line of the statement is prefixed with "-- " to turn it into
|
||||
# an SQL comment.
|
||||
#
|
||||
# 2. Parameter expansion is not performed.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !trace { finish_test ; return }
|
||||
set ::testprefix trace2
|
||||
|
||||
proc sql {zSql} { db one $zSql }
|
||||
proc trace {zSql} { lappend ::trace $zSql }
|
||||
|
||||
db func sql sql
|
||||
db trace trace
|
||||
|
||||
proc do_trace_test {tn sql expected} {
|
||||
# Test that the list of string passed to the trace callback when $sql
|
||||
# is executed is equivalent to the list of strings in $expected.
|
||||
#
|
||||
set ::trace [list]
|
||||
execsql $sql
|
||||
uplevel do_test $tn [list {set ::trace}] [list [list {*}$expected]]
|
||||
}
|
||||
|
||||
proc do_trace_select_test {tn sql expected} {
|
||||
|
||||
uplevel [list do_trace_test ${tn}.a $sql $expected]
|
||||
|
||||
# Now execute each SQL statement passed to the trace callback in the
|
||||
# block above. Check that this causes the same set of strings to be
|
||||
# passed to the trace callback again. i.e. that executing the output
|
||||
# of the trace callback is equivalent to the SQL script in $sql.
|
||||
#
|
||||
set sqllist $::trace
|
||||
set ::trace [list]
|
||||
foreach item $sqllist { execsql $item }
|
||||
uplevel do_test $tn.b [list {set ::trace}] [list $sqllist]
|
||||
}
|
||||
|
||||
do_trace_select_test 1.1 {
|
||||
SELECT 1, 2, 3;
|
||||
} {
|
||||
"SELECT 1, 2, 3;"
|
||||
}
|
||||
|
||||
do_trace_select_test 1.2 {
|
||||
SELECT sql('SELECT 1, 2, 3');
|
||||
} {
|
||||
"SELECT sql('SELECT 1, 2, 3');"
|
||||
"-- SELECT 1, 2, 3"
|
||||
}
|
||||
|
||||
do_trace_select_test 1.3 {
|
||||
SELECT sql('SELECT 1,
|
||||
2,
|
||||
3'
|
||||
);
|
||||
} {
|
||||
"SELECT sql('SELECT 1,
|
||||
2,
|
||||
3'
|
||||
);"
|
||||
"-- SELECT 1,
|
||||
-- 2,
|
||||
-- 3"
|
||||
}
|
||||
|
||||
do_trace_select_test 1.4 {
|
||||
SELECT sql('SELECT 1,
|
||||
|
||||
|
||||
3'
|
||||
);
|
||||
} {
|
||||
"SELECT sql('SELECT 1,
|
||||
|
||||
|
||||
3'
|
||||
);"
|
||||
"-- SELECT 1,
|
||||
--
|
||||
--
|
||||
-- 3"
|
||||
}
|
||||
|
||||
do_trace_select_test 1.5 {
|
||||
SELECT $var, sql('SELECT 1,
|
||||
$var,
|
||||
3'
|
||||
);
|
||||
} {
|
||||
"SELECT NULL, sql('SELECT 1,
|
||||
$var,
|
||||
3'
|
||||
);"
|
||||
"-- SELECT 1,
|
||||
-- $var,
|
||||
-- 3"
|
||||
}
|
||||
|
||||
ifcapable fts3 {
|
||||
do_execsql_test 2.1 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts4;
|
||||
INSERT INTO x1 VALUES('Cloudy, with a high near 16');
|
||||
INSERT INTO x1 VALUES('Wind chill values as low as -13');
|
||||
}
|
||||
|
||||
do_trace_test 2.2 {
|
||||
INSERT INTO x1 VALUES('North northwest wind between 8 and 14 mph');
|
||||
} {
|
||||
"INSERT INTO x1 VALUES('North northwest wind between 8 and 14 mph');"
|
||||
"-- INSERT INTO 'main'.'x1_content' VALUES(?,?)"
|
||||
"-- REPLACE INTO 'main'.'x1_docsize' VALUES(?,?)"
|
||||
"-- SELECT value FROM 'main'.'x1_stat' WHERE id=0"
|
||||
"-- REPLACE INTO 'main'.'x1_stat' VALUES(0,?)"
|
||||
"-- SELECT (SELECT max(idx) FROM 'main'.'x1_segdir' WHERE level = ?) + 1"
|
||||
"-- SELECT coalesce((SELECT max(blockid) FROM 'main'.'x1_segments') + 1, 1)"
|
||||
"-- INSERT INTO 'main'.'x1_segdir' VALUES(?,?,?,?,?,?)"
|
||||
}
|
||||
|
||||
do_trace_test 2.3 {
|
||||
INSERT INTO x1(x1) VALUES('optimize');
|
||||
} {
|
||||
"INSERT INTO x1(x1) VALUES('optimize');"
|
||||
"-- SELECT count(*), max(level) FROM 'main'.'x1_segdir'"
|
||||
"-- SELECT idx, start_block, leaves_end_block, end_block, root FROM 'main'.'x1_segdir' ORDER BY level DESC, idx ASC"
|
||||
"-- SELECT coalesce((SELECT max(blockid) FROM 'main'.'x1_segments') + 1, 1)"
|
||||
"-- DELETE FROM 'main'.'x1_segdir'"
|
||||
"-- INSERT INTO 'main'.'x1_segdir' VALUES(?,?,?,?,?,?)"
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -53,7 +53,7 @@ set in [open $TOP/manifest]
|
||||
set zDate {}
|
||||
while {![eof $in]} {
|
||||
set line [gets $in]
|
||||
if {[regexp {^D (2.*[0-9])} $line all date]} {
|
||||
if {[regexp {^D (2[-0-9T:]+)} $line all date]} {
|
||||
set zDate [string map {T { }} $date]
|
||||
break
|
||||
}
|
||||
|
||||
+1
-1
@@ -200,7 +200,7 @@ do_test shell1-1.15.3 {
|
||||
# -version show SQLite version
|
||||
do_test shell1-1.16.1 {
|
||||
catchcmd "-version test.db" ""
|
||||
} {0 3.7.3}
|
||||
} {0 3.7.5}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases shell1-2.*: Basic "dot" command token parsing.
|
||||
|
||||
+175
-12
@@ -57,8 +57,9 @@ static void out_of_memory(void){
|
||||
*/
|
||||
static unsigned char *getContent(int ofst, int nByte){
|
||||
unsigned char *aData;
|
||||
aData = malloc(nByte);
|
||||
aData = malloc(nByte+32);
|
||||
if( aData==0 ) out_of_memory();
|
||||
memset(aData, 0, nByte+32);
|
||||
lseek(db, ofst, SEEK_SET);
|
||||
read(db, aData, nByte);
|
||||
return aData;
|
||||
@@ -181,56 +182,189 @@ static void print_db_header(void){
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a description for a single cell.
|
||||
** Describe cell content.
|
||||
*/
|
||||
static int describeCell(unsigned char cType, unsigned char *a, char **pzDesc){
|
||||
static int describeContent(
|
||||
unsigned char *a, /* Cell content */
|
||||
int nLocal, /* Bytes in a[] */
|
||||
char *zDesc /* Write description here */
|
||||
){
|
||||
int nDesc = 0;
|
||||
int n, i, j;
|
||||
i64 x, v;
|
||||
const unsigned char *pData;
|
||||
const unsigned char *pLimit;
|
||||
char sep = ' ';
|
||||
|
||||
pLimit = &a[nLocal];
|
||||
n = decodeVarint(a, &x);
|
||||
pData = &a[x];
|
||||
a += n;
|
||||
i = x - n;
|
||||
while( i>0 && pData<=pLimit ){
|
||||
n = decodeVarint(a, &x);
|
||||
a += n;
|
||||
i -= n;
|
||||
nLocal -= n;
|
||||
zDesc[0] = sep;
|
||||
sep = ',';
|
||||
nDesc++;
|
||||
zDesc++;
|
||||
if( x==0 ){
|
||||
sprintf(zDesc, "*"); /* NULL is a "*" */
|
||||
}else if( x>=1 && x<=6 ){
|
||||
v = (signed char)pData[0];
|
||||
pData++;
|
||||
switch( x ){
|
||||
case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
|
||||
case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
|
||||
case 4: v = (v<<8) + pData[0]; pData++;
|
||||
case 3: v = (v<<8) + pData[0]; pData++;
|
||||
case 2: v = (v<<8) + pData[0]; pData++;
|
||||
}
|
||||
sprintf(zDesc, "%lld", v);
|
||||
}else if( x==7 ){
|
||||
sprintf(zDesc, "real");
|
||||
pData += 8;
|
||||
}else if( x==8 ){
|
||||
sprintf(zDesc, "0");
|
||||
}else if( x==9 ){
|
||||
sprintf(zDesc, "1");
|
||||
}else if( x>=12 ){
|
||||
int size = (x-12)/2;
|
||||
if( (x&1)==0 ){
|
||||
sprintf(zDesc, "blob(%d)", size);
|
||||
}else{
|
||||
sprintf(zDesc, "txt(%d)", size);
|
||||
}
|
||||
pData += size;
|
||||
}
|
||||
j = strlen(zDesc);
|
||||
zDesc += j;
|
||||
nDesc += j;
|
||||
}
|
||||
return nDesc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the local payload size given the total payload size and
|
||||
** the page size.
|
||||
*/
|
||||
static int localPayload(i64 nPayload, char cType){
|
||||
int maxLocal;
|
||||
int minLocal;
|
||||
int surplus;
|
||||
int nLocal;
|
||||
if( cType==13 ){
|
||||
/* Table leaf */
|
||||
maxLocal = pagesize-35;
|
||||
minLocal = (pagesize-12)*32/255-23;
|
||||
}else{
|
||||
maxLocal = (pagesize-12)*64/255-23;
|
||||
minLocal = (pagesize-12)*32/255-23;
|
||||
}
|
||||
if( nPayload>maxLocal ){
|
||||
surplus = minLocal + (nPayload-minLocal)%(pagesize-4);
|
||||
if( surplus<=maxLocal ){
|
||||
nLocal = surplus;
|
||||
}else{
|
||||
nLocal = minLocal;
|
||||
}
|
||||
}else{
|
||||
nLocal = nPayload;
|
||||
}
|
||||
return nLocal;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Create a description for a single cell.
|
||||
**
|
||||
** The return value is the local cell size.
|
||||
*/
|
||||
static int describeCell(
|
||||
unsigned char cType, /* Page type */
|
||||
unsigned char *a, /* Cell content */
|
||||
int showCellContent, /* Show cell content if true */
|
||||
char **pzDesc /* Store description here */
|
||||
){
|
||||
int i;
|
||||
int nDesc = 0;
|
||||
int n = 0;
|
||||
int leftChild;
|
||||
i64 nPayload;
|
||||
i64 rowid;
|
||||
static char zDesc[100];
|
||||
int nLocal;
|
||||
static char zDesc[1000];
|
||||
i = 0;
|
||||
if( cType<=5 ){
|
||||
leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
|
||||
a += 4;
|
||||
n += 4;
|
||||
sprintf(zDesc, "left-child: %d ", leftChild);
|
||||
sprintf(zDesc, "lx: %d ", leftChild);
|
||||
nDesc = strlen(zDesc);
|
||||
}
|
||||
if( cType!=5 ){
|
||||
i = decodeVarint(a, &nPayload);
|
||||
a += i;
|
||||
n += i;
|
||||
sprintf(&zDesc[nDesc], "sz: %lld ", nPayload);
|
||||
sprintf(&zDesc[nDesc], "n: %lld ", nPayload);
|
||||
nDesc += strlen(&zDesc[nDesc]);
|
||||
nLocal = localPayload(nPayload, cType);
|
||||
}else{
|
||||
nPayload = nLocal = 0;
|
||||
}
|
||||
if( cType==5 || cType==13 ){
|
||||
i = decodeVarint(a, &rowid);
|
||||
a += i;
|
||||
n += i;
|
||||
sprintf(&zDesc[nDesc], "rowid: %lld ", rowid);
|
||||
sprintf(&zDesc[nDesc], "r: %lld ", rowid);
|
||||
nDesc += strlen(&zDesc[nDesc]);
|
||||
}
|
||||
if( nLocal<nPayload ){
|
||||
int ovfl;
|
||||
unsigned char *b = &a[nLocal];
|
||||
ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3];
|
||||
sprintf(&zDesc[nDesc], "ov: %d ", ovfl);
|
||||
nDesc += strlen(&zDesc[nDesc]);
|
||||
n += 4;
|
||||
}
|
||||
if( showCellContent && cType!=5 ){
|
||||
nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]);
|
||||
}
|
||||
*pzDesc = zDesc;
|
||||
return n;
|
||||
return nLocal+n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decode a btree page
|
||||
*/
|
||||
static void decode_btree_page(unsigned char *a, int pgno, int hdrSize){
|
||||
static void decode_btree_page(
|
||||
unsigned char *a, /* Page content */
|
||||
int pgno, /* Page number */
|
||||
int hdrSize, /* Size of the page header. 0 or 100 */
|
||||
char *zArgs /* Flags to control formatting */
|
||||
){
|
||||
const char *zType = "unknown";
|
||||
int nCell;
|
||||
int i;
|
||||
int i, j;
|
||||
int iCellPtr;
|
||||
int showCellContent = 0;
|
||||
int showMap = 0;
|
||||
char *zMap = 0;
|
||||
switch( a[0] ){
|
||||
case 2: zType = "index interior node"; break;
|
||||
case 5: zType = "table interior node"; break;
|
||||
case 10: zType = "index leaf"; break;
|
||||
case 13: zType = "table leaf"; break;
|
||||
}
|
||||
while( zArgs[0] ){
|
||||
switch( zArgs[0] ){
|
||||
case 'c': showCellContent = 1; break;
|
||||
case 'm': showMap = 1; break;
|
||||
}
|
||||
zArgs++;
|
||||
}
|
||||
printf("Decode of btree page %d:\n", pgno);
|
||||
print_decode_line(a, 0, 1, zType);
|
||||
print_decode_line(a, 1, 2, "Offset to first freeblock");
|
||||
@@ -244,13 +378,40 @@ static void decode_btree_page(unsigned char *a, int pgno, int hdrSize){
|
||||
}else{
|
||||
iCellPtr = 8;
|
||||
}
|
||||
if( nCell>0 ){
|
||||
printf(" key: lx=left-child n=payload-size r=rowid\n");
|
||||
}
|
||||
if( showMap ){
|
||||
zMap = malloc(pagesize);
|
||||
memset(zMap, '.', pagesize);
|
||||
memset(zMap, '1', hdrSize);
|
||||
memset(&zMap[hdrSize], 'H', iCellPtr);
|
||||
memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell);
|
||||
}
|
||||
for(i=0; i<nCell; i++){
|
||||
int cofst = iCellPtr + i*2;
|
||||
char *zDesc;
|
||||
int n;
|
||||
|
||||
cofst = a[cofst]*256 + a[cofst+1];
|
||||
describeCell(a[0], &a[cofst-hdrSize], &zDesc);
|
||||
n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc);
|
||||
if( showMap ){
|
||||
char zBuf[30];
|
||||
memset(&zMap[cofst], '*', n);
|
||||
zMap[cofst] = '[';
|
||||
zMap[cofst+n-1] = ']';
|
||||
sprintf(zBuf, "%d", i);
|
||||
j = strlen(zBuf);
|
||||
if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j);
|
||||
}
|
||||
printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
|
||||
}
|
||||
if( showMap ){
|
||||
for(i=0; i<pagesize; i+=64){
|
||||
printf(" %03x: %.64s\n", i, &zMap[i]);
|
||||
}
|
||||
free(zMap);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -300,6 +461,8 @@ static void usage(const char *argv0){
|
||||
" NNN..MMM Show hex of pages NNN through MMM\n"
|
||||
" NNN..end Show hex of pages NNN through end of file\n"
|
||||
" NNNb Decode btree page NNN\n"
|
||||
" NNNbc Decode btree page NNN and show content\n"
|
||||
" NNNbm Decode btree page NNN and show a layout map\n"
|
||||
" NNNt Decode freelist trunk page NNN\n"
|
||||
" NNNtd Show leave freelist pages on the decode\n"
|
||||
" NNNtr Recurisvely decode freelist starting at NNN\n"
|
||||
@@ -361,7 +524,7 @@ int main(int argc, char **argv){
|
||||
nByte = pagesize;
|
||||
}
|
||||
a = getContent(ofst, nByte);
|
||||
decode_btree_page(a, iStart, hdrSize);
|
||||
decode_btree_page(a, iStart, hdrSize, &zLeft[1]);
|
||||
free(a);
|
||||
continue;
|
||||
}else if( zLeft && zLeft[0]=='t' ){
|
||||
|
||||
Reference in New Issue
Block a user